src/video/wincommon/SDL_sysevents.c
author Ryan C. Gordon
Thu, 13 Oct 2011 01:49:14 -0400
branchSDL-1.2
changeset 5983 1361a12b2e58
parent 5898 17c2babefa47
child 5988 bf927e528813
permissions -rw-r--r--
Don't bother with Win9x compatibility when building 64-bit binaries.

Fixes Bugzilla #1310.

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