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