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