• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2006 Sam Lantinga
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23 
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26 
27 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
28 #ifndef WM_XBUTTONDOWN
29 #define WM_XBUTTONDOWN 0x020B
30 #endif
31 #ifndef WM_XBUTTONUP
32 #define WM_XBUTTONUP 0x020C
33 #endif
34 #ifndef GET_XBUTTON_WPARAM
35 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
36 #endif
37 
38 #include "SDL_events.h"
39 #include "SDL_video.h"
40 #include "SDL_syswm.h"
41 #include "../SDL_sysvideo.h"
42 #include "../../events/SDL_sysevents.h"
43 #include "../../events/SDL_events_c.h"
44 #include "SDL_lowvideo.h"
45 #include "SDL_syswm_c.h"
46 #include "SDL_main.h"
47 #include "SDL_loadso.h"
48 
49 #ifdef WMMSG_DEBUG
50 #include "wmmsg.h"
51 #endif
52 
53 #ifdef _WIN32_WCE
54 #include "../gapi/SDL_gapivideo.h"
55 
56 #define IsZoomed(HWND) 1
57 #define NO_GETKEYBOARDSTATE
58 #if _WIN32_WCE < 420
59 #define NO_CHANGEDISPLAYSETTINGS
60 #endif
61 #endif
62 
63 /* The window we use for everything... */
64 #ifdef _WIN32_WCE
65 LPWSTR SDL_Appname = NULL;
66 #else
67 LPSTR SDL_Appname = NULL;
68 #endif
69 Uint32 SDL_Appstyle = 0;
70 HINSTANCE SDL_Instance = NULL;
71 HWND SDL_Window = NULL;
72 RECT SDL_bounds = {0, 0, 0, 0};
73 int SDL_windowX = 0;
74 int SDL_windowY = 0;
75 int SDL_resizing = 0;
76 int mouse_relative = 0;
77 int posted = 0;
78 #ifndef NO_CHANGEDISPLAYSETTINGS
79 DEVMODE SDL_desktop_mode;
80 DEVMODE SDL_fullscreen_mode;
81 #endif
82 WORD *gamma_saved = NULL;
83 
84 
85 /* Functions called by the message processing function */
86 LONG (*HandleMessage)(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)=NULL;
87 void (*WIN_Activate)(_THIS, BOOL active, BOOL iconic);
88 void (*WIN_RealizePalette)(_THIS);
89 void (*WIN_PaletteChanged)(_THIS, HWND window);
90 void (*WIN_WinPAINT)(_THIS, HDC hdc);
91 extern void DIB_SwapGamma(_THIS);
92 
93 #ifndef NO_GETKEYBOARDSTATE
94 /* Variables and support functions for SDL_ToUnicode() */
95 static int codepage;
96 static int Is9xME();
97 static int GetCodePage();
98 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, BYTE *keystate, LPWSTR wchars, int wsize, UINT flags);
99 
100 ToUnicodeFN SDL_ToUnicode = ToUnicode9xME;
101 #endif /* !NO_GETKEYBOARDSTATE */
102 
103 
104 #if defined(_WIN32_WCE)
105 
106 // dynamically load aygshell dll because we want SDL to work on HPC and be300
107 HINSTANCE aygshell = NULL;
108 BOOL (WINAPI *SHFullScreen)(HWND hwndRequester, DWORD dwState) = 0;
109 
110 #define SHFS_SHOWTASKBAR            0x0001
111 #define SHFS_HIDETASKBAR            0x0002
112 #define SHFS_SHOWSIPBUTTON          0x0004
113 #define SHFS_HIDESIPBUTTON          0x0008
114 #define SHFS_SHOWSTARTICON          0x0010
115 #define SHFS_HIDESTARTICON          0x0020
116 
LoadAygshell(void)117 static void LoadAygshell(void)
118 {
119 	if( !aygshell )
120 		 aygshell = SDL_LoadObject("aygshell.dll");
121 	if( (aygshell != 0) && (SHFullScreen == 0) )
122 	{
123 		SHFullScreen = (int (WINAPI *)(struct HWND__ *,unsigned long)) SDL_LoadFunction(aygshell, "SHFullScreen");
124 	}
125 }
126 
127 /* for gapi landscape mode */
GapiTransform(SDL_ScreenOrientation rotate,char hires,Sint16 * x,Sint16 * y)128 static void GapiTransform(SDL_ScreenOrientation rotate, char hires, Sint16 *x, Sint16 *y) {
129 	Sint16 rotatedX;
130 	Sint16 rotatedY;
131 
132 	if (hires) {
133 		*x = *x * 2;
134 		*y = *y * 2;
135 	}
136 
137 	switch(rotate) {
138 		case SDL_ORIENTATION_UP:
139 			{
140 /* this code needs testing on a real device!
141    So it will be enabled later */
142 /*
143 #ifdef _WIN32_WCE
144 #if _WIN32_WCE >= 420
145 				// test device orientation
146 				// FIXME: do not check every mouse message
147 				DEVMODE settings;
148 				SDL_memset(&settings, 0, sizeof(DEVMODE));
149 				settings.dmSize = sizeof(DEVMODE);
150 				settings.dmFields = DM_DISPLAYORIENTATION;
151 				ChangeDisplaySettingsEx(NULL, &settings, NULL, CDS_TEST, NULL);
152 				if( settings.dmOrientation == DMDO_90 )
153 				{
154 					rotatedX = SDL_VideoSurface->h - *x;
155 					rotatedY = *y;
156 					*x = rotatedX;
157 					*y = rotatedY;
158 				}
159 #endif
160 #endif */
161 			}
162 			break;
163 		case SDL_ORIENTATION_RIGHT:
164 			if (!SDL_VideoSurface)
165 				break;
166 			rotatedX = SDL_VideoSurface->w - *y;
167 			rotatedY = *x;
168 			*x = rotatedX;
169 			*y = rotatedY;
170 			break;
171 		case SDL_ORIENTATION_LEFT:
172 			if (!SDL_VideoSurface)
173 				break;
174 			rotatedX = *y;
175 			rotatedY = SDL_VideoSurface->h - *x;
176 			*x = rotatedX;
177 			*y = rotatedY;
178 			break;
179 	}
180 }
181 
182 #endif
183 
184 /* JC 14 Mar 2006
185    This is used all over the place, in the windib driver and in the dx5 driver
186    So we may as well stick it here instead of having multiple copies scattered
187    about
188 */
WIN_FlushMessageQueue()189 void WIN_FlushMessageQueue()
190 {
191 	MSG  msg;
192 	while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
193 		if ( msg.message == WM_QUIT ) break;
194 		TranslateMessage( &msg );
195 		DispatchMessage( &msg );
196 	}
197 }
198 
SDL_RestoreGameMode(void)199 static void SDL_RestoreGameMode(void)
200 {
201 #ifdef _WIN32_WCE
202 	SDL_VideoDevice *this = current_video;
203 	if(SDL_strcmp(this->name, "gapi") == 0)
204 	{
205 		if( this->hidden->suspended )
206 		{
207 			this->hidden->suspended = 0;
208 		}
209 	}
210 #else
211 	ShowWindow(SDL_Window, SW_RESTORE);
212 #endif
213 
214 #ifndef NO_CHANGEDISPLAYSETTINGS
215 #ifndef _WIN32_WCE
216 	ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN);
217 #endif
218 #endif /* NO_CHANGEDISPLAYSETTINGS */
219 }
SDL_RestoreDesktopMode(void)220 static void SDL_RestoreDesktopMode(void)
221 {
222 
223 #ifdef _WIN32_WCE
224 	SDL_VideoDevice *this = current_video;
225 	if(SDL_strcmp(this->name, "gapi") == 0)
226 	{
227 		if( !this->hidden->suspended )
228 		{
229 			this->hidden->suspended = 1;
230 		}
231 	}
232 #else
233 	/* WinCE does not have a taskbar, so minimizing is not convenient */
234 	ShowWindow(SDL_Window, SW_MINIMIZE);
235 #endif
236 
237 #ifndef NO_CHANGEDISPLAYSETTINGS
238 #ifndef _WIN32_WCE
239 	ChangeDisplaySettings(NULL, 0);
240 #endif
241 #endif /* NO_CHANGEDISPLAYSETTINGS */
242 }
243 
244 #ifdef WM_MOUSELEAVE
245 /*
246    Special code to handle mouse leave events - this sucks...
247    http://support.microsoft.com/support/kb/articles/q183/1/07.asp
248 
249    TrackMouseEvent() is only available on Win98 and WinNT.
250    _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
251    development environment, and only works on systems that have had IE 3.0
252    or newer installed on them (which is not the case with the base Win95).
253    Therefore, we implement our own version of _TrackMouseEvent() which
254    uses our own implementation if TrackMouseEvent() is not available.
255 */
256 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
257 
258 static VOID CALLBACK
TrackMouseTimerProc(HWND hWnd,UINT uMsg,UINT idEvent,DWORD dwTime)259 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
260 {
261 	RECT rect;
262 	POINT pt;
263 
264 	GetClientRect(hWnd, &rect);
265 	MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2);
266 	GetCursorPos(&pt);
267 	if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
268 		if ( !KillTimer(hWnd, idEvent) ) {
269 			/* Error killing the timer! */
270 		}
271 		PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
272 	}
273 }
WIN_TrackMouseEvent(TRACKMOUSEEVENT * ptme)274 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
275 {
276 	if ( ptme->dwFlags == TME_LEAVE ) {
277 		return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
278 		                (TIMERPROC)TrackMouseTimerProc) != 0;
279 	}
280 	return FALSE;
281 }
282 #endif /* WM_MOUSELEAVE */
283 
284 /* Function to retrieve the current keyboard modifiers */
WIN_GetKeyboardState(void)285 static void WIN_GetKeyboardState(void)
286 {
287 #ifndef NO_GETKEYBOARDSTATE
288 	SDLMod state;
289 	BYTE keyboard[256];
290 	Uint8 *kstate = SDL_GetKeyState(NULL);
291 
292 	state = KMOD_NONE;
293 	if ( GetKeyboardState(keyboard) ) {
294 		if ( keyboard[VK_LSHIFT] & 0x80) {
295 			state |= KMOD_LSHIFT;
296 			kstate[SDLK_LSHIFT] = SDL_PRESSED;
297 		}
298 		if ( keyboard[VK_RSHIFT] & 0x80) {
299 			state |= KMOD_RSHIFT;
300 			kstate[SDLK_RSHIFT] = SDL_PRESSED;
301 		}
302 		if ( keyboard[VK_LCONTROL] & 0x80) {
303 			state |= KMOD_LCTRL;
304 			kstate[SDLK_LCTRL] = SDL_PRESSED;
305 		}
306 		if ( keyboard[VK_RCONTROL] & 0x80) {
307 			state |= KMOD_RCTRL;
308 			kstate[SDLK_RCTRL] = SDL_PRESSED;
309 		}
310 		if ( keyboard[VK_LMENU] & 0x80) {
311 			state |= KMOD_LALT;
312 			kstate[SDLK_LALT] = SDL_PRESSED;
313 		}
314 		if ( keyboard[VK_RMENU] & 0x80) {
315 			state |= KMOD_RALT;
316 			kstate[SDLK_RALT] = SDL_PRESSED;
317 		}
318 		if ( keyboard[VK_NUMLOCK] & 0x01) {
319 			state |= KMOD_NUM;
320 			kstate[SDLK_NUMLOCK] = SDL_PRESSED;
321 		}
322 		if ( keyboard[VK_CAPITAL] & 0x01) {
323 			state |= KMOD_CAPS;
324 			kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
325 		}
326 	}
327 	SDL_SetModState(state);
328 #endif /* !NO_GETKEYBOARDSTATE */
329 }
330 
331 /* The main Win32 event handler
332 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it
333 */
WinMessage(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)334 LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
335 {
336 	SDL_VideoDevice *this = current_video;
337 	static int mouse_pressed = 0;
338 	static int in_window = 0;
339 #ifdef WMMSG_DEBUG
340 	fprintf(stderr, "Received windows message:  ");
341 	if ( msg > MAX_WMMSG ) {
342 		fprintf(stderr, "%d", msg);
343 	} else {
344 		fprintf(stderr, "%s", wmtab[msg]);
345 	}
346 	fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
347 #endif
348 	switch (msg) {
349 
350 		case WM_ACTIVATE: {
351 			SDL_VideoDevice *this = current_video;
352 			BOOL active, minimized;
353 			Uint8 appstate;
354 
355 			minimized = HIWORD(wParam);
356 			active = (LOWORD(wParam) != WA_INACTIVE) && !minimized;
357 			if ( active ) {
358 				/* Gain the following states */
359 				appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
360 				if ( this->input_grab != SDL_GRAB_OFF ) {
361 					WIN_GrabInput(this, SDL_GRAB_ON);
362 				}
363 				if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) {
364 					if ( ! DDRAW_FULLSCREEN() ) {
365 						DIB_SwapGamma(this);
366 					}
367 					if ( WINDIB_FULLSCREEN() ) {
368 						SDL_RestoreGameMode();
369 					}
370 				}
371 #if defined(_WIN32_WCE)
372 				if ( WINDIB_FULLSCREEN() ) {
373 					LoadAygshell();
374 					if( SHFullScreen )
375 						SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON);
376 					else
377 						ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE);
378 				}
379 #endif
380 				posted = SDL_PrivateAppActive(1, appstate);
381 				WIN_GetKeyboardState();
382 			} else {
383 				/* Lose the following states */
384 				appstate = SDL_APPINPUTFOCUS;
385 				if ( minimized ) {
386 					appstate |= SDL_APPACTIVE;
387 				}
388 				if ( this->input_grab != SDL_GRAB_OFF ) {
389 					WIN_GrabInput(this, SDL_GRAB_OFF);
390 				}
391 				if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
392 					if ( ! DDRAW_FULLSCREEN() ) {
393 						DIB_SwapGamma(this);
394 					}
395 					if ( WINDIB_FULLSCREEN() ) {
396 						SDL_RestoreDesktopMode();
397 #if defined(_WIN32_WCE)
398 						LoadAygshell();
399 						if( SHFullScreen )
400 							SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON);
401 						else
402 							ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW);
403 #endif
404 					}
405 				}
406 				posted = SDL_PrivateAppActive(0, appstate);
407 			}
408 			WIN_Activate(this, active, minimized);
409 			return(0);
410 		}
411 		break;
412 
413 		case WM_MOUSEMOVE: {
414 
415 			/* Mouse is handled by DirectInput when fullscreen */
416 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
417 				Sint16 x, y;
418 
419 				/* mouse has entered the window */
420 				if ( ! in_window ) {
421 #ifdef WM_MOUSELEAVE
422 					TRACKMOUSEEVENT tme;
423 
424 					tme.cbSize = sizeof(tme);
425 					tme.dwFlags = TME_LEAVE;
426 					tme.hwndTrack = SDL_Window;
427 					_TrackMouseEvent(&tme);
428 #endif /* WM_MOUSELEAVE */
429 					in_window = TRUE;
430 
431 					posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
432 				}
433 
434 				/* mouse has moved within the window */
435 				x = LOWORD(lParam);
436 				y = HIWORD(lParam);
437 				if ( mouse_relative ) {
438 					POINT center;
439 					center.x = (SDL_VideoSurface->w/2);
440 					center.y = (SDL_VideoSurface->h/2);
441 					x -= (Sint16)center.x;
442 					y -= (Sint16)center.y;
443 					if ( x || y ) {
444 						ClientToScreen(SDL_Window, &center);
445 						SetCursorPos(center.x, center.y);
446 						posted = SDL_PrivateMouseMotion(0, 1, x, y);
447 					}
448 				} else {
449 #ifdef _WIN32_WCE
450 					if (SDL_VideoSurface)
451 						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
452 #endif
453 					posted = SDL_PrivateMouseMotion(0, 0, x, y);
454 				}
455 			}
456 		}
457 		return(0);
458 
459 #ifdef WM_MOUSELEAVE
460 		case WM_MOUSELEAVE: {
461 
462 			/* Mouse is handled by DirectInput when fullscreen */
463 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
464 				/* mouse has left the window */
465 				/* or */
466 				/* Elvis has left the building! */
467 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
468 			}
469 			in_window = FALSE;
470 		}
471 		return(0);
472 #endif /* WM_MOUSELEAVE */
473 
474 		case WM_LBUTTONDOWN:
475 		case WM_LBUTTONUP:
476 		case WM_MBUTTONDOWN:
477 		case WM_MBUTTONUP:
478 		case WM_RBUTTONDOWN:
479 		case WM_RBUTTONUP:
480 		case WM_XBUTTONDOWN:
481 		case WM_XBUTTONUP: {
482 			/* Mouse is handled by DirectInput when fullscreen */
483 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
484 				WORD xbuttonval = 0;
485 				Sint16 x, y;
486 				Uint8 button, state;
487 
488 				/* DJM:
489 				   We want the SDL window to take focus so that
490 				   it acts like a normal windows "component"
491 				   (e.g. gains keyboard focus on a mouse click).
492 				 */
493 				SetFocus(SDL_Window);
494 
495 				/* Figure out which button to use */
496 				switch (msg) {
497 					case WM_LBUTTONDOWN:
498 						button = SDL_BUTTON_LEFT;
499 						state = SDL_PRESSED;
500 						break;
501 					case WM_LBUTTONUP:
502 						button = SDL_BUTTON_LEFT;
503 						state = SDL_RELEASED;
504 						break;
505 					case WM_MBUTTONDOWN:
506 						button = SDL_BUTTON_MIDDLE;
507 						state = SDL_PRESSED;
508 						break;
509 					case WM_MBUTTONUP:
510 						button = SDL_BUTTON_MIDDLE;
511 						state = SDL_RELEASED;
512 						break;
513 					case WM_RBUTTONDOWN:
514 						button = SDL_BUTTON_RIGHT;
515 						state = SDL_PRESSED;
516 						break;
517 					case WM_RBUTTONUP:
518 						button = SDL_BUTTON_RIGHT;
519 						state = SDL_RELEASED;
520 						break;
521 					case WM_XBUTTONDOWN:
522 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
523 						button = SDL_BUTTON_WHEELDOWN + xbuttonval;
524 						state = SDL_PRESSED;
525 						break;
526 					case WM_XBUTTONUP:
527 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
528 						button = SDL_BUTTON_WHEELDOWN + xbuttonval;
529 						state = SDL_RELEASED;
530 						break;
531 					default:
532 						/* Eh? Unknown button? */
533 						return(0);
534 				}
535 				if ( state == SDL_PRESSED ) {
536 					/* Grab mouse so we get up events */
537 					if ( ++mouse_pressed > 0 ) {
538 						SetCapture(hwnd);
539 					}
540 				} else {
541 					/* Release mouse after all up events */
542 					if ( --mouse_pressed <= 0 ) {
543 						ReleaseCapture();
544 						mouse_pressed = 0;
545 					}
546 				}
547 				if ( mouse_relative ) {
548 				/*	RJR: March 28, 2000
549 					report internal mouse position if in relative mode */
550 					x = 0; y = 0;
551 				} else {
552 					x = (Sint16)LOWORD(lParam);
553 					y = (Sint16)HIWORD(lParam);
554 #ifdef _WIN32_WCE
555 					if (SDL_VideoSurface)
556 						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
557 #endif
558 				}
559 				posted = SDL_PrivateMouseButton(
560 							state, button, x, y);
561 
562 				/*
563 				 * MSDN says:
564 				 *  "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP
565 				 *   messages, an application should return TRUE from [an
566 				 *   XBUTTON message] if it processes it. Doing so will allow
567 				 *   software that simulates this message on Microsoft Windows
568 				 *   systems earlier than Windows 2000 to determine whether
569 				 *   the window procedure processed the message or called
570 				 *   DefWindowProc to process it.
571 				 */
572 				if (xbuttonval > 0)
573 					return(TRUE);
574 			}
575 		}
576 		return(0);
577 
578 
579 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
580 		case WM_MOUSEWHEEL:
581 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
582 				int move = (short)HIWORD(wParam);
583 				if ( move ) {
584 					Uint8 button;
585 					if ( move > 0 )
586 						button = SDL_BUTTON_WHEELUP;
587 					else
588 						button = SDL_BUTTON_WHEELDOWN;
589 					posted = SDL_PrivateMouseButton(
590 						SDL_PRESSED, button, 0, 0);
591 					posted |= SDL_PrivateMouseButton(
592 						SDL_RELEASED, button, 0, 0);
593 				}
594 			}
595 			return(0);
596 #endif
597 
598 #ifdef WM_GETMINMAXINFO
599 		/* This message is sent as a way for us to "check" the values
600 		 * of a position change.  If we don't like it, we can adjust
601 		 * the values before they are changed.
602 		 */
603 		case WM_GETMINMAXINFO: {
604 			MINMAXINFO *info;
605 			RECT        size;
606 			int x, y;
607 			int style;
608 			int width;
609 			int height;
610 
611 			/* We don't want to clobber an internal resize */
612 			if ( SDL_resizing )
613 				return(0);
614 
615 			/* We allow resizing with the SDL_RESIZABLE flag */
616 			if ( SDL_PublicSurface &&
617 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
618 				return(0);
619 			}
620 
621 			/* Get the current position of our window */
622 			GetWindowRect(SDL_Window, &size);
623 			x = size.left;
624 			y = size.top;
625 
626 			/* Calculate current width and height of our window */
627 			size.top = 0;
628 			size.left = 0;
629 			if ( SDL_PublicSurface != NULL ) {
630 				size.bottom = SDL_PublicSurface->h;
631 				size.right = SDL_PublicSurface->w;
632 			} else {
633 				size.bottom = 0;
634 				size.right = 0;
635 			}
636 
637 			/* DJM - according to the docs for GetMenu(), the
638 			   return value is undefined if hwnd is a child window.
639 			   Aparently it's too difficult for MS to check
640 			   inside their function, so I have to do it here.
641           		 */
642          		style = GetWindowLong(hwnd, GWL_STYLE);
643          		AdjustWindowRect(
644 				&size,
645 				style,
646             			style & WS_CHILDWINDOW ? FALSE
647 						       : GetMenu(hwnd) != NULL);
648 
649 			width = size.right - size.left;
650 			height = size.bottom - size.top;
651 
652 			/* Fix our size to the current size */
653 			info = (MINMAXINFO *)lParam;
654 			info->ptMaxSize.x = width;
655 			info->ptMaxSize.y = height;
656 			info->ptMaxPosition.x = x;
657 			info->ptMaxPosition.y = y;
658 			info->ptMinTrackSize.x = width;
659 			info->ptMinTrackSize.y = height;
660 			info->ptMaxTrackSize.x = width;
661 			info->ptMaxTrackSize.y = height;
662 		}
663 		return(0);
664 #endif /* WM_GETMINMAXINFO */
665 
666 		case WM_WINDOWPOSCHANGED: {
667 			SDL_VideoDevice *this = current_video;
668 			int w, h;
669 
670 			GetClientRect(SDL_Window, &SDL_bounds);
671 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds);
672 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1);
673 			if ( !SDL_resizing && !IsZoomed(SDL_Window) &&
674 			     SDL_PublicSurface &&
675 				!(SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
676 				SDL_windowX = SDL_bounds.left;
677 				SDL_windowY = SDL_bounds.top;
678 			}
679 			w = SDL_bounds.right-SDL_bounds.left;
680 			h = SDL_bounds.bottom-SDL_bounds.top;
681 			if ( this->input_grab != SDL_GRAB_OFF ) {
682 				ClipCursor(&SDL_bounds);
683 			}
684 			if ( SDL_PublicSurface &&
685 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
686 				SDL_PrivateResize(w, h);
687 			}
688 		}
689 		break;
690 
691 		/* We need to set the cursor */
692 		case WM_SETCURSOR: {
693 			Uint16 hittest;
694 
695 			hittest = LOWORD(lParam);
696 			if ( hittest == HTCLIENT ) {
697 				SetCursor(SDL_hcursor);
698 				return(TRUE);
699 			}
700 		}
701 		break;
702 
703 		/* We are about to get palette focus! */
704 		case WM_QUERYNEWPALETTE: {
705 			WIN_RealizePalette(current_video);
706 			return(TRUE);
707 		}
708 		break;
709 
710 		/* Another application changed the palette */
711 		case WM_PALETTECHANGED: {
712 			WIN_PaletteChanged(current_video, (HWND)wParam);
713 		}
714 		break;
715 
716 		/* We were occluded, refresh our display */
717 		case WM_PAINT: {
718 			HDC hdc;
719 			PAINTSTRUCT ps;
720 
721 			hdc = BeginPaint(SDL_Window, &ps);
722 			if ( current_video->screen &&
723 			     !(current_video->screen->flags & SDL_OPENGL) ) {
724 				WIN_WinPAINT(current_video, hdc);
725 			}
726 			EndPaint(SDL_Window, &ps);
727 		}
728 		return(0);
729 
730 		/* DJM: Send an expose event in this case */
731 		case WM_ERASEBKGND: {
732 			posted = SDL_PrivateExpose();
733 		}
734 		return(0);
735 
736 		case WM_CLOSE: {
737 			if ( (posted = SDL_PrivateQuit()) )
738 				PostQuitMessage(0);
739 		}
740 		return(0);
741 
742 		case WM_DESTROY: {
743 			PostQuitMessage(0);
744 		}
745 		return(0);
746 
747 #ifndef NO_GETKEYBOARDSTATE
748 		case WM_INPUTLANGCHANGE: {
749 			codepage = GetCodePage();
750 		}
751 		return(TRUE);
752 #endif
753 
754 		default: {
755 			/* Special handling by the video driver */
756 			if (HandleMessage) {
757 				return(HandleMessage(current_video,
758 			                     hwnd, msg, wParam, lParam));
759 			}
760 		}
761 		break;
762 	}
763 	return(DefWindowProc(hwnd, msg, wParam, lParam));
764 }
765 
766 /* Allow the application handle to be stored and retrieved later */
767 static void *SDL_handle = NULL;
768 
SDL_SetModuleHandle(void * handle)769 void SDL_SetModuleHandle(void *handle)
770 {
771 	SDL_handle = handle;
772 }
SDL_GetModuleHandle(void)773 void *SDL_GetModuleHandle(void)
774 {
775 	void *handle;
776 
777 	if ( SDL_handle ) {
778 		handle = SDL_handle;
779 	} else {
780 		handle = GetModuleHandle(NULL);
781 	}
782 	return(handle);
783 }
784 
785 /* This allows the SDL_WINDOWID hack */
786 BOOL SDL_windowid = FALSE;
787 
788 static int app_registered = 0;
789 
790 /* Register the class for this application -- exported for winmain.c */
SDL_RegisterApp(char * name,Uint32 style,void * hInst)791 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
792 {
793 	WNDCLASS class;
794 #ifdef WM_MOUSELEAVE
795 	HMODULE handle;
796 #endif
797 
798 	/* Only do this once... */
799 	if ( app_registered ) {
800 		++app_registered;
801 		return(0);
802 	}
803 
804 #ifndef CS_BYTEALIGNCLIENT
805 #define CS_BYTEALIGNCLIENT	0
806 #endif
807 	if ( ! name && ! SDL_Appname ) {
808 		name = "SDL_app";
809 		SDL_Appstyle = CS_BYTEALIGNCLIENT;
810 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
811 	}
812 
813 	if ( name ) {
814 #ifdef _WIN32_WCE
815 		/* WinCE uses the UNICODE version */
816 		SDL_Appname = SDL_iconv_utf8_ucs2(name);
817 #else
818 		SDL_Appname = SDL_iconv_utf8_locale(name);
819 #endif /* _WIN32_WCE */
820 		SDL_Appstyle = style;
821 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
822 	}
823 
824 	/* Register the application class */
825 	class.hCursor		= NULL;
826 	class.hIcon		= LoadImage(SDL_Instance, SDL_Appname,
827 				            IMAGE_ICON,
828 	                                    0, 0, LR_DEFAULTCOLOR);
829 	class.lpszMenuName	= NULL;
830 	class.lpszClassName	= SDL_Appname;
831 	class.hbrBackground	= NULL;
832 	class.hInstance		= SDL_Instance;
833 	class.style		= SDL_Appstyle;
834 #if SDL_VIDEO_OPENGL
835 	class.style		|= CS_OWNDC;
836 #endif
837 	class.lpfnWndProc	= WinMessage;
838 	class.cbWndExtra	= 0;
839 	class.cbClsExtra	= 0;
840 	if ( ! RegisterClass(&class) ) {
841 		SDL_SetError("Couldn't register application class");
842 		return(-1);
843 	}
844 
845 #ifdef WM_MOUSELEAVE
846 	/* Get the version of TrackMouseEvent() we use */
847 	_TrackMouseEvent = NULL;
848 	handle = GetModuleHandle("USER32.DLL");
849 	if ( handle ) {
850 		_TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
851 	}
852 	if ( _TrackMouseEvent == NULL ) {
853 		_TrackMouseEvent = WIN_TrackMouseEvent;
854 	}
855 #endif /* WM_MOUSELEAVE */
856 
857 #ifndef NO_GETKEYBOARDSTATE
858 	/* Initialise variables for SDL_ToUnicode() */
859 	codepage = GetCodePage();
860 	SDL_ToUnicode = Is9xME() ? ToUnicode9xME : ToUnicode;
861 #endif
862 
863 	app_registered = 1;
864 	return(0);
865 }
866 
867 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
SDL_UnregisterApp()868 void SDL_UnregisterApp()
869 {
870 	WNDCLASS class;
871 
872 	/* SDL_RegisterApp might not have been called before */
873 	if ( !app_registered ) {
874 		return;
875 	}
876 	--app_registered;
877 	if ( app_registered == 0 ) {
878 		/* Check for any registered window classes. */
879 		if ( GetClassInfo(SDL_Instance, SDL_Appname, &class) ) {
880 			UnregisterClass(SDL_Appname, SDL_Instance);
881 		}
882 		SDL_free(SDL_Appname);
883 		SDL_Appname = NULL;
884 	}
885 }
886 
887 #ifndef NO_GETKEYBOARDSTATE
888 /* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */
889 
Is9xME()890 static int Is9xME()
891 {
892 	OSVERSIONINFO   info;
893 
894 	SDL_memset(&info, 0, sizeof(info));
895 	info.dwOSVersionInfoSize = sizeof(info);
896 	if (!GetVersionEx(&info)) {
897 		return 0;
898 	}
899 	return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
900 }
901 
GetCodePage()902 static int GetCodePage()
903 {
904 	char	buff[8];
905 	int	lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT);
906 	int	cp = GetACP();
907 
908 	if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) {
909 		cp = SDL_atoi(buff);
910 	}
911 	return cp;
912 }
913 
ToUnicode9xME(UINT vkey,UINT scancode,PBYTE keystate,LPWSTR wchars,int wsize,UINT flags)914 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, PBYTE keystate, LPWSTR wchars, int wsize, UINT flags)
915 {
916 	BYTE	chars[2];
917 
918 	if (ToAsciiEx(vkey, scancode, keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) {
919 		return MultiByteToWideChar(codepage, 0, chars, 1, wchars, wsize);
920 	}
921 	return 0;
922 }
923 
924 #endif /* !NO_GETKEYBOARDSTATE */
925