1 /* ---------------------------------------------------------------------- *
2  * winmain.c
3  * This file is part of lincity.
4  * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
5  * ---------------------------------------------------------------------- */
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <math.h>
9 #include <malloc.h>
10 #include <memory.h>
11 #include "lcstring.h"
12 #include "lin-city.h"
13 #include "common.h"
14 #include "generic.h"
15 #include "mouse.h"
16 #include "lchelp.h"
17 #include "module_buttons.h"
18 
19 // Define this to use DIB's instead of DDB's
20 // GCS: WIN32_USEDIB will no longer work, since I didn't update the
21 // window resizing code for DIB's.
22 //#define WIN32_USEDIB
23 
24 // Global Variables
25 static char szClassNameWithMenu[] = APPNAME " (with menu)";
26 static char szClassNameWithoutMenu[] = APPNAME " (without menu)";
27 static char szAppName[] = APPNAME;	// The name of this application
28 static char szTitle[] = APPNAME;	// The title bar text
29 static HBRUSH hbrBackground = 0;
30 
31 int pending_mouse_event = 0;
32 int pending_mouse_x = 0;
33 int pending_mouse_y = 0;
34 
35 int pending_resize_event = 0;
36 int pending_resize_w = 0;
37 int pending_resize_h = 0;
38 
39 // Private Function Prototypes
40 static ATOM MyRegisterClass (CONST WNDCLASS *);
41 static BOOL InitApplication (HINSTANCE);
42 static BOOL InitInstance (HINSTANCE, int);
43 static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
44 static LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM);
45 static BOOL CenterWindow (HWND, HWND);
46 static void InitializeBackingStore (HWND);
47 static BOOL CopyBackingStoreToScreen (HDC, HWND, LPPAINTSTRUCT);
48 static void CreateDDB (HWND hWnd);
49 static void CreateDIB (void);
50 static void InitializePalette (void);
51 static void DoSquareMouse (HDC hdc);
52 static void ResizeBackingStore (HWND hWnd);
53 static void ResizeDDB (HWND hWnd);
54 
55 
56 //----------------------------------------------------------------------------
57 //  FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
58 //
59 //  PURPOSE: Entry point for the application.
60 //
61 //  COMMENTS:
62 //
63 //      This function initializes the application and processes the
64 //      message loop.
65 //----------------------------------------------------------------------------
66 int WINAPI
WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)67 WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
68 {
69     char *args[] = {"wlincity"};
70 
71     if (!hPrevInstance) {
72 	// Perform instance initialization:
73 	if (!InitApplication (hInstance)) {
74 	    return (FALSE);
75 	}
76     }
77 
78     // Perform application initialization, including creating the
79     // Lin-City main window.
80     if (!InitInstance (hInstance, nCmdShow)) {
81 	return (FALSE);
82     }
83 
84     // Load keyboard accelerators (shortkut keys)
85     display.hAccelTable = LoadAccelerators (hInstance, szAppName);
86 
87     // Take care of any outstanding messages
88     ProcessPendingEvents ();
89 
90     // lincity_main() contains main message loop
91     lincity_main (1, args);
92 
93     // Take care of any outstanding messages after main() finishes.
94     ProcessPendingEvents ();
95 
96     return 0;
97     lpCmdLine;	// This prevents 'unused formal parameter' warnings
98 }
99 
100 
101 
102 //----------------------------------------------------------------------------
103 //  FUNCTION: MyRegisterClass(CONST WNDCLASS*)
104 //
105 //  PURPOSE: Registers the window class.
106 //
107 //  COMMENTS:
108 //
109 //      This function and its usage is only necessary if you want this code
110 //      to be compatible with Win32 systems prior to the 'RegisterClassEx'
111 //      function that was added to Windows 95. It is important to call this function
112 //      so that the application will get 'well formed' small icons associated
113 //      with it.
114 //----------------------------------------------------------------------------
MyRegisterClass(CONST WNDCLASS * lpwc)115 ATOM MyRegisterClass (CONST WNDCLASS * lpwc)
116 {
117     HANDLE hMod;
118     FARPROC proc;
119     WNDCLASSEX wcex;
120 
121     hMod = GetModuleHandle ("USER32");
122     if (hMod != NULL) {
123 #if defined (UNICODE)
124 	proc = GetProcAddress ((HMODULE) hMod, "RegisterClassExW");
125 #else /*  */
126 	proc = GetProcAddress ((HMODULE) hMod, "RegisterClassExA");
127 #endif /*  */
128 	if (proc != NULL) {
129 	    // GCS: This typedef is for the typecast in the return stmt below
130 	    typedef int (FAR WINAPI * my_FARPROC) (WNDCLASSEX *);
131 
132 	    wcex.style = lpwc->style;
133 	    wcex.lpfnWndProc = lpwc->lpfnWndProc;
134 	    wcex.cbClsExtra = lpwc->cbClsExtra;
135 	    wcex.cbWndExtra = lpwc->cbWndExtra;
136 	    wcex.hInstance = lpwc->hInstance;
137 	    wcex.hIcon = lpwc->hIcon;
138 	    wcex.hCursor = lpwc->hCursor;
139 	    wcex.hbrBackground = lpwc->hbrBackground;
140 	    wcex.lpszMenuName = lpwc->lpszMenuName;
141 	    wcex.lpszClassName = lpwc->lpszClassName;
142 
143 	    // Added elements for Windows 95:
144 	    wcex.cbSize = sizeof (WNDCLASSEX);
145 	    wcex.hIconSm = LoadIcon (wcex.hInstance, "SMALL");
146 
147 	    return (*((my_FARPROC) (proc))) (&wcex);
148 	}
149     }
150     return (RegisterClass (lpwc));
151 }
152 
153 
154 //----------------------------------------------------------------------------
155 //  FUNCTION: InitApplication(HANDLE)
156 //
157 //  PURPOSE: Initializes window data and registers window classes
158 //
159 //  COMMENTS:
160 //         We need two classes -- one which has a menu, one without a menu
161 //         (for full-screen).  This is registered by calling RegisterClass
162 //         for Win 3.1/NT, or MyRegisterClass for Win 95.
163 //----------------------------------------------------------------------------
InitApplication(HINSTANCE hInstance)164 BOOL InitApplication (HINSTANCE hInstance)
165 {
166     WNDCLASS wcWithMenu;
167     WNDCLASS wcWithoutMenu;
168     // If Lin City is already running, focus existing process.
169     // Win32 always sets hPrevInstance to NULL, so check w/ FindWindow()
170     HWND hwnd = FindWindow (szClassNameWithMenu, NULL);
171 
172     if (!hwnd)
173 	hwnd = FindWindow (szClassNameWithoutMenu, NULL);
174     if (hwnd) {
175 	// We found another version of ourself. Lets defer to it:
176 	if (IsIconic (hwnd)) {
177 	    ShowWindow (hwnd, SW_RESTORE);
178 	}
179 	SetForegroundWindow (hwnd);
180 	return FALSE;
181     }
182 
183     // Create brush for background: Nasty Brown (Lin City color # 105)
184     hbrBackground = CreateSolidBrush (RGB (0x4C, 0x4C, 0));
185 
186     // Fill in WNDCLASS for class WITH MENU.
187     wcWithMenu.style = 0;
188     wcWithMenu.lpfnWndProc = (WNDPROC) WndProc;
189     wcWithMenu.cbClsExtra = 0;
190     wcWithMenu.cbWndExtra = 0;
191     wcWithMenu.hInstance = hInstance;
192     wcWithMenu.hIcon = LoadIcon (hInstance, szAppName);
193     wcWithMenu.hCursor = LoadCursor (NULL, IDC_ARROW);
194     wcWithMenu.hbrBackground = hbrBackground;
195 
196     // Windows95 has different recommended help menu format.
197 #if defined (USE_WIN32_MENU)
198     if (IS_WIN95) {
199 	wcWithMenu.lpszMenuName = "WIN95";
200     } else {
201 	wcWithMenu.lpszMenuName = szAppName;
202     }
203     wcWithMenu.lpszClassName = szClassNameWithMenu;
204 #else
205     wcWithMenu.lpszMenuName = "";
206     wcWithMenu.lpszClassName = szClassNameWithMenu;
207 #endif
208 
209     // Fill in WNDCLASS for class WITHOUT MENU.
210     wcWithoutMenu.style = 0;
211     wcWithoutMenu.lpfnWndProc = (WNDPROC) WndProc;
212     wcWithoutMenu.cbClsExtra = 0;
213     wcWithoutMenu.cbWndExtra = 0;
214     wcWithoutMenu.hInstance = hInstance;
215     wcWithoutMenu.hIcon = LoadIcon (hInstance, szAppName);
216     wcWithoutMenu.hCursor = LoadCursor (NULL, IDC_ARROW);
217     wcWithoutMenu.hbrBackground = hbrBackground;
218     wcWithoutMenu.lpszMenuName = "";
219     wcWithoutMenu.lpszClassName = szClassNameWithoutMenu;
220 
221     // Register the window classes and return success/failure code.
222     if (IS_WIN95) {
223 	BOOL rv;
224 	rv = MyRegisterClass (&wcWithMenu);
225 	if (!rv)
226 	    return rv;
227 	rv = MyRegisterClass (&wcWithoutMenu);
228 	return rv;
229     } else {
230 	BOOL rv;
231 	rv = RegisterClass (&wcWithMenu);
232 	if (!rv)
233 	    return rv;
234 	rv = RegisterClass (&wcWithoutMenu);
235 	return rv;
236     }
237 }
238 
239 
240 //----------------------------------------------------------------------------
241 // CheckClientSize (int width, int height, int with_menus)
242 // --
243 // Return 1 if the screen can support a client of this size
244 //----------------------------------------------------------------------------
245 void
CheckClientSize(int width,int height,int with_menus)246 CheckClientSize (int width, int height, int with_menus)
247 {
248     display.screenW = GetSystemMetrics (SM_CXSCREEN);
249     display.screenH = GetSystemMetrics (SM_CYSCREEN);
250 }
251 
252 //----------------------------------------------------------------------------
253 //   FUNCTION: InitInstance(HANDLE, int)
254 //
255 //   PURPOSE:  Creates main window
256 //----------------------------------------------------------------------------
257 BOOL
InitInstance(HINSTANCE hInstance,int nCmdShow)258 InitInstance (HINSTANCE hInstance, int nCmdShow)
259 {
260     HDC hDCGlobal = GetDC (NULL);
261     INT iRasterCaps;
262     char *szClassName = 0;
263     DWORD dwStyle;
264     RECT client_size;
265 
266     // Determine graphics capabilities
267     iRasterCaps = GetDeviceCaps (hDCGlobal, RASTERCAPS);
268     if (iRasterCaps & RC_PALETTE) {
269 	display.hasPalette = TRUE;
270 	display.paletteSize = GetDeviceCaps (hDCGlobal, SIZEPALETTE);
271 	display.defaultPaletteSize = GetDeviceCaps (hDCGlobal, NUMCOLORS);
272     } else {
273 	display.hasPalette = FALSE;
274     }
275 
276     display.colorDepth = GetDeviceCaps (hDCGlobal, BITSPIXEL);
277     ReleaseDC (NULL, hDCGlobal);
278 
279     // Decide whether to use DIB's or DDB's
280 #if defined (WIN32_USEDIB)
281     if (display.colorDepth == 8)	// Only use DIB for 256 colors
282 	display.useDIB = TRUE;
283     else
284 	display.useDIB = FALSE;
285 #else /*  */
286     display.useDIB = FALSE;
287 #endif /*  */
288 
289     // Do some global initializations
290     display.hInst = hInstance;
291     display.fullscreen = FALSE;
292     //display.fullscreen = TRUE;
293     display.screenW = GetSystemMetrics (SM_CXSCREEN);
294     display.screenH = GetSystemMetrics (SM_CYSCREEN);
295     display.winFullscreenClientW = (INT) GetSystemMetrics (SM_CXFULLSCREEN);
296     display.winFullscreenClientH = (INT) GetSystemMetrics (SM_CYFULLSCREEN);
297     InitializePalette ();
298 
299     // Choose one of Lin City window types
300     //    a)  no pix doubling, no border
301     //    b)  no pix doubling, 30 pixel border
302     //    c)  pix doubling, no border
303     // GCS FIX: This doesn't work.  I need to call AdjustWindowRect on these values (?)
304     if ((display.screenW >= 2*WINWIDTH + 2*BORDERX) &&
305 	(display.screenH >= 2*WINHEIGHT + 2*BORDERY)) {
306 	pix_double = 1;
307 	borderx = 1;
308 	bordery = 1;
309     }
310     else if ((display.screenW >= 2*WINWIDTH) &&
311 	     (display.screenH >= 2*WINHEIGHT)) {
312 	pix_double = 1;
313 	borderx = 0;
314 	bordery = 0;
315     }
316     else if ((display.screenW >= WINWIDTH + (2 * BORDERX))
317 	     &&(display.screenH >= WINHEIGHT + (2 * BORDERY))) {
318 	pix_double = 0;
319 	borderx = BORDERX;
320 	bordery = BORDERY;
321     } else {
322 	pix_double = 0;
323 	borderx = 0;
324 	bordery = 0;
325     }
326     display.clientW = ((pix_double + 1) * WINWIDTH) + (2 * borderx);
327     display.clientH = ((pix_double + 1) * WINHEIGHT) + (2 * bordery);
328 
329     // Choose one of three client window types
330     //    a)  full screen
331     //    b)  maximized window
332     //    c)  regular window
333     // Prefer regular over maximized over full screen
334     dwStyle = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX;
335     client_size.left = 0;
336     client_size.top = 0;
337     client_size.right = display.clientW;
338     client_size.bottom = display.clientH;
339     AdjustWindowRect (&client_size, dwStyle, TRUE);
340 
341     if (((client_size.right - client_size.left) <= display.screenW)
342 	&&((client_size.bottom - client_size.top) <= display.screenH))
343     {
344 	// Use regular (overlapped) window
345 	szClassName = szClassNameWithMenu;
346 	if (client_size.left < 0) {
347 	    client_size.right -= client_size.left;
348 	    client_size.left = CW_USEDEFAULT;
349 	}
350 	if (client_size.top < 0) {
351 	    client_size.bottom -= client_size.top;
352 	    client_size.top = CW_USEDEFAULT;
353 	}
354     } else {
355 	// Check maximized by subtracting out the DLGFRAME size.
356 	// Note that the "obvious" method of calling AdjustWindowRect()
357 	// with style WS_MAXIMIZE doesn't work!
358 	int win_border_x = GetSystemMetrics (SM_CXDLGFRAME);
359 	int win_border_y = GetSystemMetrics (SM_CYDLGFRAME);
360 	if (((client_size.right - client_size.left - 2 * win_border_x) <= display.screenW)
361 	    &&((client_size.bottom - client_size.top - 2 * win_border_y) <= display.screenH))
362 	{
363 	    // Use maximized window
364 	    szClassName = szClassNameWithMenu;
365 	    // dwStyle |= WS_MAXIMIZE;
366 	    if (client_size.left < 0) {
367 		client_size.right -= client_size.left;
368 		client_size.left = CW_USEDEFAULT;
369 	    }
370 	    if (client_size.top < 0) {
371 		client_size.bottom -= client_size.top;
372 		client_size.top = CW_USEDEFAULT;
373 	    }
374 	    nCmdShow = SW_SHOWMAXIMIZED;
375 	} else {
376 	    // Need fullsize window
377 	    szClassName = szClassNameWithoutMenu;
378 	    dwStyle = WS_POPUP;
379 	    client_size.left = 0;
380 	    client_size.top = 0;
381 	    client_size.right = display.screenW;
382 	    client_size.bottom = display.screenH;
383 	}
384     }
385 
386     display.min_h = client_size.bottom - client_size.top;
387     display.min_w = client_size.right - client_size.left;
388 
389     // Create the window
390     display.hWnd = CreateWindow (szClassName,	// Class name
391 				 szTitle,	// Caption
392 				 dwStyle,	// Style
393 				 client_size.left, client_size.top,	// Position
394 				 client_size.right, client_size.bottom,	// Size
395 				 (HWND) NULL,	// Parent window (no parent)
396 				 (HMENU) NULL,		// use class menu
397 				 (HINSTANCE) hInstance,	// handle to window instance
398 				 (LPVOID) NULL		// no params to pass on
399 				 );
400 
401     if (!display.hWnd) {
402 	return (FALSE);
403     }
404 
405     // Display the window
406     ShowWindow (display.hWnd, nCmdShow);
407     UpdateWindow (display.hWnd);
408 
409     return (TRUE);
410 }
411 
412 
413 //----------------------------------------------------------------------------
414 //  FUNCTION: ProcessNextEvent ()
415 //            Wait for a message if necessary,
416 //            then process all messages.
417 //----------------------------------------------------------------------------
418 void
ProcessNextEvent(void)419 ProcessNextEvent (void)
420 {
421 
422     MSG msg;
423     if (GetMessage (&msg, NULL, 0, 0)) {
424 	if (!TranslateAccelerator (msg.hwnd, (HACCEL) display.hAccelTable,
425 				   &msg)) {
426 	    TranslateMessage (&msg);
427 	    DispatchMessage (&msg);
428 	}
429     }
430     ProcessPendingEvents ();
431 }
432 
433 
434 
435 //----------------------------------------------------------------------------
436 //  FUNCTION: ProcessPendingEvents ()
437 //            Process all outstanding messages.
438 //----------------------------------------------------------------------------
439 void
ProcessPendingEvents(void)440 ProcessPendingEvents (void)
441 {
442     MSG msg;
443     while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
444 	if (!TranslateAccelerator (msg.hwnd, (HACCEL) display.hAccelTable,
445 				   &msg)) {
446 	    TranslateMessage (&msg);
447 	    DispatchMessage (&msg);
448 	}
449     }
450 }
451 
452 
453 
454 //----------------------------------------------------------------------------
455 //  FUNCTION: EnableWindowsMenuItems ()
456 //  FUNCTION: DisableWindowsMenuItems ()
457 //            Enable and Disable "Load" and "Save" items
458 //----------------------------------------------------------------------------
459 void
EnableWindowsMenuItems(void)460 EnableWindowsMenuItems (void)
461 {
462 #if defined (USE_WIN32_MENU)
463     HMENU hMenu = GetMenu (display.hWnd);
464     EnableMenuItem (hMenu, IDM_OPEN, MF_BYCOMMAND | MF_ENABLED);
465     EnableMenuItem (hMenu, IDM_SAVE, MF_BYCOMMAND | MF_ENABLED);
466     EnableMenuItem (hMenu, IDM_HELPCONTENTS, MF_BYCOMMAND | MF_ENABLED);
467 #endif
468 }
469 
470 
471 void
DisableWindowsMenuItems(void)472 DisableWindowsMenuItems (void)
473 {
474 #if defined (USE_WIN32_MENU)
475     HMENU hMenu = GetMenu (display.hWnd);
476     EnableMenuItem (hMenu, IDM_OPEN, MF_BYCOMMAND | MF_GRAYED);
477     EnableMenuItem (hMenu, IDM_SAVE, MF_BYCOMMAND | MF_GRAYED);
478     EnableMenuItem (hMenu, IDM_HELPCONTENTS, MF_BYCOMMAND | MF_GRAYED);
479 #endif
480 }
481 
482 
483 
484 //----------------------------------------------------------------------------
485 //  FUNCTION: HandleMouse ()
486 //----------------------------------------------------------------------------
487 void
HandleMouse()488 HandleMouse ()
489 {
490     MSG msg;
491     /* Process queued events, ignoring mouse moves. */
492     while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
493 	if (!TranslateAccelerator (msg.hwnd, (HACCEL) display.hAccelTable,
494 				   &msg)) {
495 	    pending_mouse_x = cs_mouse_x;
496 	    pending_mouse_y = cs_mouse_y;
497 	    pending_mouse_event = 0;
498 	    pending_resize_event = 0;
499 	    TranslateMessage (&msg);
500 	    DispatchMessage (&msg);
501 	    if (pending_mouse_event)
502 		cs_mouse_handler (pending_mouse_event,
503 				  pending_mouse_x - cs_mouse_x,
504 				  pending_mouse_y - cs_mouse_y);
505 	    if (pending_resize_event) {
506 		/* Force resize, because I can't tell difference between
507 		   size change and restoring a minimized window.  Ideally,
508 		   this would simply redraw. */
509 		display.winW = 0;
510 	        resize_geometry (pending_resize_w, pending_resize_h);
511 	    }
512 	}
513     }
514 
515     /* Now move the mouse if necessary. */
516     if (pending_mouse_x != cs_mouse_x
517 	|| pending_mouse_y != cs_mouse_y)
518 	cs_mouse_handler (0, pending_mouse_x - cs_mouse_x,
519 			  pending_mouse_y - cs_mouse_y);
520 }
521 
522 
523 
524 //----------------------------------------------------------------------------
525 //  FUNCTION: GetKeystroke ()
526 //----------------------------------------------------------------------------
527 char
GetKeystroke()528 GetKeystroke ()
529 {
530     char key;
531     /* GCS 02/02/2003  I found out that sometimes the mouse events were
532 		       getting lost here. */
533     HandleMouse ();
534 //    ProcessPendingEvents ();
535     key = x_key_value;
536     x_key_value = 0;
537     return key;
538 }
539 
540 
541 
542 //----------------------------------------------------------------------------
543 //  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
544 //
545 //  PURPOSE:  Processes messages for the main window.
546 //----------------------------------------------------------------------------
WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)547 LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
548 {
549 #if defined (USE_WIN32_MENU)
550     int wmId, wmEvent;
551 #endif
552 
553     switch (message)
554     {
555 #if defined (USE_WIN32_MENU)
556     case WM_COMMAND: {
557 	wmId = LOWORD (wParam);
558 	wmEvent = HIWORD (wParam);
559 
560 	//Parse the menu selections:
561 	switch (wmId)
562 	{
563 
564 	case IDM_OPEN:
565 	    load_flag = 1;
566 	    DisableWindowsMenuItems ();
567 	    break;
568 
569 	case IDM_SAVE:
570 	    save_flag = 1;
571 	    DisableWindowsMenuItems ();
572 	    break;
573 
574 	case IDM_EXIT:
575 	    // GCS FIX: I'm still not quite satisfied with this...
576 	    // x_key_value = 'q';
577 	    DestroyWindow (hWnd);
578 	    break;
579 
580 	case IDM_ABOUT:
581 	    DialogBox (display.hInst, "AboutBox", hWnd, (DLGPROC) About);
582 	    break;
583 
584 	case IDM_HELPCONTENTS:
585 	    help_flag = 1;
586 	    DisableWindowsMenuItems ();
587 	    activate_help ("index.hlp");
588 	    break;
589 
590 	default:
591 	    return (DefWindowProc (hWnd, message, wParam, lParam));
592 	}
593     }
594     break;
595 #endif
596 
597     case WM_KEYDOWN: {
598 	int nVirtKey = (int) wParam;
599 	x_key_shifted = (GetKeyState (VK_SHIFT) & 0x80000000) ? TRUE : FALSE;
600 	switch (nVirtKey)
601 	{
602 	case VK_LEFT:
603 	    x_key_value = 1;
604 	    break;
605 
606 	case VK_DOWN:
607 	    x_key_value = 2;
608 	    break;
609 
610 	case VK_UP:
611 	    x_key_value = 3;
612 	    break;
613 
614 	case VK_RIGHT:
615 	    x_key_value = 4;
616 	    break;
617 
618 	case VK_ESCAPE:
619 	    x_key_value = 5;
620 	    break;
621 	}
622     }
623     break;
624 
625     case WM_CHAR: {
626 	TCHAR chCharCode = (TCHAR) wParam;	// character code
627 	LPARAM lKeyData = lParam;	// key data
628 	if (chCharCode == 8) {		// Fix backspace
629 	    chCharCode = 127;
630 	} else if (chCharCode == VK_ESCAPE) {  // Fix escape
631 	    chCharCode = 5;
632 	}
633 	x_key_value = chCharCode;
634     }
635     break;
636 
637     // RightClick on windows non-client area
638     case WM_NCRBUTTONUP:
639 	if (IS_WIN95 && SendMessage (hWnd, WM_NCHITTEST, 0, lParam) == HTSYSMENU)
640 	{
641 	    // The user has clicked the right button on the applications
642 	    // 'System Menu'. Here is where you would alter the default
643 	    // system menu to reflect your application. Notice how the
644 	    // explorer deals with this. For this app, we aren't doing
645 	    // anything
646 	    return (DefWindowProc (hWnd, message, wParam, lParam));
647 	} else {
648 	    // Nothing we are interested in, allow default handling...
649 	    return (DefWindowProc (hWnd, message, wParam, lParam));
650 	}
651 	break;
652 
653 	// RightClick in windows client area
654     case WM_RBUTTONDOWN:
655 	pending_mouse_x = UnAdjustX (LOWORD (lParam));
656 	pending_mouse_y = UnAdjustY (HIWORD (lParam));
657 	pending_mouse_event = LC_MOUSE_RIGHTBUTTON | LC_MOUSE_PRESS;
658 	cs_mouse_shifted = (wParam & MK_SHIFT) ? 1 : 0;
659 	break;
660 
661 	// Left Click in windows client area
662     case WM_LBUTTONDOWN:
663 	pending_mouse_x = UnAdjustX (LOWORD (lParam));
664 	pending_mouse_y = UnAdjustY (HIWORD (lParam));
665 	pending_mouse_event = LC_MOUSE_LEFTBUTTON | LC_MOUSE_PRESS;
666 	cs_mouse_shifted = (wParam & MK_SHIFT) ? 1 : 0;
667 	break;
668 
669     case WM_RBUTTONUP:
670 	pending_mouse_x = UnAdjustX (LOWORD (lParam));
671 	pending_mouse_y = UnAdjustY (HIWORD (lParam));
672 	pending_mouse_event = LC_MOUSE_RIGHTBUTTON | LC_MOUSE_RELEASE;
673 	cs_mouse_shifted = (wParam & MK_SHIFT) ? 1 : 0;
674 	break;
675 
676     case WM_LBUTTONUP:
677 	pending_mouse_x = UnAdjustX (LOWORD (lParam));
678 	pending_mouse_y = UnAdjustY (HIWORD (lParam));
679 	pending_mouse_event = LC_MOUSE_LEFTBUTTON | LC_MOUSE_RELEASE;
680 	cs_mouse_shifted = (wParam & MK_SHIFT) ? 1 : 0;
681 	break;
682 
683     case WM_MOUSEMOVE:
684 	pending_mouse_x = UnAdjustX (LOWORD (lParam));
685 	pending_mouse_y = UnAdjustY (HIWORD (lParam));
686 	cs_mouse_shifted = (wParam & MK_SHIFT) ? 1 : 0;
687 	break;
688 
689 	// Only comes through on plug'n'play systems
690     case WM_DISPLAYCHANGE: {
691 	SIZE szScreen;
692 	BOOL fChanged = (BOOL) wParam;
693 
694 	szScreen.cx = LOWORD (lParam);
695 	szScreen.cy = HIWORD (lParam);
696 
697 	if (fChanged) {
698 	    // The display 'has' changed. szScreen reflects the
699 	    // new size.
700 	    MessageBox (GetFocus (), "Display Changed", szAppName, 0);
701 	} else {
702 	    // The display 'is' changing. szScreen reflects the
703 	    // original size.
704 	    MessageBeep (0);
705 	}
706     }
707     break;
708 
709     case WM_PAINT: {
710 	PAINTSTRUCT ps;
711 	HDC hdc;
712 
713 	hdc = BeginPaint (hWnd, &ps);
714 	CopyBackingStoreToScreen (hdc, hWnd, &ps);
715 	EndPaint (hWnd, &ps);
716     }
717     break;
718 
719     // Create client area
720     case WM_CREATE:
721 	InitializeBackingStore (hWnd);
722 	break;
723 
724     case WM_DESTROY:
725 	// PostQuitMessage(0);
726 	exit (0);		// OK??
727 	break;
728 
729     case WM_SIZE:
730 	// Resize window
731 	if (wParam != SIZE_MINIMIZED) {
732 	    pending_resize_event = 1;
733 	    pending_resize_w = LOWORD (lParam);
734 	    pending_resize_h = HIWORD (lParam);
735 	    ResizeBackingStore (hWnd);
736 	}
737 	break;
738 
739     case WM_GETMINMAXINFO: {
740 	/* GCS FIX */
741 	/* This needs to include client menu */
742 	/* To do this, I need to call AdjustWindowRect, but
743 	    probably I need consider that the window might be POPUP... */
744 	LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
745 #if defined (commentout)
746 	lpmmi->ptMinTrackSize.x = (640 << pix_double) + 2 * borderx;
747 	lpmmi->ptMinTrackSize.y = (480 << pix_double) + 2 * bordery;
748 #endif
749 	lpmmi->ptMinTrackSize.x = display.min_w;
750 	lpmmi->ptMinTrackSize.y = display.min_h;
751 	break;
752 	}
753 
754     default:
755 	return (DefWindowProc (hWnd, message, wParam, lParam));
756     }
757     return (0);
758 }
759 
760 
761 
762 //----------------------------------------------------------------------------
763 //  FUNCTION: InitializeBackingStore ()
764 //----------------------------------------------------------------------------
765 void
InitializeBackingStore(HWND hWnd)766 InitializeBackingStore (HWND hWnd)
767 {
768     RECT rc;
769 
770     GetClientRect (hWnd, &rc);
771     display.winW = rc.right - rc.left;
772     display.winH = rc.bottom - rc.top;
773 
774     InitializePalette ();
775     CreateDDB (hWnd);
776     if (display.useDIB) {
777 	CreateDIB ();
778     }
779     display.hSaveUnderHdc = 0;
780     display.hSaveUnderBitmap = 0;
781 }
782 
783 void
ResizeBackingStore(HWND hWnd)784 ResizeBackingStore (HWND hWnd)
785 {
786     ResizeDDB (hWnd);
787     if (display.useDIB) {
788 	// This had better be false
789 	exit(-1);
790     }
791 }
792 
793 
794 
795 //----------------------------------------------------------------------------
796 //  FUNCTION: InitializePalette ()
797 //----------------------------------------------------------------------------
798 void
InitializePalette(void)799 InitializePalette (void)
800 {
801     INT iLoop;
802 
803     display.hPal = 0;
804     display.pLogPal = 0;
805     // Clear out palette arrays
806     for (iLoop = 0; iLoop < 256; iLoop++) {
807 	display.colorrefPal[iLoop] = 0;
808 	display.brushPal[iLoop] = 0;
809     }
810 
811     // If the device uses a palette (e.g. 8 bit display),
812     // we need to create an HPALETTE for the HDC.
813     if (display.hasPalette) {
814 	// Allocate memory for LOGPALETTE
815 	display.pLogPal = (NPLOGPALETTE) LocalAlloc (LMEM_FIXED,
816 						     (sizeof (LOGPALETTE) +
817 						      (sizeof (PALETTEENTRY) * (display.paletteSize))));
818 	if (!display.pLogPal) {
819 	    MessageBox (display.hWnd, "Not enough memory for logical palette.", NULL, MB_OK | MB_ICONHAND);
820 	    PostQuitMessage (0);
821 	    exit (-1);
822 	}
823 	display.pLogPal->palVersion = 0x300;
824 	display.pLogPal->palNumEntries = display.paletteSize;
825 
826 	// Fill palette with system colors by default
827 	for (iLoop = 0; iLoop < display.paletteSize; iLoop++) {
828 	    *((WORD *) (&display.pLogPal->palPalEntry[iLoop].peRed)) = (WORD) iLoop;
829 	    display.pLogPal->palPalEntry[iLoop].peBlue = 0;
830 	    display.pLogPal->palPalEntry[iLoop].peFlags = PC_EXPLICIT;
831 	}
832 
833 	// Convert LOGPALETTE into HPALETTE
834 	display.hPal = CreatePalette ((LPLOGPALETTE) display.pLogPal);
835     }
836 }
837 
838 
839 //----------------------------------------------------------------------------
840 //  FUNCTION: CreateDIB ()
841 //----------------------------------------------------------------------------
842 void
CreateDIB(void)843 CreateDIB (void)
844 {
845     // Let's create a 256 color DIB, just for testing!
846     ULONG sizBMI;
847     INT iNumClr = 256;
848     INT iLoop;
849 
850     // Get memory for 256 color BITMAPINFO
851     sizBMI = sizeof (BITMAPINFOHEADER) + sizeof (RGBQUAD) * iNumClr;
852     if ((display.pbminfo = (PBITMAPINFO) GlobalAlloc (GMEM_FIXED | GMEM_ZEROINIT, sizBMI)) == NULL) {
853 	MessageBox (display.hWnd, "Failed in Memory Allocation for bminfo!", "Error", MB_OK);
854 	exit (-1);
855     }
856 
857     // Fill in bitmap info
858     display.pbminfo->bmiHeader.biSize = 0x28;	// GDI needs this to work
859     display.pbminfo->bmiHeader.biWidth = display.winW;
860     display.pbminfo->bmiHeader.biHeight = display.winH;
861     display.pbminfo->bmiHeader.biPlanes = 1;
862     display.pbminfo->bmiHeader.biBitCount = 8;
863     display.pbminfo->bmiHeader.biCompression = BI_RGB;
864     // this choice for biSizeImage reflects one byte per pixel
865     display.pbminfo->bmiHeader.biSizeImage = display.winW * display.winH;
866     display.pbminfo->bmiHeader.biXPelsPerMeter = 0;
867     display.pbminfo->bmiHeader.biYPelsPerMeter = 0;
868     display.pbminfo->bmiHeader.biClrUsed = 0;
869     display.pbminfo->bmiHeader.biClrImportant = 0;
870 
871     // Fill in colormap w/ black
872     for (iLoop = 0; iNumClr; iLoop++) {
873 	display.pbminfo->bmiColors[iLoop].rgbRed = 0;
874 	display.pbminfo->bmiColors[iLoop].rgbGreen = 0;
875 	display.pbminfo->bmiColors[iLoop].rgbBlue = 0;
876 	display.pbminfo->bmiColors[iLoop].rgbReserved = 0;
877     }
878 
879     // CreateDIBSection() will allocate the pBits.
880     display.hDIB = CreateDIBSection (display.hdcMem, display.pbminfo,
881 				     DIB_RGB_COLORS,
882 				     (void **) (&display.pBits), NULL, 0);
883 }
884 
885 
886 
887 //----------------------------------------------------------------------------
888 //  FUNCTION: CreateDDB ()
889 //----------------------------------------------------------------------------
890 void
CreateDDB(HWND hWnd)891 CreateDDB (HWND hWnd)
892 {
893     HDC hdc;
894     HBITMAP hBitmapOri;
895     HPALETTE hPalOld;
896     RECT rect;
897     HBRUSH hbr, hbrOld;
898 
899     hdc = GetDC (hWnd);
900     if (display.hasPalette) {
901 	hPalOld = SelectPalette (hdc, (HPALETTE) display.hPal, FALSE);
902 	if (RealizePalette (hdc)) {
903 	    UpdateColors (hdc);
904 	}
905     }
906 
907     // Before an application can use a memory device
908     // context for drawing operations, it must select
909     // a bitmap of the correct width and height into
910     // the device context. Once a bitmap has been selected,
911     // the device context can be used to prepare images
912     // that will be copied to the screen or printed.
913     display.hdcMem = CreateCompatibleDC (hdc);
914     if (display.hasPalette) {
915 	display.hPaletteMemOri = SelectPalette (display.hdcMem, (HPALETTE) display.hPal, FALSE);
916 	RealizePalette (display.hdcMem);
917     }
918     display.hBitmap = CreateCompatibleBitmap (hdc, display.winW, display.winH);
919     hBitmapOri = (HBITMAP) SelectObject (display.hdcMem, display.hBitmap);
920 
921     // Write that nasty brown color into the backing store
922     rect.left = 0;
923     rect.top = 0;
924     rect.right = display.winW;
925     rect.bottom = display.winH;
926     hbr = hbrBackground;
927     hbrOld = (HBRUSH) SelectObject (hdc, hbr);	// Select brush
928     FillRect (display.hdcMem, &rect, (HBRUSH) hbr);	// Draw rectangle
929     hbr = (HBRUSH) SelectObject (display.hdcMem, hbrOld);		// Unselect brush
930 
931 #if defined (commentout)
932     // GCS: For now, just keep the old bitmap around.
933     //      I'll use it to swap out the full-sized color bitmap
934     //      when I do a SetDIBits/GetDIBits.
935     display.hBitmapOri = hBitmapOri;
936 #endif /*  */
937 
938 #if defined (commentout)
939     // GCS: Instead of reselecting the default bitmap back into the hdc,
940     //      I'm gonna delete it. Any problems with this??
941     DeleteObject (hBitmapOri);
942 #endif /*  */
943 
944     ReleaseDC (hWnd, hdc);
945 }
946 
947 
948 void
ResizeDDB(HWND hWnd)949 ResizeDDB (HWND hWnd)
950 {
951     RECT rect;
952     HDC hdc;
953     HBRUSH hbr, hbrOld;
954 
955     hdc = GetDC (hWnd);
956     DeleteObject (display.hBitmap);
957     display.hBitmap = CreateCompatibleBitmap (hdc, pending_resize_w, pending_resize_h);
958     SelectObject (display.hdcMem, display.hBitmap);
959 
960     rect.left = 0;
961     rect.top = 0;
962     rect.right = pending_resize_w;
963     rect.bottom = pending_resize_h;
964     hbr = hbrBackground;
965     hbrOld = (HBRUSH) SelectObject (hdc, hbr);		    // Select brush
966     FillRect (display.hdcMem, &rect, (HBRUSH) hbr);	    // Draw rectangle
967     hbr = (HBRUSH) SelectObject (display.hdcMem, hbrOld);   // Unselect brush
968 
969     ReleaseDC (hWnd, hdc);
970 }
971 
972 //----------------------------------------------------------------------------
973 //  FUNCTION: CopyBackingStoreToScreen ()
974 //----------------------------------------------------------------------------
CopyBackingStoreToScreen(HDC hdc,HWND hWnd,LPPAINTSTRUCT ps)975 BOOL CopyBackingStoreToScreen (HDC hdc, HWND hWnd, LPPAINTSTRUCT ps)
976 {
977     HPALETTE hPalOld, hPalOldMem;
978 
979     // Is this necessary???
980     if (display.hasPalette) {
981 	hPalOldMem = SelectPalette (display.hdcMem, (HPALETTE) display.hPal, FALSE);
982 	RealizePalette (display.hdcMem);
983 	hPalOld = SelectPalette (hdc, (HPALETTE) display.hPal, FALSE);
984 	RealizePalette (hdc);
985     }
986 
987     // Copy DIB into DDB
988     if (display.useDIB) {
989 	if (SetDIBits (display.hdcMem, display.hBitmap, 0,
990 		       display.pbminfo->bmiHeader.biHeight, (LPSTR) display.pBits,
991 		       display.pbminfo, DIB_RGB_COLORS) == 0)
992 	{
993 	    MessageBox (display.hWnd, "Failed in SetDIBits!", "Error", MB_OK);
994 	    exit (-1);
995 	}
996     }
997 
998     // Blast DDB onto screen
999     if (!BitBlt (hdc, ps->rcPaint.left, ps->rcPaint.top,
1000 		 (int) ps->rcPaint.right - ps->rcPaint.left,
1001 		 (int) ps->rcPaint.bottom - ps->rcPaint.top,
1002 		 display.hdcMem, ps->rcPaint.left,
1003 		 ps->rcPaint.top, SRCCOPY))
1004     {
1005 	MessageBox (NULL, "BitBlt failed!", "Failure!", MB_OK);
1006     }
1007 
1008 
1009     // Draw square mouse
1010     if (cs_square_mouse_visible) {
1011 	DoSquareMouse (hdc);
1012     }
1013 
1014     if (display.hasPalette) {
1015 	display.hPal = SelectPalette (display.hdcMem, hPalOldMem, FALSE);
1016 	display.hPal = SelectPalette (hdc, hPalOld, FALSE);
1017     }
1018     return TRUE;
1019 }
1020 
1021 
1022 //----------------------------------------------------------------------------
1023 //  FUNCTION: DoSquareMouse ()
1024 //----------------------------------------------------------------------------
1025 void
DoSquareMouse(HDC hdc)1026 DoSquareMouse (HDC hdc)
1027 {
1028     RECT rect;
1029     int size;
1030     HBRUSH hbr, hbrOld;
1031 
1032     size = (main_groups[selected_module_group].size) * 16;
1033 
1034   // Select Brush
1035     hbr = GetPaletteBrush (white (31));
1036     hbrOld = (HBRUSH) SelectObject (hdc, hbr);
1037 
1038   // Top rectangle
1039     rect.left = AdjustX (omx - 2);
1040     rect.top = AdjustY (omy - 2);
1041     rect.right = AdjustX (omx + size + 1);
1042     rect.bottom = AdjustY (omy - 1);
1043     FillRect (hdc, &rect, hbr);
1044 
1045 
1046   // Left rectangle
1047     rect.left = AdjustX (omx - 2);
1048     rect.top = AdjustY (omy);
1049     rect.right = AdjustX (omx - 1);
1050     rect.bottom = AdjustY (omy + size - 1);
1051     FillRect (hdc, &rect, hbr);
1052 
1053   // Right rectangle
1054     rect.left = AdjustX (omx + size);
1055     rect.top = AdjustY (omy);
1056     rect.right = AdjustX (omx + size + 1);
1057     rect.bottom = AdjustY (omy + size - 1);
1058     FillRect (hdc, &rect, hbr);
1059 
1060   // Bottom rectangle
1061     rect.left = AdjustX (omx - 2);
1062     rect.top = AdjustY (omy + size);
1063     rect.right = AdjustX (omx + size + 1);
1064     rect.bottom = AdjustY (omy + size + 1);
1065     FillRect (hdc, &rect, hbr);
1066 
1067   // Unselect brush
1068     hbr = (HBRUSH) SelectObject (display.hdcMem, hbrOld);
1069 }
1070 
1071 
1072 //----------------------------------------------------------------------------
1073 //  FUNCTION: CopyPixmapToScreen ()
1074 //----------------------------------------------------------------------------
1075 #if defined (USE_PIXMAPS)
1076 void
CopyPixmapToScreen(int t2,int src_x,int src_y,int width,int height,int dst_x,int dst_y)1077 CopyPixmapToScreen (int t2, int src_x, int src_y, int width, int height,
1078 		    int dst_x, int dst_y)
1079 {
1080     HDC hdcPixmap;
1081     RECT rect;
1082 
1083     // Calculate update rectangle
1084     rect.left = AdjustX (dst_x);
1085     rect.top = AdjustY (dst_y);
1086     rect.right = AdjustX (dst_x + width + 1);
1087     rect.bottom = AdjustY (dst_y + height + 1);
1088 
1089     // Copy bitmap
1090     if (display.useDIB) {
1091 	HBITMAP hOldBitmap, hOldBitmapMem;
1092 	hdcPixmap = CreateCompatibleDC (display.hdcMem);
1093 	hOldBitmap = (HBITMAP) SelectObject (hdcPixmap, icon_pixmap[t2]);
1094 	hOldBitmapMem = (HBITMAP) SelectObject (display.hdcMem, display.hDIB);
1095 	BitBlt (display.hdcMem, dst_x, dst_y, width, height, hdcPixmap,
1096 		src_x, src_y, SRCCOPY);
1097 	icon_pixmap[t2] = (HBITMAP) SelectObject (hdcPixmap, hOldBitmap);
1098 	display.hDIB = (HBITMAP) SelectObject (display.hdcMem, hOldBitmapMem);
1099 	DeleteDC (hdcPixmap);
1100     } else {
1101 	HBITMAP hOldBitmap;
1102 	hdcPixmap = CreateCompatibleDC (display.hdcMem);
1103 	hOldBitmap = (HBITMAP) SelectObject (hdcPixmap, icon_pixmap[t2]);
1104 	BitBlt (display.hdcMem, AdjustX (dst_x), AdjustY (dst_y),
1105 		width << pix_double, height << pix_double, hdcPixmap,
1106 		src_x << pix_double, src_y << pix_double, SRCCOPY);
1107 	icon_pixmap[t2] = (HBITMAP) SelectObject (hdcPixmap, hOldBitmap);
1108 	DeleteDC (hdcPixmap);
1109     }
1110 
1111     // Queue up refresh
1112     InvalidateRect (display.hWnd, &rect, FALSE);
1113 }
1114 #endif /*  */
1115 
1116 
1117 //----------------------------------------------------------------------------
1118 //  FUNCTION: About(HWND, unsigned, WORD, LONG)
1119 //
1120 //  PURPOSE:  Processes messages for "About" dialog box
1121 //              This version allows greater flexibility over the contents of the 'About' box,
1122 //              by pulling out values from the 'Version' resource.
1123 //
1124 //  MESSAGES:
1125 //
1126 //      WM_INITDIALOG - initialize dialog box
1127 //      WM_COMMAND      - Input received
1128 //
1129 //----------------------------------------------------------------------------
1130 #if defined (USE_WIN32_MENU)
About(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)1131 LRESULT CALLBACK About (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1132 {
1133     static HFONT hfontDlg;	// Font for dialog text
1134     static HFONT hFinePrint;	// Font for 'fine print' in dialog
1135     DWORD dwVerInfoSize;		// Size of version information block
1136     LPSTR lpVersion;		// String pointer to 'version' text
1137     DWORD dwVerHnd = 0;		// An 'ignored' parameter, always '0'
1138     UINT uVersionLen;
1139     WORD wRootLen;
1140     BOOL bRetCode;
1141     int i;
1142     char szFullPath[256];
1143     char szResult[256];
1144     char szGetName[256];
1145     DWORD dwVersion;
1146     char szVersion[40];
1147     DWORD dwResult;
1148 
1149     switch (message)
1150     {
1151     case WM_INITDIALOG:
1152 	ShowWindow (hDlg, SW_HIDE);
1153 	hfontDlg = CreateFont (16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1154 			       VARIABLE_PITCH | FF_SWISS, "");
1155 	hFinePrint = CreateFont (16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1156 				 VARIABLE_PITCH | FF_SWISS, "");
1157 	CenterWindow (hDlg, GetWindow (hDlg, GW_OWNER));
1158 	GetModuleFileName (display.hInst, szFullPath, sizeof (szFullPath));
1159 
1160 	// Now lets dive in and pull out the version information:
1161 	dwVerInfoSize = GetFileVersionInfoSize (szFullPath, &dwVerHnd);
1162 	if (dwVerInfoSize) {
1163 	    LPSTR lpstrVffInfo;
1164 	    HANDLE hMem;
1165 	    hMem = GlobalAlloc (GMEM_MOVEABLE, dwVerInfoSize);
1166 	    lpstrVffInfo = (char *) GlobalLock (hMem);
1167 	    GetFileVersionInfo (szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
1168 
1169 	    // The below 'hex' value looks a little confusing, but
1170 	    // essentially what it is, is the hexidecimal representation
1171 	    // of a couple different values that represent the language
1172 	    // and character set that we are wanting string values for.
1173 	    // 040904E4 is a very common one, because it means:
1174 	    //   US English, Windows MultiLingual characterset
1175 	    // Or to pull it all apart:
1176 	    // 04------             = SUBLANG_ENGLISH_USA
1177 	    // --09----             = LANG_ENGLISH
1178 	    // ----04E4 = 1252 = Codepage for Windows:Multilingual
1179 	    lstrcpy (szGetName, "\\StringFileInfo\\040904E4\\");
1180 	    wRootLen = lstrlen (szGetName);	// Save this position
1181 
1182 	    // Set the title of the dialog:
1183 	    lstrcat (szGetName, "ProductName");
1184 	    bRetCode = VerQueryValue ((LPVOID) lpstrVffInfo,
1185 				      (LPSTR) szGetName,
1186 				      (LPVOID *) & lpVersion,
1187 				      (UINT *) & uVersionLen);
1188 	    lstrcpy (szResult, "About ");
1189 	    lstrcat (szResult, lpVersion);
1190 	    SetWindowText (hDlg, szResult);
1191 
1192 	    // Walk through the dialog items that we want to replace:
1193 	    for (i = DLG_VERFIRST; i <= DLG_VERLAST; i++) {
1194 		GetDlgItemText (hDlg, i, szResult, sizeof (szResult));
1195 		szGetName[wRootLen] = (char) 0;
1196 		lstrcat (szGetName, szResult);
1197 		uVersionLen = 0;
1198 		lpVersion = NULL;
1199 		bRetCode = VerQueryValue ((LPVOID) lpstrVffInfo,
1200 					  (LPSTR) szGetName,
1201 					  (LPVOID *) & lpVersion,
1202 					  (UINT *) & uVersionLen);
1203 
1204 		if (bRetCode && uVersionLen && lpVersion) {
1205 		    // Replace dialog item text with version info
1206 		    lstrcpy (szResult, lpVersion);
1207 		    SetDlgItemText (hDlg, i, szResult);
1208 		} else {
1209 		    dwResult = GetLastError ();
1210 		    wsprintf (szResult, "Error %lu", dwResult);
1211 		    SetDlgItemText (hDlg, i, szResult);
1212 		}
1213 		SendMessage (GetDlgItem (hDlg, i), WM_SETFONT,
1214 			     (UINT) ((i == DLG_VERLAST) ? hFinePrint : hfontDlg),
1215 			     TRUE);
1216 	    }
1217 	    GlobalUnlock (hMem);
1218 	    GlobalFree (hMem);
1219 	} else {
1220 	    // No version information available.
1221 	}
1222 	SendMessage (GetDlgItem (hDlg, IDC_LABEL), WM_SETFONT,
1223 		     (WPARAM) hfontDlg, (LPARAM) TRUE);
1224 
1225 	// We are  using GetVersion rather then GetVersionEx
1226 	// because earlier versions of Windows NT and Win32s
1227 	// didn't include GetVersionEx:
1228 	dwVersion = GetVersion ();
1229 	if (dwVersion < 0x80000000) {
1230 	    // Windows NT
1231 	    wsprintf (szVersion, "Microsoft Windows NT %u.%u (Build: %u)",
1232 		      (DWORD) (LOBYTE (LOWORD (dwVersion))),
1233 		      (DWORD) (HIBYTE (LOWORD (dwVersion))),
1234 		      (DWORD) (HIWORD (dwVersion)));
1235 
1236 	} else if (LOBYTE (LOWORD (dwVersion)) < 4) {
1237 	    // Win32s
1238 	    wsprintf (szVersion, "Microsoft Win32s %u.%u (Build: %u)",
1239 		      (DWORD) (LOBYTE (LOWORD (dwVersion))),
1240 		      (DWORD) (HIBYTE (LOWORD (dwVersion))),
1241 		      (DWORD) (HIWORD (dwVersion) & ~0x8000));
1242 	} else {
1243 	    // Windows 95
1244 	    wsprintf (szVersion, "Microsoft Windows 95 %u.%u",
1245 		      (DWORD) (LOBYTE (LOWORD (dwVersion))),
1246 		      (DWORD) (HIBYTE (LOWORD (dwVersion))));
1247 	}
1248 	SetWindowText (GetDlgItem (hDlg, IDC_OSVERSION), szVersion);
1249 	ShowWindow (hDlg, SW_SHOW);
1250 	return (TRUE);
1251 
1252     case WM_COMMAND:
1253 	if (LOWORD (wParam) == IDOK || LOWORD (wParam) == IDCANCEL) {
1254 	    EndDialog (hDlg, TRUE);
1255 	    DeleteObject (hfontDlg);
1256 	    DeleteObject (hFinePrint);
1257 	    return (TRUE);
1258 	}
1259 	break;
1260     }
1261     return FALSE;
1262 }
1263 
1264 
1265 
1266 //----------------------------------------------------------------------------
1267 //   FUNCTION: CenterWindow(HWND, HWND)
1268 //
1269 //   PURPOSE: Centers one window over another.
1270 //
1271 //   COMMENTS:
1272 //
1273 //              In this function, we save the instance handle in a global variable and
1274 //              create and display the main program window.
1275 //
1276 //              This functionwill center one window over another ensuring that
1277 //              the placement of the window is within the 'working area', meaning
1278 //              that it is both within the display limits of the screen, and not
1279 //              obscured by the tray or other framing elements of the desktop.
1280 //----------------------------------------------------------------------------
CenterWindow(HWND hwndChild,HWND hwndParent)1281 BOOL CenterWindow (HWND hwndChild, HWND hwndParent)
1282 {
1283     RECT rChild, rParent, rWorkArea;
1284     int wChild, hChild, wParent, hParent;
1285     int xNew, yNew;
1286     BOOL bResult;
1287 
1288     // Get the Height and Width of the child window
1289     GetWindowRect (hwndChild, &rChild);
1290     wChild = rChild.right - rChild.left;
1291     hChild = rChild.bottom - rChild.top;
1292 
1293     // Get the Height and Width of the parent window
1294     GetWindowRect (hwndParent, &rParent);
1295     wParent = rParent.right - rParent.left;
1296     hParent = rParent.bottom - rParent.top;
1297 
1298     // Get the limits of the 'workarea'
1299     bResult = SystemParametersInfo (SPI_GETWORKAREA,
1300 				    sizeof (RECT),
1301 				    &rWorkArea,
1302 				    0);
1303 
1304     if (!bResult) {
1305 	rWorkArea.left = rWorkArea.top = 0;
1306 	rWorkArea.right = GetSystemMetrics (SM_CXSCREEN);
1307 	rWorkArea.bottom = GetSystemMetrics (SM_CYSCREEN);
1308     }
1309 
1310     // Calculate new X position, then adjust for workarea
1311     xNew = rParent.left + ((wParent - wChild) / 2);
1312 
1313     if (xNew < rWorkArea.left) {
1314 	xNew = rWorkArea.left;
1315     }
1316     else if ((xNew + wChild) > rWorkArea.right) {
1317 	xNew = rWorkArea.right - wChild;
1318     }
1319 
1320     // Calculate new Y position, then adjust for workarea
1321     yNew = rParent.top + ((hParent - hChild) / 2);
1322     if (yNew < rWorkArea.top) {
1323 	yNew = rWorkArea.top;
1324     } else if ((yNew + hChild) > rWorkArea.bottom) {
1325 	yNew = rWorkArea.bottom - hChild;
1326     }
1327 
1328     // Set it, and return
1329     return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
1330 }
1331 #endif /* USE_WIN32_MENU */
1332 
1333 
1334 //----------------------------------------------------------------------------
1335 //   FUNCTION: AddPaletteEntry ()
1336 //----------------------------------------------------------------------------
1337 void
AddPaletteEntry(int col,int red,int grn,int blu)1338 AddPaletteEntry (int col, int red, int grn, int blu)
1339 {
1340 
1341     red = (red * 255) / 62;
1342     if (red > 255)
1343 	red = 255;
1344 
1345     grn = (grn * 255) / 62;
1346     if (grn > 255)
1347 	grn = 255;
1348 
1349     blu = (blu * 255) / 62;
1350     if (blu > 255)
1351 	blu = 255;
1352 
1353     display.colorrefPal[col] = RGB (red, grn, blu);
1354 
1355     if (display.brushPal[col]) {
1356 	DeleteObject (display.brushPal[col]);
1357 	display.brushPal[col] = 0;
1358     }
1359 
1360     if (display.hasPalette) {
1361 	display.pLogPal->palPalEntry[col].peRed = red;
1362 	display.pLogPal->palPalEntry[col].peGreen = grn;
1363 	display.pLogPal->palPalEntry[col].peBlue = blu;
1364 	display.pLogPal->palPalEntry[col].peFlags = PC_NOCOLLAPSE;
1365     }
1366 
1367     if (display.useDIB) {
1368 	display.pbminfo->bmiColors[col].rgbRed = red;
1369 	display.pbminfo->bmiColors[col].rgbGreen = grn;
1370 	display.pbminfo->bmiColors[col].rgbBlue = blu;
1371 	display.pbminfo->bmiColors[col].rgbReserved = 0;
1372     }
1373 }
1374 
1375 
1376 //----------------------------------------------------------------------------
1377 //  FUNCTION: UpdatePalette ()
1378 //----------------------------------------------------------------------------
1379 void
UpdatePalette(void)1380 UpdatePalette (void)
1381 {
1382     if (display.hasPalette) {
1383 	// Make a new HPALETTE and select to hdcGlobal and hdcMem
1384 	HPALETTE hPalNew;
1385 	hPalNew = CreatePalette ((LPLOGPALETTE) display.pLogPal);
1386 	SelectPalette (display.hdcMem, hPalNew, FALSE);
1387 	RealizePalette (display.hdcMem);
1388 	DeleteObject (display.hPal);
1389 	display.hPal = hPalNew;
1390     }
1391 }
1392 
1393