src/video/wincommon/SDL_sysevents.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 27 Sep 2005 09:00:42 +0000
changeset 1145 d31afac94eff
parent 833 31fa08b36380
child 1150 7d8e1925f35b
permissions -rw-r--r--
Patch from Martin Lange (mala-sdl at hotmail.com) to unregister SDL's win32
windowclass when shutting down the video subsystem...this allows you to
safely unload/reload the SDL shared library on Windows between
initializations.

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