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