src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 17 Oct 2013 23:02:29 -0700
changeset 7828 1451063c8ecd
parent 7817 357bccc72a1c
child 7920 94ed2e31a603
permissions -rw-r--r--
Fixed building using MinGW
Our SDL_windows.h needed to be included before anything else so UNICODE is defined.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #if SDL_VIDEO_DRIVER_WINDOWS
    24 
    25 #include "../../core/windows/SDL_windows.h"
    26 
    27 #include "SDL_assert.h"
    28 #include "../SDL_sysvideo.h"
    29 #include "../SDL_pixels_c.h"
    30 #include "../../events/SDL_keyboard_c.h"
    31 
    32 #include "SDL_windowsvideo.h"
    33 #include "SDL_windowswindow.h"
    34 
    35 /* Dropfile support */
    36 #include <shellapi.h>
    37 
    38 /* This is included after SDL_windowsvideo.h, which includes windows.h */
    39 #include "SDL_syswm.h"
    40 
    41 /* Windows CE compatibility */
    42 #ifndef SWP_NOCOPYBITS
    43 #define SWP_NOCOPYBITS 0
    44 #endif
    45 
    46 /* Fake window to help with DirectInput events. */
    47 HWND SDL_HelperWindow = NULL;
    48 static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
    49 static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
    50 static ATOM SDL_HelperWindowClass = 0;
    51 
    52 #define STYLE_BASIC         (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
    53 #define STYLE_FULLSCREEN    (WS_POPUP)
    54 #define STYLE_BORDERLESS    (WS_POPUP)
    55 #define STYLE_NORMAL        (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
    56 #define STYLE_RESIZABLE     (WS_THICKFRAME | WS_MAXIMIZEBOX)
    57 #define STYLE_MASK          (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
    58 
    59 static DWORD
    60 GetWindowStyle(SDL_Window * window)
    61 {
    62     DWORD style = 0;
    63 
    64     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    65         style |= STYLE_FULLSCREEN;
    66     } else {
    67         if (window->flags & SDL_WINDOW_BORDERLESS) {
    68             style |= STYLE_BORDERLESS;
    69         } else {
    70             style |= STYLE_NORMAL;
    71         }
    72         if (window->flags & SDL_WINDOW_RESIZABLE) {
    73             style |= STYLE_RESIZABLE;
    74         }
    75     }
    76     return style;
    77 }
    78 
    79 static void
    80 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
    81 {
    82     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
    83     RECT rect;
    84     DWORD style;
    85     HWND top;
    86     BOOL menu;
    87     int x, y;
    88     int w, h;
    89 
    90     /* Figure out what the window area will be */
    91     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
    92         top = HWND_TOPMOST;
    93     } else {
    94         top = HWND_NOTOPMOST;
    95     }
    96     style = GetWindowLong(hwnd, GWL_STYLE);
    97     rect.left = 0;
    98     rect.top = 0;
    99     rect.right = window->w;
   100     rect.bottom = window->h;
   101     menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   102     AdjustWindowRectEx(&rect, style, menu, 0);
   103     w = (rect.right - rect.left);
   104     h = (rect.bottom - rect.top);
   105     x = window->x + rect.left;
   106     y = window->y + rect.top;
   107 
   108     SetWindowPos(hwnd, top, x, y, w, h, flags);
   109 }
   110 
   111 static int
   112 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created)
   113 {
   114     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   115     SDL_WindowData *data;
   116 
   117     /* Allocate the window data */
   118     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   119     if (!data) {
   120         return SDL_OutOfMemory();
   121     }
   122     data->window = window;
   123     data->hwnd = hwnd;
   124     data->hdc = GetDC(hwnd);
   125     data->created = created;
   126     data->mouse_button_flags = 0;
   127     data->videodata = videodata;
   128 
   129     window->driverdata = data;
   130 
   131     /* Associate the data with the window */
   132     if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
   133         ReleaseDC(hwnd, data->hdc);
   134         SDL_free(data);
   135         return WIN_SetError("SetProp() failed");
   136     }
   137 
   138     /* Set up the window proc function */
   139 #ifdef GWLP_WNDPROC
   140     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
   141     if (data->wndproc == WIN_WindowProc) {
   142         data->wndproc = NULL;
   143     } else {
   144         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
   145     }
   146 #else
   147     data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
   148     if (data->wndproc == WIN_WindowProc) {
   149         data->wndproc = NULL;
   150     } else {
   151         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
   152     }
   153 #endif
   154 
   155     /* Fill in the SDL window with the window data */
   156     {
   157         RECT rect;
   158         if (GetClientRect(hwnd, &rect)) {
   159             int w = rect.right;
   160             int h = rect.bottom;
   161             if ((window->w && window->w != w) || (window->h && window->h != h)) {
   162                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
   163                 WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
   164             } else {
   165                 window->w = w;
   166                 window->h = h;
   167             }
   168         }
   169     }
   170     {
   171         POINT point;
   172         point.x = 0;
   173         point.y = 0;
   174         if (ClientToScreen(hwnd, &point)) {
   175             window->x = point.x;
   176             window->y = point.y;
   177         }
   178     }
   179     {
   180         DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   181         if (style & WS_VISIBLE) {
   182             window->flags |= SDL_WINDOW_SHOWN;
   183         } else {
   184             window->flags &= ~SDL_WINDOW_SHOWN;
   185         }
   186         if (style & (WS_BORDER | WS_THICKFRAME)) {
   187             window->flags &= ~SDL_WINDOW_BORDERLESS;
   188         } else {
   189             window->flags |= SDL_WINDOW_BORDERLESS;
   190         }
   191         if (style & WS_THICKFRAME) {
   192             window->flags |= SDL_WINDOW_RESIZABLE;
   193         } else {
   194             window->flags &= ~SDL_WINDOW_RESIZABLE;
   195         }
   196 #ifdef WS_MAXIMIZE
   197         if (style & WS_MAXIMIZE) {
   198             window->flags |= SDL_WINDOW_MAXIMIZED;
   199         } else
   200 #endif
   201         {
   202             window->flags &= ~SDL_WINDOW_MAXIMIZED;
   203         }
   204 #ifdef WS_MINIMIZE
   205         if (style & WS_MINIMIZE) {
   206             window->flags |= SDL_WINDOW_MINIMIZED;
   207         } else
   208 #endif
   209         {
   210             window->flags &= ~SDL_WINDOW_MINIMIZED;
   211         }
   212     }
   213     if (GetFocus() == hwnd) {
   214         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   215         SDL_SetKeyboardFocus(data->window);
   216 
   217         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   218             RECT rect;
   219             GetClientRect(hwnd, &rect);
   220             ClientToScreen(hwnd, (LPPOINT) & rect);
   221             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   222             ClipCursor(&rect);
   223         }
   224     }
   225 
   226     /* Enable multi-touch */
   227     if (videodata->RegisterTouchWindow) {
   228         videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
   229     }
   230 
   231     /* Enable dropping files */
   232     DragAcceptFiles(hwnd, TRUE);
   233 
   234     /* All done! */
   235     return 0;
   236 }
   237 
   238 int
   239 WIN_CreateWindow(_THIS, SDL_Window * window)
   240 {
   241     HWND hwnd;
   242     RECT rect;
   243     DWORD style = STYLE_BASIC;
   244     int x, y;
   245     int w, h;
   246 
   247     style |= GetWindowStyle(window);
   248 
   249     /* Figure out what the window area will be */
   250     rect.left = window->x;
   251     rect.top = window->y;
   252     rect.right = window->x + window->w;
   253     rect.bottom = window->y + window->h;
   254     AdjustWindowRectEx(&rect, style, FALSE, 0);
   255     x = rect.left;
   256     y = rect.top;
   257     w = (rect.right - rect.left);
   258     h = (rect.bottom - rect.top);
   259 
   260     hwnd =
   261         CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
   262                      SDL_Instance, NULL);
   263     if (!hwnd) {
   264         return WIN_SetError("Couldn't create window");
   265     }
   266 
   267     WIN_PumpEvents(_this);
   268 
   269     if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) {
   270         DestroyWindow(hwnd);
   271         return -1;
   272     }
   273 #if SDL_VIDEO_OPENGL_WGL
   274     if (window->flags & SDL_WINDOW_OPENGL) {
   275         if (WIN_GL_SetupWindow(_this, window) < 0) {
   276             WIN_DestroyWindow(_this, window);
   277             return -1;
   278         }
   279     }
   280 #endif
   281     return 0;
   282 }
   283 
   284 int
   285 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   286 {
   287     HWND hwnd = (HWND) data;
   288     LPTSTR title;
   289     int titleLen;
   290 
   291     /* Query the title from the existing window */
   292     titleLen = GetWindowTextLength(hwnd);
   293     title = SDL_stack_alloc(TCHAR, titleLen + 1);
   294     if (title) {
   295         titleLen = GetWindowText(hwnd, title, titleLen);
   296     } else {
   297         titleLen = 0;
   298     }
   299     if (titleLen > 0) {
   300         window->title = WIN_StringToUTF8(title);
   301     }
   302     if (title) {
   303         SDL_stack_free(title);
   304     }
   305 
   306     if (SetupWindowData(_this, window, hwnd, SDL_FALSE) < 0) {
   307         return -1;
   308     }
   309     return 0;
   310 }
   311 
   312 void
   313 WIN_SetWindowTitle(_THIS, SDL_Window * window)
   314 {
   315     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   316     LPTSTR title;
   317 
   318     if (window->title) {
   319         title = WIN_UTF8ToString(window->title);
   320     } else {
   321         title = NULL;
   322     }
   323     SetWindowText(hwnd, title ? title : TEXT(""));
   324     SDL_free(title);
   325 }
   326 
   327 void
   328 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   329 {
   330     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   331     HICON hicon = NULL;
   332     BYTE *icon_bmp;
   333     int icon_len, y;
   334     SDL_RWops *dst;
   335 
   336     /* Create temporary bitmap buffer */
   337     icon_len = 40 + icon->h * icon->w * 4;
   338     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   339     dst = SDL_RWFromMem(icon_bmp, icon_len);
   340     if (!dst) {
   341         SDL_stack_free(icon_bmp);
   342         return;
   343     }
   344 
   345     /* Write the BITMAPINFO header */
   346     SDL_WriteLE32(dst, 40);
   347     SDL_WriteLE32(dst, icon->w);
   348     SDL_WriteLE32(dst, icon->h * 2);
   349     SDL_WriteLE16(dst, 1);
   350     SDL_WriteLE16(dst, 32);
   351     SDL_WriteLE32(dst, BI_RGB);
   352     SDL_WriteLE32(dst, icon->h * icon->w * 4);
   353     SDL_WriteLE32(dst, 0);
   354     SDL_WriteLE32(dst, 0);
   355     SDL_WriteLE32(dst, 0);
   356     SDL_WriteLE32(dst, 0);
   357 
   358     /* Write the pixels upside down into the bitmap buffer */
   359     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   360     y = icon->h;
   361     while (y--) {
   362         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   363         SDL_RWwrite(dst, src, icon->pitch, 1);
   364     }
   365 
   366     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   367 
   368     SDL_RWclose(dst);
   369     SDL_stack_free(icon_bmp);
   370 
   371     /* Set the icon for the window */
   372     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   373 
   374     /* Set the icon in the task manager (should we do this?) */
   375     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   376 }
   377 
   378 void
   379 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   380 {
   381     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   382 }
   383 
   384 void
   385 WIN_SetWindowSize(_THIS, SDL_Window * window)
   386 {
   387     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   388 }
   389 
   390 void
   391 WIN_ShowWindow(_THIS, SDL_Window * window)
   392 {
   393     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   394     ShowWindow(hwnd, SW_SHOW);
   395 }
   396 
   397 void
   398 WIN_HideWindow(_THIS, SDL_Window * window)
   399 {
   400     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   401     ShowWindow(hwnd, SW_HIDE);
   402 }
   403 
   404 void
   405 WIN_RaiseWindow(_THIS, SDL_Window * window)
   406 {
   407     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE);
   408 
   409     /* Raising the window while alt-tabbed can cause it to be minimized for some reason? */
   410     WIN_RestoreWindow(_this, window);
   411 }
   412 
   413 void
   414 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   415 {
   416     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   417     ShowWindow(hwnd, SW_MAXIMIZE);
   418 }
   419 
   420 void
   421 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   422 {
   423     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   424     ShowWindow(hwnd, SW_MINIMIZE);
   425 }
   426 
   427 void
   428 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   429 {
   430     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   431     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   432 
   433     if (bordered) {
   434         style &= ~STYLE_BORDERLESS;
   435         style |= STYLE_NORMAL;
   436     } else {
   437         style &= ~STYLE_NORMAL;
   438         style |= STYLE_BORDERLESS;
   439     }
   440 
   441     SetWindowLong(hwnd, GWL_STYLE, style);
   442     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOREPOSITION | SWP_NOZORDER |SWP_NOACTIVATE | SWP_NOSENDCHANGING);
   443 }
   444 
   445 void
   446 WIN_RestoreWindow(_THIS, SDL_Window * window)
   447 {
   448     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   449 
   450     ShowWindow(hwnd, SW_RESTORE);
   451 }
   452 
   453 void
   454 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   455 {
   456     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   457     HWND hwnd = data->hwnd;
   458     RECT rect;
   459     SDL_Rect bounds;
   460     DWORD style;
   461     HWND top;
   462     BOOL menu;
   463     int x, y;
   464     int w, h;
   465 
   466     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
   467         top = HWND_TOPMOST;
   468     } else {
   469         top = HWND_NOTOPMOST;
   470     }
   471 
   472     style = GetWindowLong(hwnd, GWL_STYLE);
   473     style &= ~STYLE_MASK;
   474     style |= GetWindowStyle(window);
   475 
   476     WIN_GetDisplayBounds(_this, display, &bounds);
   477 
   478     if (fullscreen) {
   479         x = bounds.x;
   480         y = bounds.y;
   481         w = bounds.w;
   482         h = bounds.h;
   483     } else {
   484         rect.left = 0;
   485         rect.top = 0;
   486         rect.right = window->windowed.w;
   487         rect.bottom = window->windowed.h;
   488         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   489         AdjustWindowRectEx(&rect, style, menu, 0);
   490         w = (rect.right - rect.left);
   491         h = (rect.bottom - rect.top);
   492         x = window->windowed.x + rect.left;
   493         y = window->windowed.y + rect.top;
   494     }
   495     SetWindowLong(hwnd, GWL_STYLE, style);
   496     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS);
   497 }
   498 
   499 int
   500 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   501 {
   502     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   503     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   504     HDC hdc;
   505     BOOL succeeded = FALSE;
   506 
   507     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   508     if (hdc) {
   509         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   510         if (!succeeded) {
   511             WIN_SetError("SetDeviceGammaRamp()");
   512         }
   513         DeleteDC(hdc);
   514     }
   515     return succeeded ? 0 : -1;
   516 }
   517 
   518 int
   519 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   520 {
   521     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   522     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   523     HDC hdc;
   524     BOOL succeeded = FALSE;
   525 
   526     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   527     if (hdc) {
   528         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   529         if (!succeeded) {
   530             WIN_SetError("GetDeviceGammaRamp()");
   531         }
   532         DeleteDC(hdc);
   533     }
   534     return succeeded ? 0 : -1;
   535 }
   536 
   537 void
   538 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   539 {
   540     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   541 
   542     if (grabbed) {
   543         RECT rect;
   544         GetClientRect(hwnd, &rect);
   545         ClientToScreen(hwnd, (LPPOINT) & rect);
   546         ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   547         ClipCursor(&rect);
   548     } else {
   549         ClipCursor(NULL);
   550     }
   551 
   552     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   553         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   554 
   555         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   556             flags |= SWP_NOACTIVATE;
   557         }
   558         WIN_SetWindowPositionInternal(_this, window, flags);
   559     }
   560 }
   561 
   562 void
   563 WIN_DestroyWindow(_THIS, SDL_Window * window)
   564 {
   565     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   566 
   567     if (data) {
   568         ReleaseDC(data->hwnd, data->hdc);
   569         if (data->created) {
   570             DestroyWindow(data->hwnd);
   571         } else {
   572             /* Restore any original event handler... */
   573             if (data->wndproc != NULL) {
   574 #ifdef GWLP_WNDPROC
   575                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   576                                  (LONG_PTR) data->wndproc);
   577 #else
   578                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   579                               (LONG_PTR) data->wndproc);
   580 #endif
   581             }
   582         }
   583         SDL_free(data);
   584     }
   585 }
   586 
   587 SDL_bool
   588 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   589 {
   590     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   591     if (info->version.major <= SDL_MAJOR_VERSION) {
   592         info->subsystem = SDL_SYSWM_WINDOWS;
   593         info->info.win.window = hwnd;
   594         return SDL_TRUE;
   595     } else {
   596         SDL_SetError("Application not compiled with SDL %d.%d\n",
   597                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   598         return SDL_FALSE;
   599     }
   600 }
   601 
   602 
   603 /*
   604  * Creates a HelperWindow used for DirectInput events.
   605  */
   606 int
   607 SDL_HelperWindowCreate(void)
   608 {
   609     HINSTANCE hInstance = GetModuleHandle(NULL);
   610     WNDCLASS wce;
   611 
   612     /* Make sure window isn't created twice. */
   613     if (SDL_HelperWindow != NULL) {
   614         return 0;
   615     }
   616 
   617     /* Create the class. */
   618     SDL_zero(wce);
   619     wce.lpfnWndProc = DefWindowProc;
   620     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   621     wce.hInstance = hInstance;
   622 
   623     /* Register the class. */
   624     SDL_HelperWindowClass = RegisterClass(&wce);
   625     if (SDL_HelperWindowClass == 0) {
   626         return WIN_SetError("Unable to create Helper Window Class");
   627     }
   628 
   629     /* Create the window. */
   630     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   631                                       SDL_HelperWindowName,
   632                                       WS_OVERLAPPED, CW_USEDEFAULT,
   633                                       CW_USEDEFAULT, CW_USEDEFAULT,
   634                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   635                                       hInstance, NULL);
   636     if (SDL_HelperWindow == NULL) {
   637         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   638         return WIN_SetError("Unable to create Helper Window");
   639     }
   640 
   641     return 0;
   642 }
   643 
   644 
   645 /*
   646  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   647  */
   648 void
   649 SDL_HelperWindowDestroy(void)
   650 {
   651     HINSTANCE hInstance = GetModuleHandle(NULL);
   652 
   653     /* Destroy the window. */
   654     if (SDL_HelperWindow != NULL) {
   655         if (DestroyWindow(SDL_HelperWindow) == 0) {
   656             WIN_SetError("Unable to destroy Helper Window");
   657             return;
   658         }
   659         SDL_HelperWindow = NULL;
   660     }
   661 
   662     /* Unregister the class. */
   663     if (SDL_HelperWindowClass != 0) {
   664         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   665             WIN_SetError("Unable to destroy Helper Window Class");
   666             return;
   667         }
   668         SDL_HelperWindowClass = 0;
   669     }
   670 }
   671 
   672 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   673 {
   674 #ifdef WM_MOUSELEAVE
   675     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   676     TRACKMOUSEEVENT trackMouseEvent;
   677 
   678     if (!data || !data->hwnd) {
   679         /* The window wasn't fully initialized */
   680         return;
   681     }
   682 
   683     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   684     trackMouseEvent.dwFlags = TME_LEAVE;
   685     trackMouseEvent.hwndTrack = data->hwnd;
   686 
   687     TrackMouseEvent(&trackMouseEvent);
   688 #endif /* WM_MOUSELEAVE */
   689 }
   690 
   691 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   692 
   693 /* vi: set ts=4 sw=4 expandtab: */