src/video/windows/SDL_windowswindow.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 08 Apr 2015 02:00:14 -0400
changeset 9474 067b78126485
parent 9422 286c854c1d5b
child 9619 b94b6d0bff0f
permissions -rw-r--r--
SDL_SetWindowTitle() should never set a NULL pointer for the title string.

Various backends reacted differently (or not at all) in the presence of a
NULL pointer. This simplifies things.

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