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