Home | History | Annotate | Download | only in wincommon
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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 (at) 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 	union { RECT rect; POINT pt; } rectpt;  /* prevent type-punning issue. */
    224 	POINT pt;
    225 
    226 	GetClientRect(hWnd, &rectpt.rect);
    227 	MapWindowPoints(hWnd, NULL, &rectpt.pt, 2);
    228 	GetCursorPos(&pt);
    229 	if ( !PtInRect(&rectpt.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 int sysevents_mouse_pressed = 0;
    247 
    248 /* The main Win32 event handler
    249 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it
    250 */
    251 LRESULT CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    252 {
    253 	SDL_VideoDevice *this = current_video;
    254 #ifdef WMMSG_DEBUG
    255 	fprintf(stderr, "Received windows message:  ");
    256 	if ( msg > MAX_WMMSG ) {
    257 		fprintf(stderr, "%d", msg);
    258 	} else {
    259 		fprintf(stderr, "%s", wmtab[msg]);
    260 	}
    261 	fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
    262 #endif
    263 	switch (msg) {
    264 
    265 		case WM_ACTIVATE: {
    266 			SDL_VideoDevice *this = current_video;
    267 			BOOL active, minimized;
    268 			Uint8 appstate;
    269 
    270 			minimized = HIWORD(wParam);
    271 			active = (LOWORD(wParam) != WA_INACTIVE) && !minimized;
    272 			if ( active ) {
    273 				/* Gain the following states */
    274 				appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
    275 				if ( !(SDL_GetAppState() & SDL_APPINPUTFOCUS) ) {
    276 					if ( this->input_grab != SDL_GRAB_OFF ) {
    277 						WIN_GrabInput(this, SDL_GRAB_ON);
    278 					}
    279 					if ( ! DDRAW_FULLSCREEN() ) {
    280 						DIB_SwapGamma(this);
    281 					}
    282 					if ( WINDIB_FULLSCREEN() ) {
    283 						SDL_RestoreGameMode();
    284 					}
    285 				}
    286 #if defined(_WIN32_WCE)
    287 				if ( WINDIB_FULLSCREEN() ) {
    288 					LoadAygshell();
    289 					if( SHFullScreen )
    290 						SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON);
    291 					else
    292 						ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE);
    293 				}
    294 #endif
    295 				posted = SDL_PrivateAppActive(1, appstate);
    296 			} else {
    297 				/* Lose the following states */
    298 				appstate = SDL_APPINPUTFOCUS;
    299 				if ( minimized ) {
    300 					appstate |= SDL_APPACTIVE;
    301 				}
    302 
    303 				if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
    304 					if ( this->input_grab != SDL_GRAB_OFF ) {
    305 						WIN_GrabInput(this, SDL_GRAB_OFF);
    306 					}
    307 					if ( ! DDRAW_FULLSCREEN() ) {
    308 						DIB_SwapGamma(this);
    309 					}
    310 					if ( WINDIB_FULLSCREEN() ) {
    311 						appstate |= SDL_APPMOUSEFOCUS;
    312 						SDL_RestoreDesktopMode();
    313 						/* A fullscreen app gets hidden but will not get a minimize event */
    314 						appstate |= (SDL_APPACTIVE | SDL_APPMOUSEFOCUS);
    315 #if defined(_WIN32_WCE)
    316 						LoadAygshell();
    317 						if( SHFullScreen )
    318 							SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON);
    319 						else
    320 							ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW);
    321 #endif
    322 					}
    323 				}
    324 				posted = SDL_PrivateAppActive(0, appstate);
    325 			}
    326 			WIN_Activate(this, active, minimized);
    327 			return(0);
    328 		}
    329 		break;
    330 
    331 		case WM_MOUSEMOVE: {
    332 
    333 #ifdef WM_MOUSELEAVE
    334 			if ( SDL_VideoSurface ) {
    335 				/* mouse has entered the window */
    336 
    337 				if ( !(SDL_GetAppState() & SDL_APPMOUSEFOCUS) ) {
    338 					TRACKMOUSEEVENT tme;
    339 
    340 					tme.cbSize = sizeof(tme);
    341 					tme.dwFlags = TME_LEAVE;
    342 					tme.hwndTrack = SDL_Window;
    343 					_TrackMouseEvent(&tme);
    344 				}
    345 			}
    346 #endif /* WM_MOUSELEAVE */
    347 
    348 			/* Mouse motion is handled in DIB_PumpEvents or
    349 			 * DX5_PumpEvents, depending on the video driver
    350 			 * in use */
    351 
    352 			posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
    353 		}
    354 		return(0);
    355 
    356 #ifdef WM_MOUSELEAVE
    357 		case WM_MOUSELEAVE: {
    358 
    359 			if ( SDL_VideoSurface ) {
    360 				/* mouse has left the window */
    361 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
    362 			}
    363 		}
    364 		return(0);
    365 #endif /* WM_MOUSELEAVE */
    366 
    367 		case WM_LBUTTONDOWN:
    368 		case WM_LBUTTONUP:
    369 		case WM_MBUTTONDOWN:
    370 		case WM_MBUTTONUP:
    371 		case WM_RBUTTONDOWN:
    372 		case WM_RBUTTONUP:
    373 		case WM_XBUTTONDOWN:
    374 		case WM_XBUTTONUP: {
    375 			/* Mouse is handled by DirectInput when fullscreen */
    376 			if ( SDL_VideoSurface && ! DINPUT() ) {
    377 				WORD xbuttonval = 0;
    378 				Uint8 button, state;
    379                 int x, y;
    380 
    381 				/* DJM:
    382 				   We want the SDL window to take focus so that
    383 				   it acts like a normal windows "component"
    384 				   (e.g. gains keyboard focus on a mouse click).
    385 				 */
    386 				SetFocus(SDL_Window);
    387 
    388 				/* Figure out which button to use */
    389 				switch (msg) {
    390 					case WM_LBUTTONDOWN:
    391 						button = SDL_BUTTON_LEFT;
    392 						state = SDL_PRESSED;
    393 						break;
    394 					case WM_LBUTTONUP:
    395 						button = SDL_BUTTON_LEFT;
    396 						state = SDL_RELEASED;
    397 						break;
    398 					case WM_MBUTTONDOWN:
    399 						button = SDL_BUTTON_MIDDLE;
    400 						state = SDL_PRESSED;
    401 						break;
    402 					case WM_MBUTTONUP:
    403 						button = SDL_BUTTON_MIDDLE;
    404 						state = SDL_RELEASED;
    405 						break;
    406 					case WM_RBUTTONDOWN:
    407 						button = SDL_BUTTON_RIGHT;
    408 						state = SDL_PRESSED;
    409 						break;
    410 					case WM_RBUTTONUP:
    411 						button = SDL_BUTTON_RIGHT;
    412 						state = SDL_RELEASED;
    413 						break;
    414 					case WM_XBUTTONDOWN:
    415 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
    416 						button = SDL_BUTTON_X1 + xbuttonval - 1;
    417 						state = SDL_PRESSED;
    418 						break;
    419 					case WM_XBUTTONUP:
    420 						xbuttonval = GET_XBUTTON_WPARAM(wParam);
    421 						button = SDL_BUTTON_X1 + xbuttonval - 1;
    422 						state = SDL_RELEASED;
    423 						break;
    424 					default:
    425 						/* Eh? Unknown button? */
    426 						return(0);
    427 				}
    428 				if ( state == SDL_PRESSED ) {
    429 					/* Grab mouse so we get up events */
    430 					if ( ++sysevents_mouse_pressed > 0 ) {
    431 						SetCapture(hwnd);
    432 					}
    433 				} else {
    434 					/* Release mouse after all up events */
    435 					if ( --sysevents_mouse_pressed <= 0 ) {
    436 						ReleaseCapture();
    437 						sysevents_mouse_pressed = 0;
    438 					}
    439 				}
    440 				if ( mouse_relative ) {
    441 				/*	RJR: March 28, 2000
    442 					report internal mouse position if in relative mode */
    443 					x = 0; y = 0;
    444 				} else {
    445 					x = (Sint16)LOWORD(lParam);
    446 					y = (Sint16)HIWORD(lParam);
    447 #ifdef _WIN32_WCE
    448 					if (SDL_VideoSurface)
    449 						GapiTransform(this->hidden->userOrientation,
    450 this->hidden->hiresFix, &x, &y);
    451 #endif
    452 				}
    453 				posted = SDL_PrivateMouseButton(
    454 							state, button, x, y);
    455 
    456 				/*
    457 				 * MSDN says:
    458 				 *  "Unlike the WM_LBUTTONUP, WM_MBUTTONUP, and WM_RBUTTONUP
    459 				 *   messages, an application should return TRUE from [an
    460 				 *   XBUTTON message] if it processes it. Doing so will allow
    461 				 *   software that simulates this message on Microsoft Windows
    462 				 *   systems earlier than Windows 2000 to determine whether
    463 				 *   the window procedure processed the message or called
    464 				 *   DefWindowProc to process it.
    465 				 */
    466 				if (xbuttonval > 0)
    467 					return(TRUE);
    468 			}
    469 		}
    470 		return(0);
    471 
    472 
    473 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
    474 		case WM_MOUSEWHEEL:
    475 			if ( SDL_VideoSurface && ! DINPUT() ) {
    476 				int move = (short)HIWORD(wParam);
    477 				if ( move ) {
    478 					Uint8 button;
    479 					if ( move > 0 )
    480 						button = SDL_BUTTON_WHEELUP;
    481 					else
    482 						button = SDL_BUTTON_WHEELDOWN;
    483 					posted = SDL_PrivateMouseButton(
    484 						SDL_PRESSED, button, 0, 0);
    485 					posted |= SDL_PrivateMouseButton(
    486 						SDL_RELEASED, button, 0, 0);
    487 				}
    488 			}
    489 			return(0);
    490 #endif
    491 
    492 #ifdef WM_GETMINMAXINFO
    493 		/* This message is sent as a way for us to "check" the values
    494 		 * of a position change.  If we don't like it, we can adjust
    495 		 * the values before they are changed.
    496 		 */
    497 		case WM_GETMINMAXINFO: {
    498 			MINMAXINFO *info;
    499 			RECT        size;
    500 			int x, y;
    501 			int style;
    502 			int width;
    503 			int height;
    504 
    505 			/* We don't want to clobber an internal resize */
    506 			if ( SDL_resizing )
    507 				return(0);
    508 
    509 			/* We allow resizing with the SDL_RESIZABLE flag */
    510 			if ( SDL_PublicSurface &&
    511 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
    512 				return(0);
    513 			}
    514 
    515 			/* Get the current position of our window */
    516 			GetWindowRect(SDL_Window, &size);
    517 			x = size.left;
    518 			y = size.top;
    519 
    520 			/* Calculate current width and height of our window */
    521 			size.top = 0;
    522 			size.left = 0;
    523 			if ( SDL_PublicSurface != NULL ) {
    524 				size.bottom = SDL_PublicSurface->h;
    525 				size.right = SDL_PublicSurface->w;
    526 			} else {
    527 				size.bottom = 0;
    528 				size.right = 0;
    529 			}
    530 
    531 			/* DJM - according to the docs for GetMenu(), the
    532 			   return value is undefined if hwnd is a child window.
    533 			   Aparently it's too difficult for MS to check
    534 			   inside their function, so I have to do it here.
    535           		 */
    536          		style = GetWindowLong(hwnd, GWL_STYLE);
    537          		AdjustWindowRect(
    538 				&size,
    539 				style,
    540             			style & WS_CHILDWINDOW ? FALSE
    541 						       : GetMenu(hwnd) != NULL);
    542 
    543 			width = size.right - size.left;
    544 			height = size.bottom - size.top;
    545 
    546 			/* Fix our size to the current size */
    547 			info = (MINMAXINFO *)lParam;
    548 			info->ptMaxSize.x = width;
    549 			info->ptMaxSize.y = height;
    550 			info->ptMaxPosition.x = x;
    551 			info->ptMaxPosition.y = y;
    552 			info->ptMinTrackSize.x = width;
    553 			info->ptMinTrackSize.y = height;
    554 			info->ptMaxTrackSize.x = width;
    555 			info->ptMaxTrackSize.y = height;
    556 		}
    557 		return(0);
    558 #endif /* WM_GETMINMAXINFO */
    559 
    560 		case WM_WINDOWPOSCHANGING: {
    561 			WINDOWPOS *windowpos = (WINDOWPOS*)lParam;
    562 
    563 			/* When menu is at the side or top, Windows likes
    564 			   to try to reposition the fullscreen window when
    565 			   changing video modes.
    566 			 */
    567 			if ( !SDL_resizing &&
    568 			     SDL_PublicSurface &&
    569 			     (SDL_PublicSurface->flags & SDL_FULLSCREEN) ) {
    570 				windowpos->x = 0;
    571 				windowpos->y = 0;
    572 			}
    573 		}
    574 		return(0);
    575 
    576 		case WM_WINDOWPOSCHANGED: {
    577 			SDL_VideoDevice *this = current_video;
    578 			POINT pt;
    579 			int w, h;
    580 
    581 			GetClientRect(SDL_Window, &SDL_bounds);
    582 
    583 			/* avoiding type-punning here... */
    584 			pt.x = SDL_bounds.left;
    585 			pt.y = SDL_bounds.top;
    586 			ClientToScreen(SDL_Window, &pt);
    587 			SDL_bounds.left = pt.x;
    588 			SDL_bounds.top = pt.y;
    589 
    590 			pt.x = SDL_bounds.right;
    591 			pt.y = SDL_bounds.bottom;
    592 			ClientToScreen(SDL_Window, &pt);
    593 			SDL_bounds.right = pt.x;
    594 			SDL_bounds.bottom = pt.y;
    595 
    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 #ifndef _WIN64
    673 			codepage = GetCodePage();
    674 #endif
    675 		return(TRUE);
    676 #endif
    677 
    678 		default: {
    679 			/* Special handling by the video driver */
    680 			if (HandleMessage) {
    681 				return(HandleMessage(current_video,
    682 			                     hwnd, msg, wParam, lParam));
    683 			}
    684 		}
    685 		break;
    686 	}
    687 	return(DefWindowProc(hwnd, msg, wParam, lParam));
    688 }
    689 
    690 /* Allow the application handle to be stored and retrieved later */
    691 static void *SDL_handle = NULL;
    692 
    693 void SDL_SetModuleHandle(void *handle)
    694 {
    695 	SDL_handle = handle;
    696 }
    697 void *SDL_GetModuleHandle(void)
    698 {
    699 	void *handle;
    700 
    701 	if ( SDL_handle ) {
    702 		handle = SDL_handle;
    703 	} else {
    704 		handle = GetModuleHandle(NULL);
    705 	}
    706 	return(handle);
    707 }
    708 
    709 /* This allows the SDL_WINDOWID hack */
    710 BOOL SDL_windowid = FALSE;
    711 
    712 static int app_registered = 0;
    713 
    714 /* Register the class for this application -- exported for winmain.c */
    715 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
    716 {
    717 	WNDCLASS class;
    718 #ifdef WM_MOUSELEAVE
    719 	HMODULE handle;
    720 #endif
    721 
    722 	/* Only do this once... */
    723 	if ( app_registered ) {
    724 		++app_registered;
    725 		return(0);
    726 	}
    727 
    728 #ifndef CS_BYTEALIGNCLIENT
    729 #define CS_BYTEALIGNCLIENT	0
    730 #endif
    731 	if ( ! name && ! SDL_Appname ) {
    732 		name = "SDL_app";
    733 		SDL_Appstyle = CS_BYTEALIGNCLIENT;
    734 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
    735 	}
    736 
    737 	if ( name ) {
    738 #ifdef _WIN32_WCE
    739 		/* WinCE uses the UNICODE version */
    740 		SDL_Appname = SDL_iconv_utf8_ucs2(name);
    741 #else
    742 		SDL_Appname = SDL_iconv_utf8_locale(name);
    743 #endif /* _WIN32_WCE */
    744 		SDL_Appstyle = style;
    745 		SDL_Instance = hInst ? hInst : SDL_GetModuleHandle();
    746 	}
    747 
    748 	/* Register the application class */
    749 	class.hCursor		= NULL;
    750 	class.hIcon		= LoadImage(SDL_Instance, SDL_Appname,
    751 				            IMAGE_ICON,
    752 	                                    0, 0, LR_DEFAULTCOLOR);
    753 	class.lpszMenuName	= NULL;
    754 	class.lpszClassName	= SDL_Appname;
    755 	class.hbrBackground	= NULL;
    756 	class.hInstance		= SDL_Instance;
    757 	class.style		= SDL_Appstyle;
    758 #if SDL_VIDEO_OPENGL
    759 	class.style		|= CS_OWNDC;
    760 #endif
    761 	class.lpfnWndProc	= WinMessage;
    762 	class.cbWndExtra	= 0;
    763 	class.cbClsExtra	= 0;
    764 	if ( ! RegisterClass(&class) ) {
    765 		SDL_SetError("Couldn't register application class");
    766 		return(-1);
    767 	}
    768 
    769 #ifdef WM_MOUSELEAVE
    770 	/* Get the version of TrackMouseEvent() we use */
    771 	_TrackMouseEvent = NULL;
    772 	handle = GetModuleHandle("USER32.DLL");
    773 	if ( handle ) {
    774 		_TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
    775 	}
    776 	if ( _TrackMouseEvent == NULL ) {
    777 		_TrackMouseEvent = WIN_TrackMouseEvent;
    778 	}
    779 #endif /* WM_MOUSELEAVE */
    780 
    781 #ifndef NO_GETKEYBOARDSTATE
    782 #ifndef _WIN64
    783 	/* Initialise variables for SDL_ToUnicode() */
    784 	codepage = GetCodePage();
    785 
    786 	/* Cygwin headers don't match windows.h, so we have to cast around a
    787 	   const issue here... */
    788 	SDL_ToUnicode = Is9xME() ? ToUnicode9xME : (ToUnicodeFN) ToUnicode;
    789 #endif
    790 #endif /* NO_GETKEYBOARDSTATE */
    791 
    792 	app_registered = 1;
    793 	return(0);
    794 }
    795 
    796 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
    797 void SDL_UnregisterApp()
    798 {
    799 	WNDCLASS class;
    800 
    801 	/* SDL_RegisterApp might not have been called before */
    802 	if ( !app_registered ) {
    803 		return;
    804 	}
    805 	--app_registered;
    806 	if ( app_registered == 0 ) {
    807 		/* Check for any registered window classes. */
    808 		if ( GetClassInfo(SDL_Instance, SDL_Appname, &class) ) {
    809 			UnregisterClass(SDL_Appname, SDL_Instance);
    810 		}
    811 		SDL_free(SDL_Appname);
    812 		SDL_Appname = NULL;
    813 	}
    814 }
    815 
    816 #ifndef NO_GETKEYBOARDSTATE
    817 #ifndef _WIN64
    818 /* JFP: Implementation of ToUnicode() that works on 9x/ME/2K/XP */
    819 
    820 static int Is9xME()
    821 {
    822 	OSVERSIONINFO   info;
    823 
    824 	SDL_memset(&info, 0, sizeof(info));
    825 	info.dwOSVersionInfoSize = sizeof(info);
    826 	if (!GetVersionEx(&info)) {
    827 		return 0;
    828 	}
    829 	return (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
    830 }
    831 
    832 static int GetCodePage()
    833 {
    834 	char	buff[8];
    835 	int	lcid = MAKELCID(LOWORD(GetKeyboardLayout(0)), SORT_DEFAULT);
    836 	int	cp = GetACP();
    837 
    838 	if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buff, sizeof(buff))) {
    839 		cp = SDL_atoi(buff);
    840 	}
    841 	return cp;
    842 }
    843 
    844 static int WINAPI ToUnicode9xME(UINT vkey, UINT scancode, const BYTE *keystate, LPWSTR wchars, int wsize, UINT flags)
    845 {
    846 	BYTE	chars[2];
    847 
    848 	/* arg #3 should be const BYTE *, but cygwin lists it as PBYTE. */
    849 	if (ToAsciiEx(vkey, scancode, (PBYTE) keystate, (WORD*)chars, 0, GetKeyboardLayout(0)) == 1) {
    850 		return MultiByteToWideChar(codepage, 0, (LPCSTR) chars, 1, wchars, wsize);
    851 	}
    852 	return 0;
    853 }
    854 #endif
    855 #endif /* !NO_GETKEYBOARDSTATE */
    856