src/video/win32/SDL_win32events.c
author Edgar Simo <bobbens@gmail.com>
Tue, 26 Aug 2008 11:50:37 +0000
changeset 2733 264037dd3c7a
parent 2726 f23ebf1ddac4
child 2766 5955b6550d7e
permissions -rw-r--r--
Fix for mingw compilation by Alam.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 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 #if (_WIN32_WINNT < 0x0501)
    24 #undef _WIN32_WINNT
    25 #define _WIN32_WINNT 0x0501
    26 #endif
    27 
    28 #include "SDL_config.h"
    29 
    30 #include "SDL_win32video.h"
    31 #include "SDL_syswm.h"
    32 #include "SDL_vkeys.h"
    33 #include "../../events/SDL_events_c.h"
    34 
    35 /*#define WMMSG_DEBUG*/
    36 #ifdef WMMSG_DEBUG
    37 #include <stdio.h>
    38 #include "wmmsg.h"
    39 #endif
    40 
    41 /* Masks for processing the windows KEYDOWN and KEYUP messages */
    42 #define REPEATED_KEYMASK    (1<<30)
    43 #define EXTENDED_KEYMASK    (1<<24)
    44 
    45 #define VK_ENTER    10          /* Keypad Enter ... no VKEY defined? */
    46 
    47 /* Make sure XBUTTON stuff is defined that isn't in older Platform SDKs... */
    48 #ifndef WM_XBUTTONDOWN
    49 #define WM_XBUTTONDOWN 0x020B
    50 #endif
    51 #ifndef WM_XBUTTONUP
    52 #define WM_XBUTTONUP 0x020C
    53 #endif
    54 #ifndef GET_XBUTTON_WPARAM
    55 #define GET_XBUTTON_WPARAM(w) (HIWORD(w))
    56 #endif
    57 #ifndef WM_INPUT
    58 #define WM_INPUT 0x00ff
    59 #endif
    60 
    61 extern HCTX *g_hCtx;
    62 extern HANDLE *mice;
    63 extern int total_mice;
    64 extern int tablet;
    65 int pressure = 0;               /* the pressure reported by the tablet */
    66 
    67 static WPARAM
    68 RemapVKEY(WPARAM wParam, LPARAM lParam)
    69 {
    70     int i;
    71     BYTE scancode = (BYTE) ((lParam >> 16) & 0xFF);
    72 
    73     /* Windows remaps alphabetic keys based on current layout.
    74        We try to provide USB scancodes, so undo this mapping.
    75      */
    76     if (wParam >= 'A' && wParam <= 'Z') {
    77         if (scancode != alpha_scancodes[wParam - 'A']) {
    78             for (i = 0; i < SDL_arraysize(alpha_scancodes); ++i) {
    79                 if (scancode == alpha_scancodes[i]) {
    80                     wParam = 'A' + i;
    81                     break;
    82                 }
    83             }
    84         }
    85     }
    86 
    87     /* Keypad keys are a little trickier, we always scan for them. */
    88     for (i = 0; i < SDL_arraysize(keypad_scancodes); ++i) {
    89         if (scancode == keypad_scancodes[i]) {
    90             wParam = VK_NUMPAD0 + i;
    91             break;
    92         }
    93     }
    94 
    95     return wParam;
    96 }
    97 
    98 LRESULT CALLBACK
    99 WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   100 {
   101     SDL_WindowData *data;
   102     RAWINPUT *raw;
   103     PACKET packet;
   104 
   105     /* Send a SDL_SYSWMEVENT if the application wants them */
   106     if (SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE) {
   107         SDL_SysWMmsg wmmsg;
   108 
   109         SDL_VERSION(&wmmsg.version);
   110         wmmsg.hwnd = hwnd;
   111         wmmsg.msg = msg;
   112         wmmsg.wParam = wParam;
   113         wmmsg.lParam = lParam;
   114         SDL_SendSysWMEvent(&wmmsg);
   115     }
   116 
   117     /* Get the window data for the window */
   118     data = (SDL_WindowData *) GetProp(hwnd, TEXT("SDL_WindowData"));
   119     if (!data) {
   120         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
   121     }
   122 #ifdef WMMSG_DEBUG
   123     {
   124         FILE *log = fopen("wmmsg.txt", "a");
   125         fprintf(log, "Received windows message: %p ", hwnd);
   126         if (msg > MAX_WMMSG) {
   127             fprintf(log, "%d", msg);
   128         } else {
   129             fprintf(log, "%s", wmtab[msg]);
   130         }
   131         fprintf(log, " -- 0x%X, 0x%X\n", wParam, lParam);
   132         fclose(log);
   133     }
   134 
   135 #endif
   136 
   137     switch (msg) {
   138 
   139     case WT_PACKET:
   140         {
   141             /* if we receive such data we need to update the pressure */
   142             SDL_VideoData *videodata = data->videodata;
   143             if (videodata->wintabDLL
   144                 && videodata->WTPacket((HCTX) lParam, wParam, &packet)) {
   145                 SDL_ChangeEnd(tablet, (int) packet.pkCursor);
   146                 pressure = (int) packet.pkNormalPressure;
   147             }
   148         }
   149         break;
   150 
   151     case WT_PROXIMITY:
   152         {
   153             /* checking where the proximity message showed up */
   154             int h_context = LOWORD(lParam);
   155             POINT point;
   156             GetCursorPos(&point);
   157             ScreenToClient(hwnd, &point);
   158 
   159             /* are we in proximity or out of proximity */
   160             if (h_context == 0) {
   161                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYOUT);
   162             } else {
   163                 SDL_SendProximity(tablet, point.x, point.y, SDL_PROXIMITYIN);
   164             }
   165         }
   166         break;
   167 
   168     case WM_SHOWWINDOW:
   169         {
   170             if (wParam) {
   171                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN, 0,
   172                                     0);
   173             } else {
   174                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_HIDDEN, 0,
   175                                     0);
   176             }
   177         }
   178         break;
   179 
   180     case WM_ACTIVATE:
   181         {
   182             int index;
   183             SDL_Keyboard *keyboard;
   184             BOOL minimized;
   185 
   186             minimized = HIWORD(wParam);
   187             index = data->videodata->keyboard;
   188             keyboard = SDL_GetKeyboard(index);
   189             if (!minimized && (LOWORD(wParam) != WA_INACTIVE)) {
   190                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_SHOWN,
   191                                     0, 0);
   192                 SDL_SendWindowEvent(data->windowID,
   193                                     SDL_WINDOWEVENT_RESTORED, 0, 0);
   194                 if (IsZoomed(hwnd)) {
   195                     SDL_SendWindowEvent(data->windowID,
   196                                         SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
   197                 }
   198                 if (keyboard && keyboard->focus != data->windowID) {
   199                     SDL_SetKeyboardFocus(index, data->windowID);
   200                 }
   201                 /* FIXME: Update keyboard state */
   202             } else {
   203                 if (keyboard && keyboard->focus == data->windowID) {
   204                     SDL_SetKeyboardFocus(index, 0);
   205                 }
   206                 if (minimized) {
   207                     SDL_SendWindowEvent(data->windowID,
   208                                         SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   209                 }
   210             }
   211         }
   212         return (0);
   213 
   214     case WM_INPUT:             /* mouse events */
   215         {
   216             LPBYTE lpb;
   217             int w, h;
   218             const RAWINPUTHEADER *header;
   219             int index;
   220             int i;
   221             int size = 0;
   222             const RAWMOUSE *raw_mouse = NULL;
   223             POINT point;
   224             USHORT flags;
   225 
   226             /* we're collecting data from the mouse */
   227             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &size,
   228                             sizeof(RAWINPUTHEADER));
   229             lpb = SDL_malloc(size * sizeof(LPBYTE));
   230             GetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &size,
   231                             sizeof(RAWINPUTHEADER));
   232             raw = (RAWINPUT *) lpb;
   233             header = &raw->header;
   234             flags = raw->data.mouse.usButtonFlags;
   235 
   236             /* we're checking which mouse generated the event */
   237             for (i = 0; i < total_mice; ++i) {
   238                 if (mice[i] == header->hDevice) {
   239                     index = i;
   240                     break;
   241                 }
   242             }
   243             GetCursorPos(&point);
   244             ScreenToClient(hwnd, &point);
   245             SDL_GetWindowSize(data->windowID, &w, &h);
   246             SDL_UpdateCoordinates(w, h);        /* we're updating the current window size */
   247 
   248             /* if the message was sent by a tablet we have to send also pressure */
   249             if (i == tablet) {
   250                 SDL_SendMouseMotion(index, 0, point.x, point.y, pressure);
   251             } else {
   252                 SDL_SendMouseMotion(index, 0, point.x, point.y, 0);
   253             }
   254             /* we're sending mouse buttons messages to check up if sth changed */
   255             if (flags & RI_MOUSE_BUTTON_1_DOWN) {
   256                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_LEFT);
   257             } else if (flags & RI_MOUSE_BUTTON_1_UP) {
   258                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_LEFT);
   259             }
   260             if (flags & RI_MOUSE_BUTTON_2_DOWN) {
   261                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_MIDDLE);
   262             } else if (flags & RI_MOUSE_BUTTON_2_UP) {
   263                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_MIDDLE);
   264             }
   265             if (flags & RI_MOUSE_BUTTON_3_DOWN) {
   266                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_RIGHT);
   267             } else if (flags & RI_MOUSE_BUTTON_3_UP) {
   268                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_RIGHT);
   269             }
   270             if (flags & RI_MOUSE_BUTTON_4_DOWN) {
   271                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X1);
   272             } else if (flags & RI_MOUSE_BUTTON_4_UP) {
   273                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X1);
   274             }
   275             if (flags & RI_MOUSE_BUTTON_5_DOWN) {
   276                 SDL_SendMouseButton(index, SDL_PRESSED, SDL_BUTTON_X2);
   277             } else if (flags & RI_MOUSE_BUTTON_5_UP) {
   278                 SDL_SendMouseButton(index, SDL_RELEASED, SDL_BUTTON_X2);
   279             }
   280             if (flags & RI_MOUSE_WHEEL) {
   281                 if (raw->data.mouse.usButtonData != 0) {
   282                     SDL_SendMouseWheel(index, 0,
   283                                        raw->data.mouse.usButtonData);
   284                 }
   285             }
   286         }
   287         return (0);
   288 
   289     case WM_MOUSELEAVE:
   290         {
   291             int index;
   292             SDL_Mouse *mouse;
   293 
   294             index = data->videodata->mouse;
   295             mouse = SDL_GetMouse(index);
   296 
   297             if (mouse->focus == data->windowID) {
   298                 SDL_SetMouseFocus(index, 0);
   299             }
   300         }
   301         return (0);
   302 
   303     case WM_SYSKEYDOWN:
   304     case WM_KEYDOWN:
   305         {
   306             int index;
   307 
   308             /* Ignore repeated keys */
   309             if (lParam & REPEATED_KEYMASK) {
   310                 return (0);
   311             }
   312 
   313             index = data->videodata->keyboard;
   314             wParam = RemapVKEY(wParam, lParam);
   315             switch (wParam) {
   316             case VK_CONTROL:
   317                 if (lParam & EXTENDED_KEYMASK)
   318                     wParam = VK_RCONTROL;
   319                 else
   320                     wParam = VK_LCONTROL;
   321                 break;
   322             case VK_SHIFT:
   323                 /* EXTENDED trick doesn't work here */
   324                 {
   325                     Uint8 *state = SDL_GetKeyboardState(NULL);
   326                     if (state[SDL_SCANCODE_LSHIFT] == SDL_RELEASED
   327                         && (GetKeyState(VK_LSHIFT) & 0x8000)) {
   328                         wParam = VK_LSHIFT;
   329                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_RELEASED
   330                                && (GetKeyState(VK_RSHIFT) & 0x8000)) {
   331                         wParam = VK_RSHIFT;
   332                     } else {
   333                         /* Probably a key repeat */
   334                         return (0);
   335                     }
   336                 }
   337                 break;
   338             case VK_MENU:
   339                 if (lParam & EXTENDED_KEYMASK)
   340                     wParam = VK_RMENU;
   341                 else
   342                     wParam = VK_LMENU;
   343                 break;
   344             case VK_RETURN:
   345                 if (lParam & EXTENDED_KEYMASK)
   346                     wParam = VK_ENTER;
   347                 break;
   348             }
   349             if (wParam < 256) {
   350                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   351                                     data->videodata->key_layout[wParam]);
   352             }
   353         }
   354         return (0);
   355 
   356     case WM_SYSKEYUP:
   357     case WM_KEYUP:
   358         {
   359             int index;
   360 
   361             index = data->videodata->keyboard;
   362             wParam = RemapVKEY(wParam, lParam);
   363             switch (wParam) {
   364             case VK_CONTROL:
   365                 if (lParam & EXTENDED_KEYMASK)
   366                     wParam = VK_RCONTROL;
   367                 else
   368                     wParam = VK_LCONTROL;
   369                 break;
   370             case VK_SHIFT:
   371                 /* EXTENDED trick doesn't work here */
   372                 {
   373                     Uint8 *state = SDL_GetKeyboardState(NULL);
   374                     if (state[SDL_SCANCODE_LSHIFT] == SDL_PRESSED
   375                         && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
   376                         wParam = VK_LSHIFT;
   377                     } else if (state[SDL_SCANCODE_RSHIFT] == SDL_PRESSED
   378                                && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
   379                         wParam = VK_RSHIFT;
   380                     } else {
   381                         /* Probably a key repeat */
   382                         return (0);
   383                     }
   384                 }
   385                 break;
   386             case VK_MENU:
   387                 if (lParam & EXTENDED_KEYMASK)
   388                     wParam = VK_RMENU;
   389                 else
   390                     wParam = VK_LMENU;
   391                 break;
   392             case VK_RETURN:
   393                 if (lParam & EXTENDED_KEYMASK)
   394                     wParam = VK_ENTER;
   395                 break;
   396             }
   397 
   398             /* Windows only reports keyup for print screen */
   399             if (wParam == VK_SNAPSHOT
   400                 && SDL_GetKeyboardState(NULL)[SDL_SCANCODE_PRINTSCREEN] ==
   401                 SDL_RELEASED) {
   402                 SDL_SendKeyboardKey(index, SDL_PRESSED,
   403                                     data->videodata->key_layout[wParam]);
   404             }
   405             if (wParam < 256) {
   406                 SDL_SendKeyboardKey(index, SDL_RELEASED,
   407                                     data->videodata->key_layout[wParam]);
   408             }
   409         }
   410         return (0);
   411 
   412     case WM_CHAR:
   413         {
   414             char text[4];
   415 
   416             /* Convert to UTF-8 and send it on... */
   417             if (wParam <= 0x7F) {
   418                 text[0] = (char) wParam;
   419                 text[1] = '\0';
   420             } else if (wParam <= 0x7FF) {
   421                 text[0] = 0xC0 | (char) ((wParam >> 6) & 0x1F);
   422                 text[1] = 0x80 | (char) (wParam & 0x3F);
   423                 text[2] = '\0';
   424             } else {
   425                 text[0] = 0xE0 | (char) ((wParam >> 12) & 0x0F);
   426                 text[1] = 0x80 | (char) ((wParam >> 6) & 0x3F);
   427                 text[2] = 0x80 | (char) (wParam & 0x3F);
   428                 text[3] = '\0';
   429             }
   430             SDL_SendKeyboardText(data->videodata->keyboard, text);
   431         }
   432         return (0);
   433 
   434     case WM_INPUTLANGCHANGE:
   435         {
   436             WIN_UpdateKeymap(data->videodata->keyboard);
   437         }
   438         return (1);
   439 
   440     case WM_GETMINMAXINFO:
   441         {
   442             MINMAXINFO *info;
   443             RECT size;
   444             int x, y;
   445             int w, h;
   446             int style;
   447 
   448             /* If we allow resizing, let the resize happen naturally */
   449             if (SDL_GetWindowFlags(data->windowID) & SDL_WINDOW_RESIZABLE) {
   450                 return (0);
   451             }
   452 
   453             /* Get the current position of our window */
   454             GetWindowRect(hwnd, &size);
   455             x = size.left;
   456             y = size.top;
   457 
   458             /* Calculate current size of our window */
   459             SDL_GetWindowSize(data->windowID, &w, &h);
   460             size.top = 0;
   461             size.left = 0;
   462             size.bottom = h;
   463             size.right = w;
   464 
   465             /* DJM - according to the docs for GetMenu(), the
   466                return value is undefined if hwnd is a child window.
   467                Aparently it's too difficult for MS to check
   468                inside their function, so I have to do it here.
   469              */
   470             style = GetWindowLong(hwnd, GWL_STYLE);
   471             AdjustWindowRect(&size, style,
   472                              style & WS_CHILDWINDOW ? FALSE : GetMenu(hwnd)
   473                              != NULL);
   474             w = size.right - size.left;
   475             h = size.bottom - size.top;
   476 
   477             /* Fix our size to the current size */
   478             info = (MINMAXINFO *) lParam;
   479             info->ptMaxSize.x = w;
   480             info->ptMaxSize.y = h;
   481             info->ptMaxPosition.x = x;
   482             info->ptMaxPosition.y = y;
   483             info->ptMinTrackSize.x = w;
   484             info->ptMinTrackSize.y = h;
   485             info->ptMaxTrackSize.x = w;
   486             info->ptMaxTrackSize.y = h;
   487         }
   488         return (0);
   489 
   490     case WM_WINDOWPOSCHANGED:
   491         {
   492             RECT rect;
   493             int x, y;
   494             int w, h;
   495             Uint32 window_flags;
   496 
   497             GetClientRect(hwnd, &rect);
   498             ClientToScreen(hwnd, (LPPOINT) & rect);
   499             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   500 
   501             window_flags = SDL_GetWindowFlags(data->windowID);
   502             if ((window_flags & SDL_WINDOW_INPUT_GRABBED) &&
   503                 (window_flags & SDL_WINDOW_INPUT_FOCUS)) {
   504                 ClipCursor(&rect);
   505             }
   506 
   507             x = rect.left;
   508             y = rect.top;
   509             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_MOVED, x, y);
   510 
   511             w = rect.right - rect.left;
   512             h = rect.bottom - rect.top;
   513             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_RESIZED, w,
   514                                 h);
   515         }
   516         break;
   517 
   518     case WM_SETCURSOR:
   519         {
   520             /*
   521                Uint16 hittest;
   522 
   523                hittest = LOWORD(lParam);
   524                if (hittest == HTCLIENT) {
   525                SetCursor(SDL_hcursor);
   526                return (TRUE);
   527                }
   528              */
   529         }
   530         break;
   531 
   532         /* We are about to get palette focus! */
   533     case WM_QUERYNEWPALETTE:
   534         {
   535             /*
   536                WIN_RealizePalette(current_video);
   537                return (TRUE);
   538              */
   539         }
   540         break;
   541 
   542         /* Another application changed the palette */
   543     case WM_PALETTECHANGED:
   544         {
   545             /*
   546                WIN_PaletteChanged(current_video, (HWND) wParam);
   547              */
   548         }
   549         break;
   550 
   551         /* We were occluded, refresh our display */
   552     case WM_PAINT:
   553         {
   554             RECT rect;
   555             if (GetUpdateRect(hwnd, &rect, FALSE)) {
   556                 ValidateRect(hwnd, &rect);
   557                 SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_EXPOSED,
   558                                     0, 0);
   559             }
   560         }
   561         return (0);
   562 
   563         /* We'll do our own drawing, prevent flicker */
   564     case WM_ERASEBKGND:
   565         {
   566         }
   567         return (1);
   568 
   569     case WM_SYSCOMMAND:
   570         {
   571             /* Don't start the screensaver or blank the monitor in fullscreen apps */
   572             if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
   573                 (wParam & 0xFFF0) == SC_MONITORPOWER) {
   574                 if (SDL_GetWindowFlags(data->windowID) &
   575                     SDL_WINDOW_FULLSCREEN) {
   576                     return (0);
   577                 }
   578             }
   579         }
   580         break;
   581 
   582     case WM_CLOSE:
   583         {
   584             SDL_SendWindowEvent(data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0);
   585         }
   586         return (0);
   587     }
   588     return CallWindowProc(data->wndproc, hwnd, msg, wParam, lParam);
   589 }
   590 
   591 void
   592 WIN_PumpEvents(_THIS)
   593 {
   594     MSG msg;
   595     while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
   596         TranslateMessage(&msg);
   597         DispatchMessage(&msg);
   598     }
   599 }
   600 
   601 static int app_registered = 0;
   602 LPTSTR SDL_Appname = NULL;
   603 Uint32 SDL_Appstyle = 0;
   604 HINSTANCE SDL_Instance = NULL;
   605 
   606 /* Register the class for this application */
   607 int
   608 SDL_RegisterApp(char *name, Uint32 style, void *hInst)
   609 {
   610     WNDCLASS class;
   611 
   612     /* Only do this once... */
   613     if (app_registered) {
   614         ++app_registered;
   615         return (0);
   616     }
   617     if (!name && !SDL_Appname) {
   618         name = "SDL_app";
   619         SDL_Appstyle = (CS_BYTEALIGNCLIENT | CS_OWNDC);
   620         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   621     }
   622 
   623     if (name) {
   624         SDL_Appname = WIN_UTF8ToString(name);
   625         SDL_Appstyle = style;
   626         SDL_Instance = hInst ? hInst : GetModuleHandle(NULL);
   627     }
   628 
   629     /* Register the application class */
   630     class.hCursor = NULL;
   631     class.hIcon =
   632         LoadImage(SDL_Instance, SDL_Appname, IMAGE_ICON, 0, 0,
   633                   LR_DEFAULTCOLOR);
   634     class.lpszMenuName = NULL;
   635     class.lpszClassName = SDL_Appname;
   636     class.hbrBackground = NULL;
   637     class.hInstance = SDL_Instance;
   638     class.style = SDL_Appstyle;
   639     class.lpfnWndProc = DefWindowProc;
   640     class.cbWndExtra = 0;
   641     class.cbClsExtra = 0;
   642     if (!RegisterClass(&class)) {
   643         SDL_SetError("Couldn't register application class");
   644         return (-1);
   645     }
   646 
   647     app_registered = 1;
   648     return (0);
   649 }
   650 
   651 /* Unregisters the windowclass registered in SDL_RegisterApp above. */
   652 void
   653 SDL_UnregisterApp()
   654 {
   655     WNDCLASS class;
   656 
   657     /* SDL_RegisterApp might not have been called before */
   658     if (!app_registered) {
   659         return;
   660     }
   661     --app_registered;
   662     if (app_registered == 0) {
   663         /* Check for any registered window classes. */
   664         if (GetClassInfo(SDL_Instance, SDL_Appname, &class)) {
   665             UnregisterClass(SDL_Appname, SDL_Instance);
   666         }
   667         SDL_free(SDL_Appname);
   668         SDL_Appname = NULL;
   669     }
   670 }
   671 
   672 /* Sets an error message based on GetLastError() */
   673 void
   674 WIN_SetError(const char *prefix)
   675 {
   676     TCHAR buffer[1024];
   677     char *message;
   678     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
   679                   buffer, SDL_arraysize(buffer), NULL);
   680     message = WIN_StringToUTF8(buffer);
   681     SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ":" : "", message);
   682     SDL_free(message);
   683 }
   684 
   685 /* vi: set ts=4 sw=4 expandtab: */