src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 01 Feb 2011 21:23:43 -0800
changeset 5149 be02be2ea897
parent 5139 57851a238c8f
child 5262 b530ef003506
permissions -rw-r--r--
Making the API simpler, removed support for palettized video modes and textures.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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 
    23 #include "SDL_config.h"
    24 
    25 #include "SDL_windowsvideo.h"
    26 #include "SDL_windowsshape.h"
    27 #include "SDL_syswm.h"
    28 #include "SDL_vkeys.h"
    29 #include "../../events/SDL_events_c.h"
    30 #include "../../events/SDL_touch_c.h"
    31 
    32 
    33 
    34 /*#define WMMSG_DEBUG*/
    35 #ifdef WMMSG_DEBUG
    36 #include <stdio.h>	
    37 #include "wmmsg.h"
    38 #endif
    39 
    40 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    41 #define REPEATED_KEYMASK    (1<<30)
    42 #define EXTENDED_KEYMASK    (1<<24)
    43 
    44 #define VK_ENTER    10          /* Keypad Enter ... no VKEY defined? */
    45 
    46 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
    47 #ifndef WM_XBUTTONDOWN
    48 #define WM_XBUTTONDOWN 0x020B
    49 #endif
    50 #ifndef WM_XBUTTONUP
    51 #define WM_XBUTTONUP 0x020C
    52 #endif
    53 #ifndef GET_XBUTTON_WPARAM
    54 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
    55 #endif
    56 #ifndef WM_INPUT
    57 #define WM_INPUT 0x00ff
    58 #endif
    59 #ifndef WM_TOUCH
    60 #define WM_TOUCH 0x0240
    61 #endif
    62 
    63 
    64 static WPARAM
    65 RemapVKEY(WPARAM wParam, LPARAM lParam)
    66 {
    67     int i;
    68     BYTE scancode = (BYTE) ((lParam >> 16) & 0xFF);
    69 
    70     /* Windows remaps alphabetic keys based on current layout.
    71        We try to provide USB scancodes, so undo this mapping.
    72      */
    73     if (wParam >= 'A' && wParam <= 'Z') {
    74         if (scancode != alpha_scancodes[wParam - 'A']) {
    75             for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) {
    76                 if (scancode == alpha_scancodes[i]) {
    77                     wParam = 'A' + i;
    78                     break;
    79                 }
    80             }
    81         }
    82     }
    83 
    84     /* Keypad keys are a little trickier, we always scan for them.
    85        Keypad arrow keys have the same scancode as normal arrow keys,
    86        except they don't have the extended bit (0x1000000) set.
    87      */
    88     if (!(lParam & 0x1000000)) {
    89         if (wParam == VK_DELETE) {
    90             wParam = VK_DECIMAL;
    91         } else {
    92             for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
    93                 if (scancode == keypad_scancodes[i]) {
    94                     wParam = VK_NUMPAD0 + i;
    95                     break;
    96                 }
    97             }
    98         }
    99     }
   100 
   101     return wParam;
   102 }
   103 
   104 LRESULT CALLBACK
   105 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   106 {
   107     SDL_WindowData *data;
   108     LRESULT returnCode = -1;
   109 
   110     /* Send a SDL_SYSWMEVENT if the application wants them */
   111     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
   112         SDL_SysWMmsg wmmsg;
   113 
   114         SDL_VERSION(&wmmsg.version);
   115         wmmsg.subsystem = SDL_SYSWM_WINDOWS;
   116         wmmsg.msg.win.hwnd = hwnd;
   117         wmmsg.msg.win.msg = msg;
   118         wmmsg.msg.win.wParam = wParam;
   119         wmmsg.msg.win.lParam = lParam;
   120         SDL_SendSysWMEvent(&wmmsg);
   121     }
   122 
   123     /* Get the window data for the window */
   124     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   125     if (!data) {
   126         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   127     }
   128 
   129 #ifdef WMMSG_DEBUG
   130     {		
   131         FILE *log = fopen("wmmsg.txt", "a");		
   132         fprintf(log, "Received windows message: %p ", hwnd);
   133         if (msg > MAX_WMMSG) {
   134             fprintf(log, "%d", msg);
   135         } else {
   136             fprintf(log, "%s", wmtab[msg]);
   137         }
   138         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   139         fclose(log);
   140     }
   141 #endif
   142 
   143     if (IME_HandleMessage(hwnd, msg, wParam, &lParam, data->videodata))
   144         return 0;
   145 
   146     switch (msg) {
   147 
   148     case WM_SHOWWINDOW:
   149         {
   150             if (wParam) {
   151                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   152             } else {
   153                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   154             }
   155         }
   156         break;
   157 
   158     case WM_ACTIVATE:
   159         {
   160             BOOL minimized;
   161 
   162             minimized = HIWORD(wParam);
   163             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   164                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
   165                 SDL_SendWindowEvent(data->window,
   166                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   167 #ifndef _WIN32_WCE              /* WinCE misses IsZoomed() */
   168                 if (IsZoomed(hwnd)) {
   169                     SDL_SendWindowEvent(data->window,
   170                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   171                 }
   172 #endif
   173                 if (SDL_GetKeyboardFocus() != data->window) {
   174                     SDL_SetKeyboardFocus(data->window);
   175                 }
   176                 /*
   177                  * FIXME: Update keyboard state
   178                  */
   179                 WIN_CheckClipboardUpdate(data->videodata);
   180             } else {
   181                 if (SDL_GetKeyboardFocus() == data->window) {
   182                     SDL_SetKeyboardFocus(NULL);
   183                 }
   184                 if (minimized) {
   185                     SDL_SendWindowEvent(data->window,
   186                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   187                 }
   188             }
   189         }
   190         returnCode = 0;
   191         break;
   192 
   193 	case WM_MOUSEMOVE:
   194 #ifdef _WIN32_WCE
   195         /* transform coords for VGA, WVGA... */
   196         {
   197             SDL_VideoData *videodata = data->videodata;
   198             if(videodata->CoordTransform) {
   199                 POINT pt;
   200                 pt.x = LOWORD(lParam);
   201                 pt.y = HIWORD(lParam);
   202                 videodata->CoordTransform(data->window, &pt);
   203                 SDL_SendMouseMotion(data->window, 0, pt.x, pt.y);
   204                 break;
   205             }
   206         }
   207 #endif
   208         SDL_SendMouseMotion(data->window, 0, LOWORD(lParam), HIWORD(lParam));
   209         break;
   210 
   211     case WM_LBUTTONDOWN:
   212         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_LEFT);
   213         break;
   214 
   215     case WM_LBUTTONUP:
   216         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_LEFT);
   217         break;
   218 
   219     case WM_RBUTTONDOWN:
   220         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_RIGHT);
   221         break;
   222 
   223     case WM_RBUTTONUP:
   224         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_RIGHT);
   225         break;
   226 
   227     case WM_MBUTTONDOWN:
   228         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   229         break;
   230 
   231     case WM_MBUTTONUP:
   232         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   233         break;
   234 
   235     case WM_XBUTTONDOWN:
   236         SDL_SendMouseButton(data->window, SDL_PRESSED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   237         returnCode = TRUE;
   238         break;
   239 
   240     case WM_XBUTTONUP:
   241         SDL_SendMouseButton(data->window, SDL_RELEASED, SDL_BUTTON_X1 + GET_XBUTTON_WPARAM(wParam) - 1);
   242         returnCode = TRUE;
   243         break;
   244 
   245     case WM_MOUSEWHEEL:
   246         {
   247             int motion = (short) HIWORD(wParam);
   248 
   249             SDL_SendMouseWheel(data->window, 0, motion);
   250             break;
   251         }
   252 
   253 #ifdef WM_MOUSELEAVE
   254     /* FIXME: Do we need the SDL 1.2 hack to generate WM_MOUSELEAVE now? */
   255     case WM_MOUSELEAVE:
   256         if (SDL_GetMouseFocus() == data->window) {
   257             SDL_SetMouseFocus(NULL);
   258         }
   259         returnCode = 0;
   260         break;
   261 #endif /* WM_MOUSELEAVE */
   262 
   263     case WM_SYSKEYDOWN:
   264     case WM_KEYDOWN:
   265         {
   266             wParam = RemapVKEY(wParam, lParam);
   267             switch (wParam) {
   268             case VK_CONTROL:
   269                 if (lParam & EXTENDED_KEYMASK)
   270                     wParam = VK_RCONTROL;
   271                 else
   272                     wParam = VK_LCONTROL;
   273                 break;
   274             case VK_SHIFT:
   275                 /* EXTENDED trick doesn't work here */
   276                 {
   277                     Uint8 *state = SDL_GetKeyboardState(NULL);
   278                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   279                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   280                         wParam = VK_LSHIFT;
   281                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   282                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   283                         wParam = VK_RSHIFT;
   284                     } else {
   285                         /* Probably a key repeat */
   286                         wParam = 256;
   287                     }
   288                 }
   289                 break;
   290             case VK_MENU:
   291                 if (lParam & EXTENDED_KEYMASK)
   292                     wParam = VK_RMENU;
   293                 else
   294                     wParam = VK_LMENU;
   295                 break;
   296             case VK_RETURN:
   297                 if (lParam & EXTENDED_KEYMASK)
   298                     wParam = VK_ENTER;
   299                 break;
   300             }
   301             if (wParam < 256) {
   302                 SDL_SendKeyboardKey(SDL_PRESSED,
   303                                     data->videodata->key_layout[wParam]);
   304             }
   305         }
   306         returnCode = 0;
   307         break;
   308 
   309     case WM_SYSKEYUP:
   310     case WM_KEYUP:
   311         {
   312             wParam = RemapVKEY(wParam, lParam);
   313             switch (wParam) {
   314             case VK_CONTROL:
   315                 if (lParam & EXTENDED_KEYMASK)
   316                     wParam = VK_RCONTROL;
   317                 else
   318                     wParam = VK_LCONTROL;
   319                 break;
   320             case VK_SHIFT:
   321                 /* EXTENDED trick doesn't work here */
   322                 {
   323                     Uint8 *state = SDL_GetKeyboardState(NULL);
   324                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   325                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   326                         wParam = VK_LSHIFT;
   327                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   328                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   329                         wParam = VK_RSHIFT;
   330                     } else {
   331                         /* Probably a key repeat */
   332                         wParam = 256;
   333                     }
   334                 }
   335                 break;
   336             case VK_MENU:
   337                 if (lParam & EXTENDED_KEYMASK)
   338                     wParam = VK_RMENU;
   339                 else
   340                     wParam = VK_LMENU;
   341                 break;
   342             case VK_RETURN:
   343                 if (lParam & EXTENDED_KEYMASK)
   344                     wParam = VK_ENTER;
   345                 break;
   346             }
   347 
   348             /* Windows only reports keyup for print screen */
   349             if (wParam == VK_SNAPSHOT
   350                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   351                 SDL_RELEASED) {
   352                 SDL_SendKeyboardKey(SDL_PRESSED,
   353                                     data->videodata->key_layout[wParam]);
   354             }
   355             if (wParam < 256) {
   356                 SDL_SendKeyboardKey(SDL_RELEASED,
   357                                     data->videodata->key_layout[wParam]);
   358             }
   359         }
   360         returnCode = 0;
   361         break;
   362 
   363     case WM_CHAR:
   364         {
   365             char text[4];
   366 
   367             /* Convert to UTF-8 and send it on... */
   368             if (wParam <= 0x7F) {
   369                 text[0] = (char) wParam;
   370                 text[1] = '\0';
   371             } else if (wParam <= 0x7FF) {
   372                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   373                 text[1] = 0x80 | (char) (wParam & 0x3F);
   374                 text[2] = '\0';
   375             } else {
   376                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   377                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   378                 text[2] = 0x80 | (char) (wParam & 0x3F);
   379                 text[3] = '\0';
   380             }
   381             SDL_SendKeyboardText(text);
   382         }
   383         returnCode = 0;
   384         break;
   385 
   386 #ifdef WM_INPUTLANGCHANGE
   387     case WM_INPUTLANGCHANGE:
   388         {
   389             WIN_UpdateKeymap();
   390         }
   391         returnCode = 1;
   392         break;
   393 #endif /* WM_INPUTLANGCHANGE */
   394 
   395 #ifdef WM_GETMINMAXINFO
   396     case WM_GETMINMAXINFO:
   397         {
   398             MINMAXINFO *info;
   399             RECT size;
   400             int x, y;
   401             int w, h;
   402             int style;
   403             BOOL menu;
   404 
   405             /* If we allow resizing, let the resize happen naturally */
   406             if(SDL_IsShapedWindow(data->window))
   407                 Win32_ResizeWindowShape(data->window);
   408             if (SDL_GetWindowFlags(data->window) & SDL_WINDOW_RESIZABLE) {
   409                 returnCode = 0;
   410                 break;
   411             }
   412 
   413             /* Get the current position of our window */
   414             GetWindowRect(hwnd, &size);
   415             x = size.left;
   416             y = size.top;
   417 
   418             /* Calculate current size of our window */
   419             SDL_GetWindowSize(data->window, &w, &h);
   420             size.top = 0;
   421             size.left = 0;
   422             size.bottom = h;
   423             size.right = w;
   424 
   425 
   426             style = GetWindowLong(hwnd, GWL_STYLE);
   427 #ifdef _WIN32_WCE
   428             menu = FALSE;
   429 #else
   430             /* DJM - according to the docs for GetMenu(), the
   431                return value is undefined if hwnd is a child window.
   432                Aparently it's too difficult for MS to check
   433                inside their function, so I have to do it here.
   434              */
   435             menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   436 #endif
   437             AdjustWindowRectEx(&size, style, menu, 0);
   438             w = size.right - size.left;
   439             h = size.bottom - size.top;
   440 
   441             /* Fix our size to the current size */
   442             info = (MINMAXINFO *) lParam;
   443             info->ptMaxSize.x = w;
   444             info->ptMaxSize.y = h;
   445             info->ptMaxPosition.x = x;
   446             info->ptMaxPosition.y = y;
   447             info->ptMinTrackSize.x = w;
   448             info->ptMinTrackSize.y = h;
   449             info->ptMaxTrackSize.x = w;
   450             info->ptMaxTrackSize.y = h;
   451         }
   452         returnCode = 0;
   453         break;
   454 #endif /* WM_GETMINMAXINFO */
   455 
   456     case WM_WINDOWPOSCHANGED:
   457         {
   458             RECT rect;
   459             int x, y;
   460             int w, h;
   461             Uint32 window_flags;
   462 
   463             if (!GetClientRect(hwnd, &rect) ||
   464                 (rect.right == rect.left && rect.bottom == rect.top)) {
   465                 break;
   466             }
   467             ClientToScreen(hwnd, (LPPOINT) & rect);
   468             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   469 
   470             window_flags = SDL_GetWindowFlags(data->window);
   471             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   472                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   473                 ClipCursor(&rect);
   474             }
   475 
   476             x = rect.left;
   477             y = rect.top;
   478             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_MOVED, x, y);
   479 
   480             w = rect.right - rect.left;
   481             h = rect.bottom - rect.top;
   482             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_RESIZED, w,
   483                                 h);
   484         }
   485         break;
   486 
   487     case WM_SETCURSOR:
   488         {
   489             Uint16 hittest;
   490 
   491             hittest = LOWORD(lParam);
   492             if (hittest == HTCLIENT) {
   493                 /* FIXME: Implement the cursor API */
   494                 static HCURSOR cursor;
   495                 if (!cursor) {
   496                     cursor = LoadCursor(NULL, IDC_ARROW);
   497                 }
   498                 SetCursor(cursor);
   499                 returnCode = TRUE;
   500             }
   501         }
   502         break;
   503 
   504         /* We were occluded, refresh our display */
   505     case WM_PAINT:
   506         {
   507             RECT rect;
   508             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   509                 ValidateRect(hwnd, &rect);
   510                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   511                                     0, 0);
   512             }
   513         }
   514         returnCode = 0;
   515         break;
   516 
   517         /* We'll do our own drawing, prevent flicker */
   518     case WM_ERASEBKGND:
   519         {
   520         }
   521         return (1);
   522 
   523 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   524     case WM_SYSCOMMAND:
   525         {
   526             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   527             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   528                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   529                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   530                     return (0);
   531                 }
   532             }
   533         }
   534         break;
   535 #endif /* System has screensaver support */
   536 
   537     case WM_CLOSE:
   538         {
   539             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   540         }
   541         returnCode = 0;
   542         break;
   543 
   544 	case WM_TOUCH:
   545 		{
   546 			UINT i, num_inputs = LOWORD(wParam);
   547 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   548 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   549 				RECT rect;
   550 				float x, y;
   551 
   552 				if (!GetClientRect(hwnd, &rect) ||
   553 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   554 					break;
   555 				}
   556 				ClientToScreen(hwnd, (LPPOINT) & rect);
   557 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   558 				rect.top *= 100;
   559 				rect.left *= 100;
   560 				rect.bottom *= 100;
   561 				rect.right *= 100;
   562 
   563 				for (i = 0; i < num_inputs; ++i) {
   564 					PTOUCHINPUT input = &inputs[i];
   565 
   566 					SDL_TouchID touchId = (SDL_TouchID)input->hSource;
   567 					if (!SDL_GetTouch(touchId)) {
   568 						SDL_Touch touch;
   569 
   570 						touch.id = touchId;
   571 						touch.x_min = 0;
   572 						touch.x_max = 1;
   573 						touch.native_xres = touch.x_max - touch.x_min;
   574 						touch.y_min = 0;
   575 						touch.y_max = 1;
   576 						touch.native_yres = touch.y_max - touch.y_min;
   577 						touch.pressure_min = 0;
   578 						touch.pressure_max = 1;
   579 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   580 
   581 						if (SDL_AddTouch(&touch, "") < 0) {
   582 							continue;
   583 						}
   584 					}
   585 
   586 					// Get the normalized coordinates for the window
   587 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   588 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   589 
   590 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   591 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   592 					}
   593 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   594 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   595 					}
   596 					if (input->dwFlags & TOUCHEVENTF_UP) {
   597 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   598 					}
   599 				}
   600 			}
   601 			SDL_stack_free(inputs);
   602 
   603 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   604 			return 0;
   605 		}
   606 		break;
   607 	}
   608 
   609     /* If there's a window proc, assume it's going to handle messages */
   610     if (data->wndproc) {
   611         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   612     } else if (returnCode >= 0) {
   613         return returnCode;
   614     } else {
   615         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   616     }
   617 }
   618 
   619 void
   620 WIN_PumpEvents(_THIS)
   621 {
   622     MSG msg;
   623     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   624         TranslateMessage(&msg);
   625         DispatchMessage(&msg);
   626     }
   627 }
   628 
   629 static int app_registered = 0;
   630 LPTSTR SDL_Appname = NULL;
   631 Uint32 SDL_Appstyle = 0;
   632 HINSTANCE SDL_Instance = NULL;
   633 
   634 /* Register the class for this application */
   635 int
   636 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   637 {
   638     WNDCLASS class;
   639 
   640     /* Only do this once... */
   641     if (app_registered) {
   642         ++app_registered;
   643         return (0);
   644     }
   645     if (!name && !SDL_Appname) {
   646         name = "SDL_app";
   647 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   648         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   649 #endif
   650         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   651     }
   652 
   653     if (name) {
   654         SDL_Appname = WIN_UTF8ToString(name);
   655         SDL_Appstyle = style;
   656         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   657     }
   658 
   659     /* Register the application class */
   660     class.hCursor = NULL;
   661     class.hIcon =
   662         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   663                   LR_DEFAULTCOLOR);
   664     class.lpszMenuName = NULL;
   665     class.lpszClassName = SDL_Appname;
   666     class.hbrBackground = NULL;
   667     class.hInstance = SDL_Instance;
   668     class.style = SDL_Appstyle;
   669     class.lpfnWndProc = WIN_WindowProc;
   670     class.cbWndExtra = 0;
   671     class.cbClsExtra = 0;
   672     if (!RegisterClass(&class)) {
   673         SDL_SetError("Couldn't register application class");
   674         return (-1);
   675     }
   676 
   677     app_registered = 1;
   678     return (0);
   679 }
   680 
   681 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   682 void
   683 SDL_UnregisterApp()
   684 {
   685     WNDCLASS class;
   686 
   687     /* SDL_RegisterApp might not have been called before */
   688     if (!app_registered) {
   689         return;
   690     }
   691     --app_registered;
   692     if (app_registered == 0) {
   693         /* Check for any registered window classes. */
   694         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   695             UnregisterClass(SDL_Appname, SDL_Instance);
   696         }
   697         SDL_free(SDL_Appname);
   698         SDL_Appname = NULL;
   699     }
   700 }
   701 
   702 /* vi: set ts=4 sw=4 expandtab: */