src/video/windows/SDL_windowsevents.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 31 Jan 2011 22:53:45 -0800
changeset 5139 57851a238c8f
parent 5086 c2539ff054c8
child 5149 be02be2ea897
permissions -rw-r--r--
Removed more partially functional renderers
     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 are about to get palette focus! */
   505     case WM_QUERYNEWPALETTE:
   506         {
   507             /*
   508                 WIN_RealizePalette(current_video);
   509                 returnCode = TRUE;
   510              */
   511         }
   512         break;
   513 
   514         /* Another application changed the palette */
   515     case WM_PALETTECHANGED:
   516         {
   517             /*
   518                WIN_PaletteChanged(current_video, (HWND) wParam);
   519              */
   520         }
   521         break;
   522 
   523         /* We were occluded, refresh our display */
   524     case WM_PAINT:
   525         {
   526             RECT rect;
   527             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   528                 ValidateRect(hwnd, &rect);
   529                 SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_EXPOSED,
   530                                     0, 0);
   531             }
   532         }
   533         returnCode = 0;
   534         break;
   535 
   536         /* We'll do our own drawing, prevent flicker */
   537     case WM_ERASEBKGND:
   538         {
   539         }
   540         return (1);
   541 
   542 #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER)
   543     case WM_SYSCOMMAND:
   544         {
   545             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   546             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   547                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   548                 if (SDL_GetVideoDevice()->suspend_screensaver) {
   549                     return (0);
   550                 }
   551             }
   552         }
   553         break;
   554 #endif /* System has screensaver support */
   555 
   556     case WM_CLOSE:
   557         {
   558             SDL_SendWindowEvent(data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
   559         }
   560         returnCode = 0;
   561         break;
   562 
   563 	case WM_TOUCH:
   564 		{
   565 			UINT i, num_inputs = LOWORD(wParam);
   566 			PTOUCHINPUT inputs = SDL_stack_alloc(TOUCHINPUT, num_inputs);
   567 			if (data->videodata->GetTouchInputInfo((HTOUCHINPUT)lParam, num_inputs, inputs, sizeof(TOUCHINPUT))) {
   568 				RECT rect;
   569 				float x, y;
   570 
   571 				if (!GetClientRect(hwnd, &rect) ||
   572 				    (rect.right == rect.left && rect.bottom == rect.top)) {
   573 					break;
   574 				}
   575 				ClientToScreen(hwnd, (LPPOINT) & rect);
   576 				ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   577 				rect.top *= 100;
   578 				rect.left *= 100;
   579 				rect.bottom *= 100;
   580 				rect.right *= 100;
   581 
   582 				for (i = 0; i < num_inputs; ++i) {
   583 					PTOUCHINPUT input = &inputs[i];
   584 
   585 					SDL_TouchID touchId = (SDL_TouchID)input->hSource;
   586 					if (!SDL_GetTouch(touchId)) {
   587 						SDL_Touch touch;
   588 
   589 						touch.id = touchId;
   590 						touch.x_min = 0;
   591 						touch.x_max = 1;
   592 						touch.native_xres = touch.x_max - touch.x_min;
   593 						touch.y_min = 0;
   594 						touch.y_max = 1;
   595 						touch.native_yres = touch.y_max - touch.y_min;
   596 						touch.pressure_min = 0;
   597 						touch.pressure_max = 1;
   598 						touch.native_pressureres = touch.pressure_max - touch.pressure_min;
   599 
   600 						if (SDL_AddTouch(&touch, "") < 0) {
   601 							continue;
   602 						}
   603 					}
   604 
   605 					// Get the normalized coordinates for the window
   606 					x = (float)(input->x - rect.left)/(rect.right - rect.left);
   607 					y = (float)(input->y - rect.top)/(rect.bottom - rect.top);
   608 
   609 					if (input->dwFlags & TOUCHEVENTF_DOWN) {
   610 						SDL_SendFingerDown(touchId, input->dwID, SDL_TRUE, x, y, 1);
   611 					}
   612 					if (input->dwFlags & TOUCHEVENTF_MOVE) {
   613 						SDL_SendTouchMotion(touchId, input->dwID, SDL_FALSE, x, y, 1);
   614 					}
   615 					if (input->dwFlags & TOUCHEVENTF_UP) {
   616 						SDL_SendFingerDown(touchId, input->dwID, SDL_FALSE, x, y, 1);
   617 					}
   618 				}
   619 			}
   620 			SDL_stack_free(inputs);
   621 
   622 			data->videodata->CloseTouchInputHandle((HTOUCHINPUT)lParam);
   623 			return 0;
   624 		}
   625 		break;
   626 	}
   627 
   628     /* If there's a window proc, assume it's going to handle messages */
   629     if (data->wndproc) {
   630         return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   631     } else if (returnCode >= 0) {
   632         return returnCode;
   633     } else {
   634         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   635     }
   636 }
   637 
   638 void
   639 WIN_PumpEvents(_THIS)
   640 {
   641     MSG msg;
   642     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   643         TranslateMessage(&msg);
   644         DispatchMessage(&msg);
   645     }
   646 }
   647 
   648 static int app_registered = 0;
   649 LPTSTR SDL_Appname = NULL;
   650 Uint32 SDL_Appstyle = 0;
   651 HINSTANCE SDL_Instance = NULL;
   652 
   653 /* Register the class for this application */
   654 int
   655 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   656 {
   657     WNDCLASS class;
   658 
   659     /* Only do this once... */
   660     if (app_registered) {
   661         ++app_registered;
   662         return (0);
   663     }
   664     if (!name && !SDL_Appname) {
   665         name = "SDL_app";
   666 #if defined(CS_BYTEALIGNCLIENT) || defined(CS_OWNDC)
   667         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   668 #endif
   669         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   670     }
   671 
   672     if (name) {
   673         SDL_Appname = WIN_UTF8ToString(name);
   674         SDL_Appstyle = style;
   675         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   676     }
   677 
   678     /* Register the application class */
   679     class.hCursor = NULL;
   680     class.hIcon =
   681         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   682                   LR_DEFAULTCOLOR);
   683     class.lpszMenuName = NULL;
   684     class.lpszClassName = SDL_Appname;
   685     class.hbrBackground = NULL;
   686     class.hInstance = SDL_Instance;
   687     class.style = SDL_Appstyle;
   688     class.lpfnWndProc = WIN_WindowProc;
   689     class.cbWndExtra = 0;
   690     class.cbClsExtra = 0;
   691     if (!RegisterClass(&class)) {
   692         SDL_SetError("Couldn't register application class");
   693         return (-1);
   694     }
   695 
   696     app_registered = 1;
   697     return (0);
   698 }
   699 
   700 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   701 void
   702 SDL_UnregisterApp()
   703 {
   704     WNDCLASS class;
   705 
   706     /* SDL_RegisterApp might not have been called before */
   707     if (!app_registered) {
   708         return;
   709     }
   710     --app_registered;
   711     if (app_registered == 0) {
   712         /* Check for any registered window classes. */
   713         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   714             UnregisterClass(SDL_Appname, SDL_Instance);
   715         }
   716         SDL_free(SDL_Appname);
   717         SDL_Appname = NULL;
   718     }
   719 }
   720 
   721 /* vi: set ts=4 sw=4 expandtab: */