src/video/wincommon/SDL_sysevents.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 06 Jan 2006 13:20:10 +0000
changeset 1234 73676c1f56ee
parent 1152 51a8702d8ecd
child 1251 86d0d01290ea
permissions -rw-r--r--
For sanity's sake, removed the '&' when passing copy_row array to asm.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 #include <stdlib.h>
    29 #include <stdio.h>
    30 #include <windows.h>
    31 
    32 #include "SDL_getenv.h"
    33 #include "SDL_events.h"
    34 #include "SDL_video.h"
    35 #include "SDL_error.h"
    36 #include "SDL_syswm.h"
    37 #include "SDL_sysevents.h"
    38 #include "SDL_events_c.h"
    39 #include "SDL_sysvideo.h"
    40 #include "SDL_lowvideo.h"
    41 #include "SDL_syswm_c.h"
    42 #include "SDL_main.h"
    43 #include "SDL_loadso.h"
    44 
    45 #ifdef WMMSG_DEBUG
    46 #include "wmmsg.h"
    47 #endif
    48 
    49 #ifdef _WIN32_WCE
    50 #define NO_GETKEYBOARDSTATE
    51 #define NO_CHANGEDISPLAYSETTINGS
    52 #endif
    53 
    54 /* The window we use for everything... */
    55 #ifdef _WIN32_WCE
    56 LPWSTR SDL_Appname = NULL;
    57 #else
    58 LPSTR SDL_Appname = NULL;
    59 #endif
    60 HINSTANCE SDL_Instance = NULL;
    61 HWND SDL_Window = NULL;
    62 RECT SDL_bounds = {0, 0, 0, 0};
    63 int SDL_windowX = 0;
    64 int SDL_windowY = 0;
    65 int SDL_resizing = 0;
    66 int mouse_relative = 0;
    67 int posted = 0;
    68 #ifndef NO_CHANGEDISPLAYSETTINGS
    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 #if defined(_WIN32_WCE)
    82 
    83 // dynamically load aygshell dll because we want SDL to work on HPC and be300
    84 HINSTANCE aygshell = NULL;
    85 BOOL (WINAPI *SHFullScreen)(HWND hwndRequester, DWORD dwState) = 0;
    86 
    87 #define SHFS_SHOWTASKBAR            0x0001
    88 #define SHFS_HIDETASKBAR            0x0002
    89 #define SHFS_SHOWSIPBUTTON          0x0004
    90 #define SHFS_HIDESIPBUTTON          0x0008
    91 #define SHFS_SHOWSTARTICON          0x0010
    92 #define SHFS_HIDESTARTICON          0x0020
    93 
    94 static void LoadAygshell(void)
    95 {
    96 	if( !aygshell )
    97 		 aygshell = SDL_LoadObject("aygshell.dll");
    98 	if( aygshell )
    99 	{
   100 		SHFullScreen = (int (WINAPI *)(struct HWND__ *,unsigned long)) SDL_LoadFunction(aygshell, "SHFullScreen");
   101 	}
   102 }
   103 
   104 #endif
   105 
   106 static void SDL_RestoreGameMode(void)
   107 {
   108 #ifndef NO_CHANGEDISPLAYSETTINGS
   109 	ShowWindow(SDL_Window, SW_RESTORE);
   110 	ChangeDisplaySettings(&SDL_fullscreen_mode, CDS_FULLSCREEN);
   111 #endif
   112 }
   113 static void SDL_RestoreDesktopMode(void)
   114 {
   115 #ifndef NO_CHANGEDISPLAYSETTINGS
   116 	ShowWindow(SDL_Window, SW_MINIMIZE);
   117 	ChangeDisplaySettings(NULL, 0);
   118 #endif
   119 }
   120 
   121 #ifdef WM_MOUSELEAVE
   122 /* 
   123    Special code to handle mouse leave events - this sucks...
   124    http://support.microsoft.com/support/kb/articles/q183/1/07.asp
   125 
   126    TrackMouseEvent() is only available on Win98 and WinNT.
   127    _TrackMouseEvent() is available on Win95, but isn't yet in the mingw32
   128    development environment, and only works on systems that have had IE 3.0
   129    or newer installed on them (which is not the case with the base Win95).
   130    Therefore, we implement our own version of _TrackMouseEvent() which
   131    uses our own implementation if TrackMouseEvent() is not available.
   132 */
   133 static BOOL (WINAPI *_TrackMouseEvent)(TRACKMOUSEEVENT *ptme) = NULL;
   134 
   135 static VOID CALLBACK
   136 TrackMouseTimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime)
   137 {
   138 	RECT rect;
   139 	POINT pt;
   140 
   141 	GetClientRect(hWnd, &rect);
   142 	MapWindowPoints(hWnd, NULL, (LPPOINT)&rect, 2);
   143 	GetCursorPos(&pt);
   144 	if ( !PtInRect(&rect, pt) || (WindowFromPoint(pt) != hWnd) ) {
   145 		if ( !KillTimer(hWnd, idEvent) ) {
   146 			/* Error killing the timer! */
   147 		}
   148 		PostMessage(hWnd, WM_MOUSELEAVE, 0, 0);
   149 	}
   150 }
   151 static BOOL WINAPI WIN_TrackMouseEvent(TRACKMOUSEEVENT *ptme)
   152 {
   153 	if ( ptme->dwFlags == TME_LEAVE ) {
   154 		return SetTimer(ptme->hwndTrack, ptme->dwFlags, 100,
   155 		                (TIMERPROC)TrackMouseTimerProc);
   156 	}
   157 	return FALSE;
   158 }
   159 #endif /* WM_MOUSELEAVE */
   160 
   161 /* Function to retrieve the current keyboard modifiers */
   162 static void WIN_GetKeyboardState(void)
   163 {
   164 #ifndef NO_GETKEYBOARDSTATE
   165 	SDLMod state;
   166 	BYTE keyboard[256];
   167 	Uint8 *kstate = SDL_GetKeyState(NULL);
   168 
   169 	state = KMOD_NONE;
   170 	if ( GetKeyboardState(keyboard) ) {
   171 		if ( keyboard[VK_LSHIFT] & 0x80) {
   172 			state |= KMOD_LSHIFT;
   173 		}
   174 		if ( keyboard[VK_RSHIFT] & 0x80) {
   175 			state |= KMOD_RSHIFT;
   176 		}
   177 		if ( keyboard[VK_LCONTROL] & 0x80) {
   178 			state |= KMOD_LCTRL;
   179 		}
   180 		if ( keyboard[VK_RCONTROL] & 0x80) {
   181 			state |= KMOD_RCTRL;
   182 		}
   183 		if ( keyboard[VK_LMENU] & 0x80) {
   184 			state |= KMOD_LALT;
   185 		}
   186 		if ( keyboard[VK_RMENU] & 0x80) {
   187 			state |= KMOD_RALT;
   188 		}
   189 		if ( keyboard[VK_NUMLOCK] & 0x01) {
   190 			state |= KMOD_NUM;
   191 			kstate[SDLK_NUMLOCK] = SDL_PRESSED;
   192 		}
   193 		if ( keyboard[VK_CAPITAL] & 0x01) {
   194 			state |= KMOD_CAPS;
   195 			kstate[SDLK_CAPSLOCK] = SDL_PRESSED;
   196 		}
   197 	}
   198 	SDL_SetModState(state);
   199 #endif /* !NO_GETKEYBOARDSTATE */
   200 }
   201 
   202 /* The main Win32 event handler
   203 DJM: This is no longer static as (DX5/DIB)_CreateWindow needs it
   204 */
   205 LONG CALLBACK WinMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   206 {
   207 	SDL_VideoDevice *this = current_video;
   208 	static int mouse_pressed = 0;
   209 	static int in_window = 0;
   210 #ifdef WMMSG_DEBUG
   211 	fprintf(stderr, "Received windows message:  ");
   212 	if ( msg > MAX_WMMSG ) {
   213 		fprintf(stderr, "%d", msg);
   214 	} else {
   215 		fprintf(stderr, "%s", wmtab[msg]);
   216 	}
   217 	fprintf(stderr, " -- 0x%X, 0x%X\n", wParam, lParam);
   218 #endif
   219 	switch (msg) {
   220 
   221 		case WM_ACTIVATE: {
   222 			SDL_VideoDevice *this = current_video;
   223 			BOOL minimized;
   224 			Uint8 appstate;
   225 
   226 			minimized = HIWORD(wParam);
   227 			if ( !minimized && (LOWORD(wParam) != WA_INACTIVE) ) {
   228 				/* Gain the following states */
   229 				appstate = SDL_APPACTIVE|SDL_APPINPUTFOCUS;
   230 				if ( this->input_grab != SDL_GRAB_OFF ) {
   231 					WIN_GrabInput(this, SDL_GRAB_ON);
   232 				}
   233 				if ( !(SDL_GetAppState()&SDL_APPINPUTFOCUS) ) {
   234 					if ( ! DDRAW_FULLSCREEN() ) {
   235 						DIB_SwapGamma(this);
   236 					}
   237 					if ( WINDIB_FULLSCREEN() ) {
   238 						SDL_RestoreGameMode();
   239 					}
   240 				}
   241 #if defined(_WIN32_WCE)
   242 			if ( WINDIB_FULLSCREEN() )
   243 			{
   244 						LoadAygshell();
   245 						if( aygshell ) 
   246 							SHFullScreen(SDL_Window, SHFS_HIDESTARTICON|SHFS_HIDETASKBAR|SHFS_HIDESIPBUTTON);
   247 						else
   248 							ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_HIDE);
   249 
   250 			}
   251 #endif
   252 
   253 				posted = SDL_PrivateAppActive(1, appstate);
   254 				WIN_GetKeyboardState();
   255 			} else {
   256 				/* Lose the following states */
   257 				appstate = SDL_APPINPUTFOCUS;
   258 				if ( minimized ) {
   259 					appstate |= SDL_APPACTIVE;
   260 				}
   261 				if ( this->input_grab != SDL_GRAB_OFF ) {
   262 					WIN_GrabInput(this, SDL_GRAB_OFF);
   263 				}
   264 				if ( SDL_GetAppState() & SDL_APPINPUTFOCUS ) {
   265 					if ( ! DDRAW_FULLSCREEN() ) {
   266 						DIB_SwapGamma(this);
   267 					}
   268 					if ( WINDIB_FULLSCREEN() ) {
   269 						SDL_RestoreDesktopMode();
   270 #if defined(_WIN32_WCE)
   271 						LoadAygshell();
   272 						if( aygshell ) 
   273 							SHFullScreen(SDL_Window, SHFS_SHOWSTARTICON|SHFS_SHOWTASKBAR|SHFS_SHOWSIPBUTTON);
   274 						else
   275 							ShowWindow(FindWindow(TEXT("HHTaskBar"),NULL),SW_SHOW);
   276 
   277 #endif
   278 					}
   279 				}
   280 				posted = SDL_PrivateAppActive(0, appstate);
   281 			}
   282 			return(0);
   283 		}
   284 		break;
   285 
   286 		case WM_MOUSEMOVE: {
   287 			
   288 			/* Mouse is handled by DirectInput when fullscreen */
   289 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   290 				Sint16 x, y;
   291 
   292 				/* mouse has entered the window */
   293 				if ( ! in_window ) {
   294 #ifdef WM_MOUSELEAVE
   295 					TRACKMOUSEEVENT tme;
   296 
   297 					tme.cbSize = sizeof(tme);
   298 					tme.dwFlags = TME_LEAVE;
   299 					tme.hwndTrack = SDL_Window;
   300 					_TrackMouseEvent(&tme);
   301 #endif /* WM_MOUSELEAVE */
   302 					in_window = TRUE;
   303 
   304 					posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   305 				}
   306 
   307 				/* mouse has moved within the window */
   308 				x = LOWORD(lParam);
   309 				y = HIWORD(lParam);
   310 				if ( mouse_relative ) {
   311 					POINT center;
   312 					center.x = (SDL_VideoSurface->w/2);
   313 					center.y = (SDL_VideoSurface->h/2);
   314 					x -= (Sint16)center.x;
   315 					y -= (Sint16)center.y;
   316 					if ( x || y ) {
   317 						ClientToScreen(SDL_Window, &center);
   318 						SetCursorPos(center.x, center.y);
   319 						posted = SDL_PrivateMouseMotion(0, 1, x, y);
   320 					}
   321 				} else {
   322 					posted = SDL_PrivateMouseMotion(0, 0, x, y);
   323 				}
   324 			}
   325 		}
   326 		return(0);
   327 
   328 #ifdef WM_MOUSELEAVE
   329 		case WM_MOUSELEAVE: {
   330 
   331 			/* Mouse is handled by DirectInput when fullscreen */
   332 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   333 				/* mouse has left the window */
   334 				/* or */
   335 				/* Elvis has left the building! */
   336 				posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   337 			}
   338 			in_window = FALSE;
   339 		}
   340 		return(0);
   341 #endif /* WM_MOUSELEAVE */
   342 
   343 		case WM_LBUTTONDOWN:
   344 		case WM_LBUTTONUP:
   345 		case WM_MBUTTONDOWN:
   346 		case WM_MBUTTONUP:
   347 		case WM_RBUTTONDOWN:
   348 		case WM_RBUTTONUP: {
   349 			/* Mouse is handled by DirectInput when fullscreen */
   350 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   351 				Sint16 x, y;
   352 				Uint8 button, state;
   353 
   354 				/* DJM:
   355 				   We want the SDL window to take focus so that
   356 				   it acts like a normal windows "component"
   357 				   (e.g. gains keyboard focus on a mouse click).
   358 				 */
   359 				SetFocus(SDL_Window);
   360 
   361 				/* Figure out which button to use */
   362 				switch (msg) {
   363 					case WM_LBUTTONDOWN:
   364 						button = SDL_BUTTON_LEFT;
   365 						state = SDL_PRESSED;
   366 						break;
   367 					case WM_LBUTTONUP:
   368 						button = SDL_BUTTON_LEFT;
   369 						state = SDL_RELEASED;
   370 						break;
   371 					case WM_MBUTTONDOWN:
   372 						button = SDL_BUTTON_MIDDLE;
   373 						state = SDL_PRESSED;
   374 						break;
   375 					case WM_MBUTTONUP:
   376 						button = SDL_BUTTON_MIDDLE;
   377 						state = SDL_RELEASED;
   378 						break;
   379 					case WM_RBUTTONDOWN:
   380 						button = SDL_BUTTON_RIGHT;
   381 						state = SDL_PRESSED;
   382 						break;
   383 					case WM_RBUTTONUP:
   384 						button = SDL_BUTTON_RIGHT;
   385 						state = SDL_RELEASED;
   386 						break;
   387 					default:
   388 						/* Eh? Unknown button? */
   389 						return(0);
   390 				}
   391 				if ( state == SDL_PRESSED ) {
   392 					/* Grab mouse so we get up events */
   393 					if ( ++mouse_pressed > 0 ) {
   394 						SetCapture(hwnd);
   395 					}
   396 				} else {
   397 					/* Release mouse after all up events */
   398 					if ( --mouse_pressed <= 0 ) {
   399 						ReleaseCapture();
   400 						mouse_pressed = 0;
   401 					}
   402 				}
   403 				if ( mouse_relative ) {
   404 				/*	RJR: March 28, 2000
   405 					report internal mouse position if in relative mode */
   406 					x = 0; y = 0;
   407 				} else {
   408 					x = (Sint16)LOWORD(lParam);
   409 					y = (Sint16)HIWORD(lParam);
   410 				}
   411 				posted = SDL_PrivateMouseButton(
   412 							state, button, x, y);
   413 			}
   414 		}
   415 		return(0);
   416 
   417 
   418 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)
   419 		case WM_MOUSEWHEEL: 
   420 			if ( SDL_VideoSurface && ! DINPUT_FULLSCREEN() ) {
   421 				int move = (short)HIWORD(wParam);
   422 				if ( move ) {
   423 					Uint8 button;
   424 					if ( move > 0 )
   425 						button = SDL_BUTTON_WHEELUP;
   426 					else
   427 						button = SDL_BUTTON_WHEELDOWN;
   428 					posted = SDL_PrivateMouseButton(
   429 						SDL_PRESSED, button, 0, 0);
   430 					posted |= SDL_PrivateMouseButton(
   431 						SDL_RELEASED, button, 0, 0);
   432 				}
   433 			}
   434 			return(0);
   435 #endif
   436 
   437 #ifdef WM_GETMINMAXINFO
   438 		/* This message is sent as a way for us to "check" the values
   439 		 * of a position change.  If we don't like it, we can adjust
   440 		 * the values before they are changed.
   441 		 */
   442 		case WM_GETMINMAXINFO: {
   443 			MINMAXINFO *info;
   444 			RECT        size;
   445 			int x, y;
   446 			int style;
   447 			int width;
   448 			int height;
   449 
   450 			/* We don't want to clobber an internal resize */
   451 			if ( SDL_resizing )
   452 				return(0);
   453 
   454 			/* We allow resizing with the SDL_RESIZABLE flag */
   455 			if ( SDL_PublicSurface &&
   456 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
   457 				return(0);
   458 			}
   459 
   460 			/* Get the current position of our window */
   461 			GetWindowRect(SDL_Window, &size);
   462 			x = size.left;
   463 			y = size.top;
   464 
   465 			/* Calculate current width and height of our window */
   466 			size.top = 0;
   467 			size.left = 0;
   468 			if ( SDL_PublicSurface != NULL ) {
   469 				size.bottom = SDL_PublicSurface->h;
   470 				size.right = SDL_PublicSurface->w;
   471 			} else {
   472 				size.bottom = 0;
   473 				size.right = 0;
   474 			}
   475 
   476 			/* DJM - according to the docs for GetMenu(), the
   477 			   return value is undefined if hwnd is a child window.
   478 			   Aparently it's too difficult for MS to check
   479 			   inside their function, so I have to do it here.
   480           		 */
   481          		style = GetWindowLong(hwnd, GWL_STYLE);
   482          		AdjustWindowRect(
   483 				&size,
   484 				style,
   485             			style & WS_CHILDWINDOW ? FALSE
   486 						       : GetMenu(hwnd) != NULL);
   487 
   488 			width = size.right - size.left;
   489 			height = size.bottom - size.top;
   490 
   491 			/* Fix our size to the current size */
   492 			info = (MINMAXINFO *)lParam;
   493 			info->ptMaxSize.x = width;
   494 			info->ptMaxSize.y = height;
   495 			info->ptMaxPosition.x = x;
   496 			info->ptMaxPosition.y = y;
   497 			info->ptMinTrackSize.x = width;
   498 			info->ptMinTrackSize.y = height;
   499 			info->ptMaxTrackSize.x = width;
   500 			info->ptMaxTrackSize.y = height;
   501 		}
   502 		return(0);
   503 #endif /* WM_GETMINMAXINFO */
   504 
   505 		case WM_WINDOWPOSCHANGED: {
   506 			SDL_VideoDevice *this = current_video;
   507 			int w, h;
   508 
   509 			GetClientRect(SDL_Window, &SDL_bounds);
   510 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds);
   511 			ClientToScreen(SDL_Window, (LPPOINT)&SDL_bounds+1);
   512 			if ( SDL_bounds.left || SDL_bounds.top ) {
   513 				SDL_windowX = SDL_bounds.left;
   514 				SDL_windowY = SDL_bounds.top;
   515 			}
   516 			w = SDL_bounds.right-SDL_bounds.left;
   517 			h = SDL_bounds.bottom-SDL_bounds.top;
   518 			if ( this->input_grab != SDL_GRAB_OFF ) {
   519 				ClipCursor(&SDL_bounds);
   520 			}
   521 			if ( SDL_PublicSurface && 
   522 				(SDL_PublicSurface->flags & SDL_RESIZABLE) ) {
   523 				SDL_PrivateResize(w, h);
   524 			}
   525 		}
   526 		break;
   527 
   528 		/* We need to set the cursor */
   529 		case WM_SETCURSOR: {
   530 			Uint16 hittest;
   531 
   532 			hittest = LOWORD(lParam);
   533 			if ( hittest == HTCLIENT ) {
   534 				SetCursor(SDL_hcursor);
   535 				return(TRUE);
   536 			}
   537 		}
   538 		break;
   539 
   540 		/* We are about to get palette focus! */
   541 		case WM_QUERYNEWPALETTE: {
   542 			WIN_RealizePalette(current_video);
   543 			return(TRUE);
   544 		}
   545 		break;
   546 
   547 		/* Another application changed the palette */
   548 		case WM_PALETTECHANGED: {
   549 			WIN_PaletteChanged(current_video, (HWND)wParam);
   550 		}
   551 		break;
   552 
   553 		/* We were occluded, refresh our display */
   554 		case WM_PAINT: {
   555 			HDC hdc;
   556 			PAINTSTRUCT ps;
   557 
   558 			hdc = BeginPaint(SDL_Window, &ps);
   559 			if ( current_video->screen &&
   560 			     !(current_video->screen->flags & SDL_OPENGL) ) {
   561 				WIN_WinPAINT(current_video, hdc);
   562 			}
   563 			EndPaint(SDL_Window, &ps);
   564 		}
   565 		return(0);
   566 
   567 		/* DJM: Send an expose event in this case */
   568 		case WM_ERASEBKGND: {
   569 			posted = SDL_PrivateExpose();
   570 		}
   571 		return(0);
   572 
   573 		case WM_CLOSE: {
   574 			if ( (posted = SDL_PrivateQuit()) )
   575 				PostQuitMessage(0);
   576 		}
   577 		return(0);
   578 
   579 		case WM_DESTROY: {
   580 			PostQuitMessage(0);
   581 		}
   582 		return(0);
   583 
   584 		default: {
   585 			/* Special handling by the video driver */
   586 			if (HandleMessage) {
   587 				return(HandleMessage(current_video,
   588 			                     hwnd, msg, wParam, lParam));
   589 			}
   590 		}
   591 		break;
   592 	}
   593 	return(DefWindowProc(hwnd, msg, wParam, lParam));
   594 }
   595 
   596 /* Allow the application handle to be stored and retrieved later */
   597 static void *SDL_handle = NULL;
   598 
   599 void SDL_SetModuleHandle(void *handle)
   600 {
   601 	SDL_handle = handle;
   602 }
   603 void *SDL_GetModuleHandle(void)
   604 {
   605 	void *handle;
   606 
   607 	if ( SDL_handle ) {
   608 		handle = SDL_handle;
   609 	} else {
   610 		handle = GetModuleHandle(NULL);
   611 	}
   612 	return(handle);
   613 }
   614 
   615 /* This allows the SDL_WINDOWID hack */
   616 const char *SDL_windowid = NULL;
   617 
   618 static int app_registered = 0;
   619 
   620 /* Register the class for this application -- exported for winmain.c */
   621 int SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   622 {
   623 	WNDCLASS class;
   624 #ifdef WM_MOUSELEAVE
   625 	HMODULE handle;
   626 #endif
   627 
   628 	/* Only do this once... */
   629 	if ( app_registered ) {
   630 		return(0);
   631 	}
   632 
   633 	/* This function needs to be passed the correct process handle
   634 	   by the application.
   635 	 */
   636 	if ( ! hInst ) {
   637 		hInst = SDL_GetModuleHandle();
   638 	}
   639 
   640 	/* Register the application class */
   641 	class.hCursor		= NULL;
   642 #ifdef _WIN32_WCE
   643 	{
   644 		/* WinCE uses the UNICODE version */
   645 		int nLen = strlen(name)+1;
   646 		SDL_Appname = malloc(nLen*2);
   647 		MultiByteToWideChar(CP_ACP, 0, name, -1, SDL_Appname, nLen);
   648 	}
   649 #else
   650 	{
   651 		int nLen = strlen(name)+1;
   652 		SDL_Appname = malloc(nLen);
   653 		strcpy(SDL_Appname, name);
   654 	}
   655 #endif /* _WIN32_WCE */
   656 	class.hIcon		= LoadImage(hInst, SDL_Appname, IMAGE_ICON,
   657 	                                    0, 0, LR_DEFAULTCOLOR);
   658 	class.lpszMenuName	= NULL;
   659 	class.lpszClassName	= SDL_Appname;
   660 	class.hbrBackground	= NULL;
   661 	class.hInstance		= hInst;
   662 	class.style		= style;
   663 #ifdef HAVE_OPENGL
   664 	class.style		|= CS_OWNDC;
   665 #endif
   666 	class.lpfnWndProc	= WinMessage;
   667 	class.cbWndExtra	= 0;
   668 	class.cbClsExtra	= 0;
   669 	if ( ! RegisterClass(&class) ) {
   670 		SDL_SetError("Couldn't register application class");
   671 		return(-1);
   672 	}
   673 	SDL_Instance = hInst;
   674 
   675 #ifdef WM_MOUSELEAVE
   676 	/* Get the version of TrackMouseEvent() we use */
   677 	_TrackMouseEvent = NULL;
   678 	handle = GetModuleHandle("USER32.DLL");
   679 	if ( handle ) {
   680 		_TrackMouseEvent = (BOOL (WINAPI *)(TRACKMOUSEEVENT *))GetProcAddress(handle, "TrackMouseEvent");
   681 	}
   682 	if ( _TrackMouseEvent == NULL ) {
   683 		_TrackMouseEvent = WIN_TrackMouseEvent;
   684 	}
   685 #endif /* WM_MOUSELEAVE */
   686 
   687 	/* Check for SDL_WINDOWID hack */
   688 	SDL_windowid = getenv("SDL_WINDOWID");
   689 
   690 	app_registered = 1;
   691 	return(0);
   692 }
   693 
   694 /*
   695  * Unregisters the windowclass registered in SDL_RegisterApp above.
   696  *  Called from DIB_VideoQuit and DX5_VideoQuit when
   697  *  SDL_QuitSubSystem(INIT_VIDEO) is called.
   698  */
   699 void SDL_UnregisterApp()
   700 {
   701 	WNDCLASS class;
   702 
   703 	/* SDL_RegisterApp might not have been called before */
   704 	if (app_registered) {
   705 		/* Check for any registered windowclasses. */
   706 		if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   707 			UnregisterClass(SDL_Appname, SDL_Instance);
   708 		}
   709 	}
   710 	app_registered = 0;
   711 }
   712