1 /* -*-C++-*- $NetBSD: menu.cpp,v 1.12 2010/04/06 16:20:28 nonaka Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <hpcmenu.h> 33 #include <hpcboot.h> 34 #include <res/resource.h> 35 #include <menu/window.h> 36 #include <menu/tabwindow.h> 37 #include <menu/rootwindow.h> 38 #include <machine/bootinfo.h> 39 #include <framebuffer.h> 40 #include <console.h> 41 42 #include <menu/menu.h> 43 44 #define SCALEX(x) (((x) * dpix) / 96/*DPI*/) 45 #define SCALEY(y) (((y) * dpiy) / 96/*DPI*/) 46 #define UNSCALEX(x) (((x) * 96) / dpix) 47 #define UNSCALEY(y) (((y) * 96) / dpiy) 48 49 TabWindow * 50 TabWindowBase::boot(int id) 51 { 52 TabWindow *w = NULL; 53 HpcMenuInterface &menu = HPC_MENU; 54 55 switch(id) { 56 default: 57 break; 58 case IDC_BASE_MAIN: 59 menu._main = new MainTabWindow(*this, IDC_BASE_MAIN); 60 w = menu._main; 61 break; 62 case IDC_BASE_OPTION: 63 menu._option = new OptionTabWindow(*this, IDC_BASE_OPTION); 64 w = menu._option; 65 break; 66 case IDC_BASE_CONSOLE: 67 menu._console = new ConsoleTabWindow(*this, IDC_BASE_CONSOLE); 68 w = menu._console; 69 break; 70 } 71 72 if (w) 73 w->create(0); 74 75 return w; 76 } 77 78 // 79 // Main window 80 // 81 void 82 MainTabWindow::_insert_item(HWND w, TCHAR *name, int id) 83 { 84 int idx = SendDlgItemMessage(w, id, CB_ADDSTRING, 0, 85 reinterpret_cast <LPARAM>(name)); 86 if (idx != CB_ERR) 87 SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETITEMDATA, 88 idx, _item_idx++); 89 } 90 91 void 92 MainTabWindow::init(HWND w) 93 { 94 HpcMenuInterface &menu = HPC_MENU; 95 struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; 96 97 _window = w; 98 // insert myself to tab-control 99 TabWindow::init(w); 100 101 // setup child. 102 TCHAR *entry; 103 int i; 104 // kernel directory path 105 for (i = 0; entry = menu.dir(i); i++) 106 _insert_item(w, entry, IDC_MAIN_DIR); 107 SendDlgItemMessage(w, IDC_MAIN_DIR, CB_SETCURSEL, menu.dir_default(), 108 0); 109 // platform 110 _sort_platids(w); 111 // kernel file name. 112 Edit_SetText(GetDlgItem(w, IDC_MAIN_KERNEL), pref.kernel_user ? 113 pref.kernel_user_file : TEXT("netbsd.gz")); 114 115 // root file system. 116 int fs = pref.rootfs + IDC_MAIN_ROOT_; 117 _set_check(fs, TRUE); 118 119 _edit_md_root = GetDlgItem(w, IDC_MAIN_ROOT_MD_OPS); 120 Edit_SetText(_edit_md_root, pref.rootfs_file); 121 EnableWindow(_edit_md_root, fs == IDC_MAIN_ROOT_MD ? TRUE : FALSE); 122 123 // layout checkbox and editbox. 124 layout(); 125 126 // set default kernel boot options. 127 _set_check(IDC_MAIN_OPTION_A, pref.boot_ask_for_name); 128 _set_check(IDC_MAIN_OPTION_D, pref.boot_debugger); 129 _set_check(IDC_MAIN_OPTION_S, pref.boot_single_user); 130 _set_check(IDC_MAIN_OPTION_V, pref.boot_verbose); 131 _set_check(IDC_MAIN_OPTION_H, pref.boot_serial); 132 133 // serial console speed. 134 TCHAR *speed_tab[] = { L"9600", L"19200", L"115200", 0 }; 135 int sel = 0; 136 i = 0; 137 for (TCHAR **speed = speed_tab; *speed; speed++, i++) { 138 _insert_item(w, *speed, IDC_MAIN_OPTION_H_SPEED); 139 if (_wtoi(*speed) == pref.serial_speed) 140 sel = i; 141 } 142 _combobox_serial_speed = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED); 143 SendDlgItemMessage(w, IDC_MAIN_OPTION_H_SPEED, CB_SETCURSEL, sel, 0); 144 EnableWindow(_combobox_serial_speed, pref.boot_serial); 145 } 146 147 int 148 MainTabWindow::_platcmp(const void *a, const void *b) 149 { 150 const MainTabWindow::PlatMap *pa = 151 reinterpret_cast <const MainTabWindow::PlatMap *>(a); 152 const MainTabWindow::PlatMap *pb = 153 reinterpret_cast <const MainTabWindow::PlatMap *>(b); 154 155 return wcscmp(pa->name, pb->name); 156 } 157 158 void 159 MainTabWindow::_sort_platids(HWND w) 160 { 161 HpcMenuInterface &menu = HPC_MENU; 162 MainTabWindow::PlatMap *p; 163 TCHAR *entry; 164 int nids; 165 int i; 166 167 for (nids = 0; menu.platform_get(nids); ++nids) 168 continue; 169 170 _platmap = reinterpret_cast <MainTabWindow::PlatMap *> 171 (malloc(nids * sizeof(MainTabWindow::PlatMap))); 172 173 if (_platmap == NULL) { 174 // can't sort, present in the order of definition 175 for (i = 0; entry = menu.platform_get(i); i++) 176 _insert_item(w, entry, IDC_MAIN_PLATFORM); 177 SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, 178 menu.platform_default(), 0); 179 return; 180 } 181 182 for (i = 0, p = _platmap; i < nids; ++i, ++p) { 183 p->id = i; 184 p->name = menu.platform_get(i); 185 } 186 187 qsort(_platmap, nids, sizeof(MainTabWindow::PlatMap), 188 MainTabWindow::_platcmp); 189 190 int defid = menu.platform_default(); 191 int defitem = 0; 192 for (i = 0; i < nids; ++i) { 193 if (_platmap[i].id == defid) 194 defitem = i; 195 _insert_item(w, _platmap[i].name, IDC_MAIN_PLATFORM); 196 } 197 SendDlgItemMessage(w, IDC_MAIN_PLATFORM, CB_SETCURSEL, defitem, 0); 198 } 199 200 int 201 MainTabWindow::_item_to_platid(int idx) 202 { 203 if (_platmap == NULL) 204 return idx; 205 else 206 return _platmap[idx].id; 207 } 208 209 void 210 MainTabWindow::layout() 211 { 212 // inquire display size. 213 HDC hdc = GetDC(0); 214 int width = GetDeviceCaps(hdc, HORZRES); 215 int height = GetDeviceCaps(hdc, VERTRES); 216 int dpix = GetDeviceCaps(hdc, LOGPIXELSX); 217 int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); 218 ReleaseDC(0, hdc); 219 220 // set origin 221 int x, y; 222 if (width <= 320) { 223 x = 5, y = 140; 224 } else if (height <= 240) { 225 x = 250, y = 5; 226 } else { 227 x = 5, y = 140; 228 } 229 230 HWND h; 231 h = GetDlgItem(_window, IDC_MAIN_OPTION_V); 232 SetWindowPos(h, 0, SCALEX(x), SCALEY(y), 233 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 234 h = GetDlgItem(_window, IDC_MAIN_OPTION_S); 235 SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 20), 236 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 237 h = GetDlgItem(_window, IDC_MAIN_OPTION_A); 238 SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 40), 239 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 240 h = GetDlgItem(_window, IDC_MAIN_OPTION_D); 241 SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 60), 242 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 243 h = GetDlgItem(_window, IDC_MAIN_OPTION_H); 244 SetWindowPos(h, 0, SCALEX(x), SCALEY(y + 80), 245 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 246 h = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED); 247 SetWindowPos(h, 0, SCALEX(x + 100), SCALEY(y + 80), 248 SCALEX(120), SCALEY(10), SWP_NOSIZE | SWP_NOZORDER); 249 } 250 251 void 252 MainTabWindow::get() 253 { 254 HpcMenuInterface &menu = HPC_MENU; 255 struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; 256 257 HWND w = GetDlgItem(_window, IDC_MAIN_DIR); 258 ComboBox_GetText(w, pref.dir_user_path, MAX_PATH); 259 pref.dir_user = TRUE; 260 w = GetDlgItem(_window, IDC_MAIN_KERNEL); 261 Edit_GetText(w, pref.kernel_user_file, MAX_PATH); 262 pref.kernel_user = TRUE; 263 264 int i = ComboBox_GetCurSel(GetDlgItem(_window, IDC_MAIN_PLATFORM)); 265 menu.platform_set(_item_to_platid(i)); 266 267 if (_is_checked(IDC_MAIN_ROOT_WD)) 268 pref.rootfs = 0; 269 else if (_is_checked(IDC_MAIN_ROOT_SD)) 270 pref.rootfs = 1; 271 else if (_is_checked(IDC_MAIN_ROOT_MD)) 272 pref.rootfs = 2; 273 else if (_is_checked(IDC_MAIN_ROOT_NFS)) 274 pref.rootfs = 3; 275 else if (_is_checked(IDC_MAIN_ROOT_DK)) 276 pref.rootfs = 4; 277 else if (_is_checked(IDC_MAIN_ROOT_LD)) 278 pref.rootfs = 5; 279 280 pref.boot_ask_for_name = _is_checked(IDC_MAIN_OPTION_A); 281 pref.boot_debugger = _is_checked(IDC_MAIN_OPTION_D); 282 pref.boot_verbose = _is_checked(IDC_MAIN_OPTION_V); 283 pref.boot_single_user = _is_checked(IDC_MAIN_OPTION_S); 284 pref.boot_serial = _is_checked(IDC_MAIN_OPTION_H); 285 Edit_GetText(_edit_md_root, pref.rootfs_file, MAX_PATH); 286 287 TCHAR tmpbuf[8]; 288 ComboBox_GetText(_combobox_serial_speed, tmpbuf, 8); 289 pref.serial_speed = _wtoi(tmpbuf); 290 } 291 292 void 293 MainTabWindow::command(int id, int msg) 294 { 295 switch (id) { 296 case IDC_MAIN_OPTION_H: 297 EnableWindow(_combobox_serial_speed, 298 _is_checked(IDC_MAIN_OPTION_H)); 299 break; 300 case IDC_MAIN_ROOT_WD: 301 /* FALLTHROUGH */ 302 case IDC_MAIN_ROOT_SD: 303 /* FALLTHROUGH */ 304 case IDC_MAIN_ROOT_MD: 305 /* FALLTHROUGH */ 306 case IDC_MAIN_ROOT_NFS: 307 /* FALLTHROUGH */ 308 case IDC_MAIN_ROOT_DK: 309 /* FALLTHROUGH */ 310 case IDC_MAIN_ROOT_LD: 311 EnableWindow(_edit_md_root, _is_checked(IDC_MAIN_ROOT_MD)); 312 } 313 } 314 315 // 316 // Option window 317 // 318 void 319 OptionTabWindow::init(HWND w) 320 { 321 struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; 322 HDC hdc = GetDC(0); 323 int dpix = GetDeviceCaps(hdc, LOGPIXELSX); 324 int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); 325 ReleaseDC(0, hdc); 326 327 _window = w; 328 329 TabWindow::init(_window); 330 _spin_edit = GetDlgItem(_window, IDC_OPT_AUTO_INPUT); 331 _spin = CreateUpDownControl(WS_CHILD | WS_BORDER | WS_VISIBLE | 332 UDS_SETBUDDYINT | UDS_ALIGNRIGHT, 333 SCALEX(80), SCALEY(0), SCALEX(50), SCALEY(50), _window, 334 IDC_OPT_AUTO_UPDOWN, _app._instance, _spin_edit, 60, 1, 30); 335 BOOL onoff = pref.auto_boot ? TRUE : FALSE; 336 EnableWindow(_spin_edit, onoff); 337 EnableWindow(_spin, onoff); 338 339 SET_CHECK(AUTO, pref.auto_boot); 340 if (pref.auto_boot) { 341 TCHAR tmp[32]; 342 wsprintf(tmp, TEXT("%d"), pref.auto_boot); 343 Edit_SetText(_spin_edit, tmp); 344 } 345 SET_CHECK(VIDEO, pref.reverse_video); 346 SET_CHECK(PAUSE, pref.pause_before_boot); 347 SET_CHECK(DEBUG, pref.load_debug_info); 348 SET_CHECK(SAFETY, pref.safety_message); 349 Edit_SetText(GetDlgItem(w, IDC_OPT_EXTKOPT), pref.boot_extra); 350 } 351 352 void 353 OptionTabWindow::command(int id, int msg) 354 { 355 switch (id) { 356 case IDC_OPT_AUTO: 357 if (IS_CHECKED(AUTO)) { 358 EnableWindow(_spin_edit, TRUE); 359 EnableWindow(_spin, TRUE); 360 } else { 361 EnableWindow(_spin_edit, FALSE); 362 EnableWindow(_spin, FALSE); 363 } 364 break; 365 } 366 } 367 368 void 369 OptionTabWindow::get() 370 { 371 HWND w; 372 struct HpcMenuInterface::HpcMenuPreferences &pref = HPC_PREFERENCE; 373 if (IS_CHECKED(AUTO)) { 374 TCHAR tmp[32]; 375 Edit_GetText(_spin_edit, tmp, 32); 376 pref.auto_boot = _wtoi(tmp); 377 } else 378 pref.auto_boot = 0; 379 pref.reverse_video = IS_CHECKED(VIDEO); 380 pref.pause_before_boot = IS_CHECKED(PAUSE); 381 pref.load_debug_info = IS_CHECKED(DEBUG); 382 pref.safety_message = IS_CHECKED(SAFETY); 383 384 w = GetDlgItem(_window, IDC_OPT_EXTKOPT); 385 Edit_GetText(w, pref.boot_extra, MAX_BOOT_STR); 386 } 387 #undef IS_CHECKED 388 #undef SET_CHECK 389 390 391 // 392 // Console window 393 // 394 void 395 ConsoleTabWindow::print(TCHAR *buf, BOOL force_display) 396 { 397 int cr; 398 TCHAR *p; 399 400 if (force_display) 401 goto display; 402 403 if (_filesave) { 404 if (_logfile == INVALID_HANDLE_VALUE && !_open_log_file()) { 405 _filesave = FALSE; 406 _set_check(IDC_CONS_FILESAVE, _filesave); 407 EnableWindow(_filename_edit, _filesave); 408 goto display; 409 } 410 DWORD cnt; 411 char c; 412 for (int i = 0; *buf != TEXT('\0'); buf++) { 413 c = *buf & 0x7f; 414 WriteFile(_logfile, &c, 1, &cnt, 0); 415 } 416 FlushFileBuffers(_logfile); 417 return; 418 } 419 420 display: 421 // count number of '\n' 422 for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++) 423 continue; 424 425 // total length of new buffer ('\n' -> "\r\n" + '\0') 426 size_t sz = (wcslen(buf) + cr + 1) * sizeof(TCHAR); 427 428 p = reinterpret_cast <TCHAR *>(malloc(sz)); 429 if (p == NULL) 430 return; 431 432 // convert newlines 433 TCHAR *d = p; 434 while (*buf != TEXT('\0')) { 435 TCHAR c = *buf++; 436 if (c == TEXT('\n')) 437 *d++ = TEXT('\r'); 438 *d++ = c; 439 } 440 *d = TEXT('\0'); 441 442 // append the text and scroll 443 int end = Edit_GetTextLength(_edit); 444 Edit_SetSel(_edit, end, end); 445 Edit_ReplaceSel(_edit, p); 446 Edit_ScrollCaret(_edit); 447 UpdateWindow(_edit); 448 449 free(p); 450 } 451 452 void 453 ConsoleTabWindow::init(HWND w) 454 { 455 HDC hdc = GetDC(0); 456 int dpix = GetDeviceCaps(hdc, LOGPIXELSX); 457 int dpiy = GetDeviceCaps(hdc, LOGPIXELSY); 458 ReleaseDC(0, hdc); 459 460 // at this time _window is NULL. 461 // use argument of window procedure. 462 TabWindow::init(w); 463 _edit = GetDlgItem(w, IDC_CONS_EDIT); 464 MoveWindow(_edit, SCALEX(5), SCALEY(60), 465 SCALEX(UNSCALEX(_rect.right - _rect.left) - 10), 466 SCALEY(UNSCALEY(_rect.bottom - _rect.top) - 60), TRUE); 467 Edit_FmtLines(_edit, TRUE); 468 469 // log file. 470 _filename_edit = GetDlgItem(w, IDC_CONS_FILENAME); 471 _filesave = FALSE; 472 Edit_SetText(_filename_edit, L"bootlog.txt"); 473 EnableWindow(_filename_edit, _filesave); 474 } 475 476 void 477 ConsoleTabWindow::command(int id, int msg) 478 { 479 HpcMenuInterface &menu = HPC_MENU; 480 struct HpcMenuInterface::cons_hook_args *hook = 0; 481 int bit; 482 483 switch(id) { 484 case IDC_CONS_FILESAVE: 485 _filesave = _is_checked(IDC_CONS_FILESAVE); 486 EnableWindow(_filename_edit, _filesave); 487 break; 488 case IDC_CONS_CHK0: 489 /* FALLTHROUGH */ 490 case IDC_CONS_CHK1: 491 /* FALLTHROUGH */ 492 case IDC_CONS_CHK2: 493 /* FALLTHROUGH */ 494 case IDC_CONS_CHK3: 495 /* FALLTHROUGH */ 496 case IDC_CONS_CHK4: 497 /* FALLTHROUGH */ 498 case IDC_CONS_CHK5: 499 /* FALLTHROUGH */ 500 case IDC_CONS_CHK6: 501 /* FALLTHROUGH */ 502 case IDC_CONS_CHK7: 503 bit = 1 << (id - IDC_CONS_CHK_); 504 if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0)) 505 menu._cons_parameter |= bit; 506 else 507 menu._cons_parameter &= ~bit; 508 break; 509 case IDC_CONS_BTN0: 510 /* FALLTHROUGH */ 511 case IDC_CONS_BTN1: 512 /* FALLTHROUGH */ 513 case IDC_CONS_BTN2: 514 /* FALLTHROUGH */ 515 case IDC_CONS_BTN3: 516 hook = &menu._cons_hook[id - IDC_CONS_BTN_]; 517 if (hook->func) 518 hook->func(hook->arg, menu._cons_parameter); 519 520 break; 521 } 522 } 523 524 BOOL 525 ConsoleTabWindow::_open_log_file() 526 { 527 TCHAR path[MAX_PATH]; 528 TCHAR filename[MAX_PATH]; 529 TCHAR filepath[MAX_PATH]; 530 531 if (!_find_pref_dir(path)) { 532 print(L"couldn't find temporary directory.\n", TRUE); 533 return FALSE; 534 } 535 536 Edit_GetText(_filename_edit, filename, MAX_PATH); 537 wsprintf(filepath, TEXT("\\%s\\%s"), path, filename); 538 _logfile = CreateFile(filepath, GENERIC_WRITE, 0, 0, 539 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); 540 if (_logfile == INVALID_HANDLE_VALUE) 541 return FALSE; 542 543 wsprintf(path, TEXT("log file is %s\n"), filepath); 544 print(path, TRUE); 545 546 return TRUE; 547 } 548 549 // 550 // Common utility 551 // 552 BOOL 553 _find_pref_dir(TCHAR *path) 554 { 555 WIN32_FIND_DATA fd; 556 HANDLE find; 557 558 lstrcpy(path, TEXT("\\*.*")); 559 find = FindFirstFile(path, &fd); 560 561 if (find != INVALID_HANDLE_VALUE) { 562 do { 563 int attr = fd.dwFileAttributes; 564 if ((attr & FILE_ATTRIBUTE_DIRECTORY) && 565 (attr & FILE_ATTRIBUTE_TEMPORARY)) { 566 wcscpy(path, fd.cFileName); 567 FindClose(find); 568 return TRUE; 569 } 570 } while (FindNextFile(find, &fd)); 571 } 572 FindClose(find); 573 574 return FALSE; 575 } 576