xref: /netbsd/sys/arch/hpc/stand/hpcboot/menu/menu.cpp (revision bf9ec67e)
1 /* -*-C++-*-	$NetBSD: menu.cpp,v 1.5 2002/03/25 17:23:19 uch 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, HWND_TOP, x, y, 120, 10, TRUE);
174 	h = GetDlgItem(_window, IDC_MAIN_OPTION_S);
175 	SetWindowPos(h, HWND_TOP, x, y + 20, 120, 10, TRUE);
176 	h = GetDlgItem(_window, IDC_MAIN_OPTION_A);
177 	SetWindowPos(h, HWND_TOP, x, y + 40, 120, 10, TRUE);
178 	h = GetDlgItem(_window, IDC_MAIN_OPTION_D);
179 	SetWindowPos(h, HWND_TOP, x, y + 60, 120, 10, TRUE);
180 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H);
181 	SetWindowPos(h, HWND_TOP, x, y + 80, 120, 10, TRUE);
182 	h = GetDlgItem(_window, IDC_MAIN_OPTION_H_SPEED);
183 	SetWindowPos(h, HWND_TOP, x + 100, y + 80, 120, 10, TRUE);
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 # of '\n'
344 	for (cr = 0, p = buf; p = wcschr(p, TEXT('\n')); cr++, p++)
345 		;
346 	// total length of new buffer('\n' -> "\r\n" + '\0')
347 	int ln = wcslen(buf) + cr + 1;
348 
349 	// get old buffer.
350 	int lo = Edit_GetTextLength(_edit);
351 	size_t sz =(lo  + ln) * sizeof(TCHAR);
352 
353 	p = reinterpret_cast <TCHAR *>(malloc(sz));
354 	if (p == NULL)
355 		return;
356 
357 	memset(p, 0, sz);
358 	Edit_GetText(_edit, p, lo + 1);
359 
360 	// put new buffer to end of old buffer.
361 	TCHAR *d = p + lo;
362 	while (*buf != TEXT('\0')) {
363 		TCHAR c = *buf++;
364 		if (c == TEXT('\n'))
365 			*d++ = TEXT('\r');
366 		*d++ = c;
367 	}
368 	*d = TEXT('\0');
369 
370 	// display total buffer.
371 	Edit_SetText(_edit, p);
372 //  Edit_Scroll(_edit, Edit_GetLineCount(_edit), 0);
373 	UpdateWindow(_edit);
374 
375 	free(p);
376 }
377 
378 void
379 ConsoleTabWindow::init(HWND w)
380 {
381 	// at this time _window is NULL.
382 	// use argument of window procedure.
383 	TabWindow::init(w);
384 	_edit = GetDlgItem(w, IDC_CONS_EDIT);
385 	MoveWindow(_edit, 5, 60, _rect.right - _rect.left - 10,
386 	    _rect.bottom - _rect.top - 60, TRUE);
387 	Edit_FmtLines(_edit, TRUE);
388 
389 	// log file.
390 	_filename_edit = GetDlgItem(w, IDC_CONS_FILENAME);
391 	_filesave = FALSE;
392 	Edit_SetText(_filename_edit, L"bootlog.txt");
393 	EnableWindow(_filename_edit, _filesave);
394 }
395 
396 void
397 ConsoleTabWindow::command(int id, int msg)
398 {
399 	HpcMenuInterface &menu = HPC_MENU;
400 	struct HpcMenuInterface::cons_hook_args *hook = 0;
401 	int bit;
402 
403 	switch(id) {
404 	case IDC_CONS_FILESAVE:
405 		_filesave = _is_checked(IDC_CONS_FILESAVE);
406 		EnableWindow(_filename_edit, _filesave);
407 		break;
408 	case IDC_CONS_CHK0:
409 		/* FALLTHROUGH */
410 	case IDC_CONS_CHK1:
411 		/* FALLTHROUGH */
412 	case IDC_CONS_CHK2:
413 		/* FALLTHROUGH */
414 	case IDC_CONS_CHK3:
415 		/* FALLTHROUGH */
416 	case IDC_CONS_CHK4:
417 		/* FALLTHROUGH */
418 	case IDC_CONS_CHK5:
419 		/* FALLTHROUGH */
420 	case IDC_CONS_CHK6:
421 		/* FALLTHROUGH */
422 	case IDC_CONS_CHK7:
423 		bit = 1 << (id - IDC_CONS_CHK_);
424 		if (SendDlgItemMessage(_window, id, BM_GETCHECK, 0, 0))
425 			menu._cons_parameter |= bit;
426 		else
427 			menu._cons_parameter &= ~bit;
428 		break;
429 	case IDC_CONS_BTN0:
430 		/* FALLTHROUGH */
431 	case IDC_CONS_BTN1:
432 		/* FALLTHROUGH */
433 	case IDC_CONS_BTN2:
434 		/* FALLTHROUGH */
435 	case IDC_CONS_BTN3:
436 		hook = &menu._cons_hook[id - IDC_CONS_BTN_];
437 		if (hook->func)
438 			hook->func(hook->arg, menu._cons_parameter);
439 
440 		break;
441 	}
442 }
443 
444 BOOL
445 ConsoleTabWindow::_open_log_file()
446 {
447 	TCHAR path[MAX_PATH];
448 	TCHAR filename[MAX_PATH];
449 	TCHAR filepath[MAX_PATH];
450 
451 	if (!_find_pref_dir(path)) {
452 		print(L"couldn't find temporary directory.\n", TRUE);
453 		return FALSE;
454 	}
455 
456 	Edit_GetText(_filename_edit, filename, MAX_PATH);
457 	wsprintf(filepath, TEXT("\\%s\\%s"), path, filename);
458 	_logfile = CreateFile(filepath, GENERIC_WRITE, 0, 0,
459 	    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
460 	if (_logfile == INVALID_HANDLE_VALUE)
461 		return FALSE;
462 
463 	wsprintf(path, TEXT("log file is %s\n"), filepath);
464 	print(path, TRUE);
465 
466 	return TRUE;
467 }
468 
469 //
470 // Common utility
471 //
472 BOOL
473 _find_pref_dir(TCHAR *path)
474 {
475 	WIN32_FIND_DATA fd;
476 	HANDLE find;
477 
478 	lstrcpy(path, TEXT("\\*.*"));
479 	find = FindFirstFile(path, &fd);
480 
481 	if (find != INVALID_HANDLE_VALUE) {
482 		do {
483 			int attr = fd.dwFileAttributes;
484 			if ((attr & FILE_ATTRIBUTE_DIRECTORY) &&
485 			    (attr & FILE_ATTRIBUTE_TEMPORARY)) {
486 				wcscpy(path, fd.cFileName);
487 				FindClose(find);
488 				return TRUE;
489 			}
490 		} while (FindNextFile(find, &fd));
491 	}
492 	FindClose(find);
493 
494 	return FALSE;
495 }
496