1 /* -*-C++-*- $NetBSD: rootwindow.cpp,v 1.22 2008/04/28 20:23:20 martin Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2004 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 <menu/window.h> 34 #include <menu/tabwindow.h> 35 #include <menu/rootwindow.h> 36 #include <res/resource.h> 37 #include "../binary/build_number.h" 38 #include <console.h> 39 40 // 41 // root window 42 // 43 RootWindow::RootWindow(HpcBootApp &app) 44 : Window(app) 45 { 46 _boot_button = 0; 47 _base = 0; 48 _main = 0; 49 _option = 0; 50 _console = 0; 51 } 52 53 RootWindow::~RootWindow() 54 { 55 if (_boot_button) 56 delete _boot_button; 57 if (_cancel_button) 58 delete _cancel_button; 59 if (_progress_bar) 60 delete _progress_bar; 61 if (_main) 62 delete _main; 63 if (_option) 64 delete _option; 65 if (_console) 66 delete _console; 67 if (_base) 68 delete _base; 69 } 70 71 BOOL 72 RootWindow::create(LPCREATESTRUCT aux) 73 { 74 TCHAR app_name[32]; 75 // Root window's create don't called by Window Procedure. 76 // so aux is NULL 77 HINSTANCE inst = _app._instance; 78 TCHAR *wc_name = reinterpret_cast <TCHAR *> 79 (LoadString(inst, IDS_HPCMENU, 0, 0)); 80 wsprintf(app_name, TEXT("%s Build %d"), wc_name, HPCBOOT_BUILD_NUMBER); 81 82 _window = CreateWindow(wc_name, app_name, WS_VISIBLE, 83 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 84 0, 0, inst, this); 85 if (!_window) 86 return FALSE; 87 88 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 89 if (menu._pref.auto_boot > 0) 90 SetTimer(_window, IDD_TIMER, menu._pref.auto_boot * 1000, 0); 91 92 ShowWindow(_window, SW_SHOW); 93 UpdateWindow(_window); 94 95 return TRUE; 96 } 97 98 BOOL 99 RootWindow::proc(HWND w, UINT msg, WPARAM wparam, LPARAM lparam) 100 { 101 LPCREATESTRUCT aux = reinterpret_cast <LPCREATESTRUCT>(lparam); 102 HpcMenuInterface &menu = HpcMenuInterface::Instance(); 103 104 switch(msg) { 105 default: // message can't handle. 106 return FALSE; 107 case WM_CREATE: 108 WMCreate(w, aux); 109 break; 110 case WM_PAINT: 111 WMPaint(w, aux); 112 break; 113 case WM_ENTERMENULOOP: 114 SaveFocus(); 115 break; 116 case WM_EXITMENULOOP: 117 RestoreFocus(); 118 break; 119 case WM_ACTIVATE: 120 if ((UINT)LOWORD(wparam) == WA_INACTIVE) 121 SaveFocus(); 122 else 123 RestoreFocus(); 124 break; 125 case WM_NOTIFY: 126 { 127 NMHDR *notify = reinterpret_cast <NMHDR *>(lparam); 128 // get current selected tab id 129 int tab_id = TabCtrl_GetCurSel(_base->_window); 130 // get context 131 TC_ITEM tc_item; 132 tc_item.mask = TCIF_PARAM; 133 TabCtrl_GetItem(_base->_window, tab_id, &tc_item); 134 TabWindow *tab = reinterpret_cast <TabWindow *> 135 (tc_item.lParam); 136 switch(notify->code) { 137 case TCN_SELCHANGING: 138 tab->hide(); 139 break; 140 case TCN_SELCHANGE: 141 tab->show(); 142 break; 143 case TCN_KEYDOWN: { 144 NMTCKEYDOWN *key = reinterpret_cast 145 <NMTCKEYDOWN *>(lparam); 146 return _base->focusManagerHook(key->wVKey, key->flags, 147 _cancel_button->_window); 148 } 149 } 150 } 151 break; 152 case WM_TIMER: 153 disableTimer(); 154 goto boot; 155 case WM_COMMAND: 156 switch(wparam) 157 { 158 case IDC_BOOTBUTTON: 159 // inquire current options. 160 menu.get_options(); 161 if (menu._pref.safety_message) { 162 UINT mb_icon = menu._pref.pause_before_boot ? 163 MB_ICONQUESTION : MB_ICONWARNING; 164 if (MessageBox(_window, 165 TEXT("Data in memory will be lost.\nAre you sure?"), 166 TEXT("WARNING"), 167 mb_icon | MB_YESNO) != IDYES) 168 break; 169 UpdateWindow(_window); 170 } 171 boot: 172 SendMessage(_progress_bar->_window, PBM_SETPOS, 0, 0); 173 menu.print(TEXT("BOOT START\n")); 174 // inquire current options. 175 menu.get_options(); 176 // save options to `hpcboot.cnf' 177 menu.save(); 178 // start boot sequence. 179 menu.boot(); 180 // NOTREACHED 181 break; 182 case IDC_PROGRESSBAR: 183 break; 184 case IDC_CANCELBUTTON: 185 PostQuitMessage(0); 186 break; 187 } 188 break; 189 case WM_DESTROY: 190 PostQuitMessage(0); 191 break; 192 } 193 return TRUE; 194 } 195 196 void 197 RootWindow::SaveFocus() { 198 _saved_focus = GetFocus(); 199 } 200 201 void 202 RootWindow::RestoreFocus() { 203 SetFocus(IsWindowEnabled(_saved_focus) ? 204 _saved_focus : _boot_button->_window); 205 } 206 207 void 208 RootWindow::WMPaint(HWND w, LPCREATESTRUCT aux) 209 { 210 PAINTSTRUCT ps; 211 BeginPaint(w, &ps); 212 EndPaint(w, &ps); 213 } 214 215 void 216 RootWindow::WMCreate(HWND w, LPCREATESTRUCT aux) 217 { 218 int cmdbar_height; 219 220 _window = w; 221 // Command bar. 222 _app._cmdbar = CommandBar_Create(aux->hInstance, w, IDC_CMDBAR); 223 CommandBar_AddAdornments(_app._cmdbar, 0, 0); 224 cmdbar_height = CommandBar_Height(_app._cmdbar); 225 226 _button_height = cmdbar_height; 227 _button_width = BOOT_BUTTON_WIDTH; 228 229 HDC hdc = GetDC(0); 230 if (GetDeviceCaps(hdc, HORZRES) > 320) 231 _button_width += _button_width/2; 232 ReleaseDC(0, hdc); 233 234 RECT rect; 235 GetClientRect(w, &rect); 236 rect.top += cmdbar_height; 237 238 // BOOT button. 239 _boot_button = new BootButton(_app, *this, rect); 240 _boot_button->create(aux); 241 // CANCEL button. 242 _cancel_button = new CancelButton(_app, *this, rect); 243 _cancel_button->create(aux); 244 // Progress bar 245 _progress_bar = new ProgressBar(_app, *this, rect); 246 _progress_bar->create(aux); 247 248 // regsiter myself to menu 249 HpcMenuInterface::Instance()._root = this; 250 251 rect.top += _button_height; 252 // Tab control. 253 _base = new TabWindowBase(_app, w, rect, IDC_BASE); 254 _base->create(aux); 255 // main/option/console dialog.(register to Menu) 256 _main = _base->boot(IDC_BASE_MAIN); 257 _option = _base->boot(IDC_BASE_OPTION); 258 _console = _base->boot(IDC_BASE_CONSOLE); 259 260 _main->show(); 261 SetFocus(_boot_button->_window); 262 263 return; 264 } 265 266 void 267 RootWindow::disableTimer() 268 { 269 KillTimer(_window, IDD_TIMER); 270 } 271 272 BOOL 273 RootWindow::isDialogMessage(MSG &msg) 274 { 275 HWND tab_window; 276 277 if (_main && IsWindowVisible(_main->_window)) 278 tab_window = _main->_window; 279 else if (_option && IsWindowVisible(_option->_window)) 280 tab_window = _option->_window; 281 else if (_console && IsWindowVisible(_console->_window)) 282 tab_window = _console->_window; 283 284 if (focusManagerHook(msg, tab_window)) 285 return TRUE; 286 287 return IsDialogMessage(tab_window, &msg); 288 } 289 290 // 291 // XXX !!! XXX !!! XXX !!! XXX !!! 292 // 293 // WinCE 2.11 doesn't support keyboard focus traversal for nested 294 // dialogs, so implement poor man focus manager for our root window. 295 // This function handles focus transition from boot/cancel buttons. 296 // Transition from the tab-control is done on WM_NOTIFY/TCN_KEYDOWN 297 // above. 298 // 299 // XXX: This is a very smplistic implementation that doesn't handle 300 // <TAB> auto-repeat count in LOWORD(msg.lParam), WS_GROUP, etc... 301 // 302 BOOL 303 RootWindow::focusManagerHook(MSG &msg, HWND tab_window) 304 { 305 HWND next, prev; 306 HWND dst = 0; 307 LRESULT dlgcode = 0; 308 309 if (msg.message != WM_KEYDOWN) 310 return FALSE; 311 312 if (msg.hwnd == _boot_button->_window) { 313 next = _cancel_button->_window; 314 prev = _base->_window; 315 } else if (msg.hwnd == _cancel_button->_window) { 316 next = _base->_window; 317 prev = _boot_button->_window; 318 } else if (tab_window == 0) { 319 return FALSE; 320 } else { 321 // last focusable control in the tab_window (XXX: WS_GROUP?) 322 HWND last = GetNextDlgTabItem(tab_window, NULL, TRUE); 323 if (last == NULL || 324 !(last == msg.hwnd || IsChild(last, msg.hwnd))) 325 return FALSE; 326 dlgcode = SendMessage(last, WM_GETDLGCODE, NULL, (LPARAM)&msg); 327 next = _base->_window; // out of the tab window 328 prev = 0; // let IsDialogMessage handle it 329 } 330 331 #if 0 // XXX: breaks tabbing out of the console window 332 if (dlgcode & DLGC_WANTALLKEYS) 333 return FALSE; 334 #endif 335 switch (msg.wParam) { 336 case VK_RIGHT: 337 case VK_DOWN: 338 if (dlgcode & DLGC_WANTARROWS) 339 return FALSE; 340 dst = next; 341 break; 342 343 case VK_LEFT: 344 case VK_UP: 345 if (dlgcode & DLGC_WANTARROWS) 346 return FALSE; 347 dst = prev; 348 break; 349 350 case VK_TAB: 351 if (dlgcode & DLGC_WANTTAB) 352 return FALSE; 353 if (GetKeyState(VK_SHIFT) & 0x8000) // Shift-Tab 354 dst = prev; 355 else 356 dst = next; 357 break; 358 } 359 360 if (dst == 0) 361 return FALSE; 362 363 SetFocus(dst); 364 return TRUE; 365 } 366 367 void 368 RootWindow::progress(const char *msg) 369 { 370 371 if (msg) 372 Console::Instance()->print(TEXT("[progress] %S\n"), msg); 373 374 SendMessage(_progress_bar->_window, PBM_STEPIT, 0, 0); 375 } 376 377 void 378 RootWindow::unprogress() 379 { 380 SendMessage(_progress_bar->_window, PBM_SETPOS, 0, 0); 381 } 382 383 // 384 // BOOT button 385 // 386 BOOL 387 BootButton::create(LPCREATESTRUCT aux) 388 { 389 int cx = _root._button_width; 390 int cy = _root._button_height; 391 392 _window = CreateWindow(TEXT("BUTTON"), TEXT("Boot"), 393 BS_PUSHBUTTON | BS_NOTIFY | 394 WS_VISIBLE | WS_CHILD | WS_TABSTOP, 395 _rect.left, _rect.top, cx, cy, _parent_window, 396 reinterpret_cast <HMENU>(IDC_BOOTBUTTON), 397 aux->hInstance, 398 NULL); 399 400 return IsWindow(_window) ? TRUE : FALSE; 401 } 402 403 // 404 // CANCEL button 405 // 406 BOOL 407 CancelButton::create(LPCREATESTRUCT aux) 408 { 409 int cx = _root._button_width; 410 int cy = _root._button_height; 411 int x = _rect.right - _root._button_width; 412 413 _window = CreateWindow(TEXT("BUTTON"), TEXT("Cancel"), 414 BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | 415 WS_VISIBLE | WS_CHILD, 416 x, _rect.top, cx, cy, _parent_window, 417 reinterpret_cast <HMENU>(IDC_CANCELBUTTON), 418 aux->hInstance, 419 NULL); 420 421 return IsWindow(_window) ? TRUE : FALSE; 422 } 423 424 // 425 // PROGRESS BAR 426 // 427 BOOL 428 ProgressBar::create(LPCREATESTRUCT aux) 429 { 430 int cx = _rect.right - _rect.left - _root._button_width * 2; 431 int cy = _root._button_height; 432 int x = _rect.left + _root._button_width; 433 _window = CreateWindowEx(WS_EX_CLIENTEDGE, 434 PROGRESS_CLASS, TEXT(""), 435 PBS_SMOOTH | WS_VISIBLE | WS_CHILD, 436 x, _rect.top, cx, cy, _parent_window, 437 reinterpret_cast <HMENU>(IDC_PROGRESSBAR), 438 aux->hInstance, NULL); 439 SendMessage(_window, PBM_SETRANGE, 0, MAKELPARAM(0, 11)); 440 SendMessage(_window, PBM_SETSTEP, 1, 0); 441 SendMessage(_window, PBM_SETPOS, 0, 0); 442 443 return IsWindow(_window) ? TRUE : FALSE; 444 } 445