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