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