/* -*-C++-*- $NetBSD: menu.cpp,v 1.13 2011/11/23 15:49:58 nonaka Exp $ */ /*- * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by UCHIYAMA Yasushi. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #define SCALEX(x) (((x) * dpix) / 96/*DPI*/) #define SCALEY(y) (((y) * dpiy) / 96/*DPI*/) #define UNSCALEX(x) (((x) * 96) / dpix) #define UNSCALEY(y) (((y) * 96) / dpiy) TabWindow * TabWindowBase::boot(int id) { TabWindow *w = NULL; HpcMenuInterface &menu = HPC_MENU; switch(id) { default: break; case IDC_BASE_MAIN: menu._main = new MainTabWindow(*this, IDC_BASE_MAIN); w = menu._main; break; case IDC_BASE_OPTION: menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION); w = menu._option; break; case IDC_BASE_CONSOLE: menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE); w = menu._console; break; } if (w) w->create(0); return w; } // // Main window // void MainTabWindow::_insert_item(HWND w, TCHAR *name, int id) { int idx = SendDlgItemMessage(w, id, CB_ADDSTRING, 0, reinterpret_cast (name)); if (idx != CB_ERR) SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETITEMDATA, idx, _item_idx++); } void MainTabWindow::init(HWND w) { HpcMenuInterface &menu = HPC_MENU; struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; _window = w; // insert myself to tab-control TabWindow::init(w); // setup child. TCHAR *entry; int i; // kernel directory path for (i = 0; entry = menu.dir(i); i++) _insert_item(w, entry, IDC_MAIN_DIR); SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETCURSEL, menu.dir_default(), 0); // platform _sort_platids(w); // kernel file name. Edit_SetText(GetDlgItem(w, IDC_MAIN_KERNEL), pref.kernel_user ? pref.kernel_user_file : TEXT("netbsd.gz")); // root file system. int fs = pref.rootfs + IDC_MAIN_ROOT_; _set_check(fs, TRUE); _edit_md_root = GetDlgItem(w, IDC_MAIN_ROOT_MD_OPS); Edit_SetText(_edit_md_root, pref.rootfs_file); EnableWindow(_edit_md_root, fs == IDC_MAIN_ROOT_MD ? TRUE : FALSE); // layout checkbox and editbox. layout(); // set default kernel boot options. _set_check(IDC_MAIN_OPTION_A, pref.boot_ask_for_name); _set_check(IDC_MAIN_OPTION_D, pref.boot_debugger); _set_check(IDC_MAIN_OPTION_S, pref.boot_single_user); _set_check(IDC_MAIN_OPTION_V, pref.boot_verbose); _set_check(IDC_MAIN_OPTION_H, pref.boot_serial); // serial console speed. TCHAR *speed_tab[] = { L"9600", L"19200", L"115200", 0 }; int sel = 0; i = 0; for (TCHAR **speed = speed_tab; *speed; speed++, i++) { _insert_item(w, *speed, IDC_MAIN_OPTION_H_SPEED); if (_wtoi(*speed) == pref.serial_speed) sel = i; } _combobox_serial_speed = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED); SendDlgItemMessage(w, IDC_MAIN_OPTION_H_SPEED, CB_SETCURSEL, sel, 0); EnableWindow(_combobox_serial_speed, pref.boot_serial); } int MainTabWindow::_platcmp(const void *a, const void *b) { const MainTabWindow::PlatMap *pa = reinterpret_cast (a); const MainTabWindow::PlatMap *pb = reinterpret_cast (b); return wcscmp(pa->name, pb->name); } void MainTabWindow::_sort_platids(HWND w) { HpcMenuInterface &menu = HPC_MENU; MainTabWindow::PlatMap *p; TCHAR *entry; int nids; int i; for (nids = 0; menu.platform_get(nids); ++nids) continue; _platmap = reinterpret_cast (malloc(nids * sizeof(MainTabWindow::PlatMap))); if (_platmap == NULL) { // can't sort, present in the order of definition for (i = 0; entry = menu.platform_get(i); i++) _insert_item(w, entry, IDC_MAIN_PLATFORM); SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, menu.platform_default(), 0); return; } for (i = 0, p = _platmap; i < nids; ++i, ++p) { p->id = i; p->name = menu.platform_get(i); } qsort(_platmap, nids, sizeof(MainTabWindow::PlatMap), MainTabWindow::_platcmp); int defid = menu.platform_default(); int defitem = 0; for (i = 0; i < nids; ++i) { if (_platmap[i].id == defid) defitem = i; _insert_item(w, _platmap[i].name, IDC_MAIN_PLATFORM); } SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, defitem, 0); } int MainTabWindow::_item_to_platid(int idx) { if (_platmap == NULL) return idx; else return _platmap[idx].id; } void MainTabWindow::layout() { // inquire display size. HDC hdc = GetDC(0); int width = GetDeviceCaps(hdc, HORZRES); int height = GetDeviceCaps(hdc, VERTRES); int dpix = GetDeviceCaps(hdc, LOGPIXELSX); int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(0, hdc); // set origin int x, y; if (width <= 320) { x = 5, y = 140; } else if (height <= 240) { x = 250, y = 5; } else { x = 5, y = 140; } HWND h; h = GetDlgItem(_window, IDC_MAIN_OPTION_V); SetWindowPos(h, 0, SCALEX(x), SCALEY(y), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); h = GetDlgItem(_window, IDC_MAIN_OPTION_S); SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 20), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); h = GetDlgItem(_window, IDC_MAIN_OPTION_A); SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 40), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); h = GetDlgItem(_window, IDC_MAIN_OPTION_D); SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 60), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); h = GetDlgItem(_window, IDC_MAIN_OPTION_H); SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 80), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); h = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED); SetWindowPos(h, 0, SCALEX(x + 100), SCALEY(y + 80), SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); } void MainTabWindow::get() { HpcMenuInterface &menu = HPC_MENU; struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; HWND w = GetDlgItem(_window, IDC_MAIN_DIR); ComboBox_GetText(w, pref.dir_user_path, MAX_PATH); pref.dir_user = TRUE; w = GetDlgItem(_window, IDC_MAIN_KERNEL); Edit_GetText(w, pref.kernel_user_file, MAX_PATH); pref.kernel_user = TRUE; int i = ComboBox_GetCurSel(GetDlgItem(_window, IDC_MAIN_PLATFORM)); menu.platform_set(_item_to_platid(i)); if (_is_checked(IDC_MAIN_ROOT_WD)) pref.rootfs = 0; else if (_is_checked(IDC_MAIN_ROOT_SD)) pref.rootfs = 1; else if (_is_checked(IDC_MAIN_ROOT_MD)) pref.rootfs = 2; else if (_is_checked(IDC_MAIN_ROOT_NFS)) pref.rootfs = 3; else if (_is_checked(IDC_MAIN_ROOT_DK)) pref.rootfs = 4; else if (_is_checked(IDC_MAIN_ROOT_LD)) pref.rootfs = 5; pref.boot_ask_for_name = _is_checked(IDC_MAIN_OPTION_A); pref.boot_debugger = _is_checked(IDC_MAIN_OPTION_D); pref.boot_verbose = _is_checked(IDC_MAIN_OPTION_V); pref.boot_single_user = _is_checked(IDC_MAIN_OPTION_S); pref.boot_serial = _is_checked(IDC_MAIN_OPTION_H); Edit_GetText(_edit_md_root, pref.rootfs_file, MAX_PATH); TCHAR tmpbuf[8]; ComboBox_GetText(_combobox_serial_speed, tmpbuf, 8); pref.serial_speed = _wtoi(tmpbuf); } void MainTabWindow::command(int id, int msg) { switch (id) { case IDC_MAIN_OPTION_H: EnableWindow(_combobox_serial_speed, _is_checked(IDC_MAIN_OPTION_H)); break; case IDC_MAIN_ROOT_WD: /* FALLTHROUGH */ case IDC_MAIN_ROOT_SD: /* FALLTHROUGH */ case IDC_MAIN_ROOT_MD: /* FALLTHROUGH */ case IDC_MAIN_ROOT_NFS: /* FALLTHROUGH */ case IDC_MAIN_ROOT_DK: /* FALLTHROUGH */ case IDC_MAIN_ROOT_LD: EnableWindow(_edit_md_root, _is_checked(IDC_MAIN_ROOT_MD)); } } // // Option window // void OptionTabWindow::init(HWND w) { struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; HDC hdc = GetDC(0); int dpix = GetDeviceCaps(hdc, LOGPIXELSX); int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(0, hdc); _window = w; TabWindow::init(_window); _spin_edit = GetDlgItem(_window, IDC_OPT_AUTO_INPUT); _spin = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | UDS_SETBUDDYINT | UDS_ALIGNRIGHT, SCALEX(80), SCALEY(0), SCALEX(50), SCALEY(50), _window, IDC_OPT_AUTO_UPDOWN, _app._instance, _spin_edit, 60, 1, 30); BOOL onoff = pref.auto_boot ? TRUE : FALSE; EnableWindow(_spin_edit, onoff); EnableWindow(_spin, onoff); SET_CHECK(AUTO, pref.auto_boot); if (pref.auto_boot) { TCHAR tmp[32]; wsprintf(tmp, TEXT("%d"), pref.auto_boot); Edit_SetText(_spin_edit, tmp); } SET_CHECK(VIDEO, pref.reverse_video); SET_CHECK(PAUSE, pref.pause_before_boot); SET_CHECK(DEBUG, pref.load_debug_info); SET_CHECK(SAFETY, pref.safety_message); Edit_SetText(GetDlgItem(w, IDC_OPT_EXTKOPT), pref.boot_extra); } void OptionTabWindow::command(int id, int msg) { switch (id) { case IDC_OPT_AUTO: if (IS_CHECKED(AUTO)) { EnableWindow(_spin_edit, TRUE); EnableWindow(_spin, TRUE); } else { EnableWindow(_spin_edit, FALSE); EnableWindow(_spin, FALSE); } break; } } void OptionTabWindow::get() { HWND w; struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; if (IS_CHECKED(AUTO)) { TCHAR tmp[32]; Edit_GetText(_spin_edit, tmp, 32); pref.auto_boot = _wtoi(tmp); } else pref.auto_boot = 0; pref.reverse_video = IS_CHECKED(VIDEO); pref.pause_before_boot = IS_CHECKED(PAUSE); pref.load_debug_info = IS_CHECKED(DEBUG); pref.safety_message = IS_CHECKED(SAFETY); w = GetDlgItem(_window, IDC_OPT_EXTKOPT); Edit_GetText(w, pref.boot_extra, MAX_BOOT_STR); } #undef IS_CHECKED #undef SET_CHECK // // Console window // void ConsoleTabWindow::print(TCHAR *buf, BOOL force_display) { int cr; TCHAR *p; if (force_display) goto display; if (_filesave) { if (_logfile == INVALID_HANDLE_VALUE && !_open_log_file()) { _filesave = FALSE; _set_check(IDC_CONS_FILESAVE, _filesave); EnableWindow(_filename_edit, _filesave); goto display; } DWORD cnt; char c; for (int i = 0; *buf != TEXT('\0'); buf++) { c = *buf & 0x7f; WriteFile(_logfile, &c, 1, &cnt, 0); } FlushFileBuffers(_logfile); return; } display: // count number of '\n' for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++) continue; // total length of new buffer ('\n' -> "\r\n" + '\0') size_t sz = (wcslen(buf) + cr + 1) * sizeof(TCHAR); p = reinterpret_cast (malloc(sz)); if (p == NULL) return; // convert newlines TCHAR *d = p; while (*buf != TEXT('\0')) { TCHAR c = *buf++; if (c == TEXT('\n')) *d++ = TEXT('\r'); *d++ = c; } *d = TEXT('\0'); // append the text and scroll int end = Edit_GetTextLength(_edit); Edit_SetSel(_edit, end, end); Edit_ReplaceSel(_edit, p); Edit_ScrollCaret(_edit); UpdateWindow(_edit); free(p); } void ConsoleTabWindow::init(HWND w) { HDC hdc = GetDC(0); int dpix = GetDeviceCaps(hdc, LOGPIXELSX); int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); ReleaseDC(0, hdc); // at this time _window is NULL. // use argument of window procedure. TabWindow::init(w); _edit = GetDlgItem(w, IDC_CONS_EDIT); MoveWindow(_edit, SCALEX(5), SCALEY(60), SCALEX(UNSCALEX(_rect.right - _rect.left) - 10), SCALEY(UNSCALEY(_rect.bottom - _rect.top) - 60), TRUE); Edit_FmtLines(_edit, TRUE); // log file. _filename_edit = GetDlgItem(w, IDC_CONS_FILENAME); _filesave = FALSE; Edit_SetText(_filename_edit, L"bootlog.txt"); EnableWindow(_filename_edit, _filesave); } void ConsoleTabWindow::command(int id, int msg) { HpcMenuInterface &menu = HPC_MENU; struct HpcMenuInterface::cons_hook_args *hook = 0; int bit; switch(id) { case IDC_CONS_FILESAVE: _filesave = _is_checked(IDC_CONS_FILESAVE); EnableWindow(_filename_edit, _filesave); break; case IDC_CONS_CHK0: /* FALLTHROUGH */ case IDC_CONS_CHK1: /* FALLTHROUGH */ case IDC_CONS_CHK2: /* FALLTHROUGH */ case IDC_CONS_CHK3: /* FALLTHROUGH */ case IDC_CONS_CHK4: /* FALLTHROUGH */ case IDC_CONS_CHK5: /* FALLTHROUGH */ case IDC_CONS_CHK6: /* FALLTHROUGH */ case IDC_CONS_CHK7: bit = 1 << (id - IDC_CONS_CHK_); if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0)) menu._cons_parameter |= bit; else menu._cons_parameter &= ~bit; break; case IDC_CONS_BTN0: /* FALLTHROUGH */ case IDC_CONS_BTN1: /* FALLTHROUGH */ case IDC_CONS_BTN2: /* FALLTHROUGH */ case IDC_CONS_BTN3: hook = &menu._cons_hook[id - IDC_CONS_BTN_]; if (hook->func) hook->func(hook->arg, menu._cons_parameter); break; } } BOOL ConsoleTabWindow::_open_log_file() { TCHAR path[MAX_PATH]; TCHAR filename[MAX_PATH]; TCHAR filepath[MAX_PATH]; if (!_find_pref_dir(path)) { print(L"couldn't find temporary directory.\n", TRUE); return FALSE; } Edit_GetText(_filename_edit, filename, MAX_PATH); wsprintf(filepath, TEXT("\\%s\\%s"), path, filename); _logfile = CreateFile(filepath, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); if (_logfile == INVALID_HANDLE_VALUE) return FALSE; wsprintf(path, TEXT("log file is %s\n"), filepath); print(path, TRUE); return TRUE; } // // Common utility // static BOOL is_ignore_directory(TCHAR *filename) { static const TCHAR *dirs[] = { // Network (in Japanese) (const TCHAR *)"\xcd\x30\xc3\x30\xc8\x30\xef\x30\xfc\x30\xaf\x30\x00\x00", }; for (int i = 0; i < sizeof(dirs) / sizeof(dirs[0]); i++) { if (wcscmp(filename, dirs[i]) == 0) { return TRUE; } } return FALSE; } BOOL _find_pref_dir(TCHAR *path) { WIN32_FIND_DATA fd; HANDLE find; lstrcpy(path, TEXT("\\*.*")); find = FindFirstFile(path, &fd); if (find != INVALID_HANDLE_VALUE) { do { int attr = fd.dwFileAttributes; if ((attr & FILE_ATTRIBUTE_DIRECTORY) && (attr & FILE_ATTRIBUTE_TEMPORARY) && !is_ignore_directory(fd.cFileName)) { wcscpy(path, fd.cFileName); FindClose(find); return TRUE; } } while (FindNextFile(find, &fd)); } FindClose(find); return FALSE; }