src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 28 May 2015 08:51:59 -0700
changeset 9665 8d24b4bfa3dd
parent 9664 42ab66d97cc1
child 9886 adb374e144d6
permissions -rw-r--r--
Fixed Windows build
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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         RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
   619         if (data->created) {
   620             DestroyWindow(data->hwnd);
   621         } else {
   622             /* Restore any original event handler... */
   623             if (data->wndproc != NULL) {
   624 #ifdef GWLP_WNDPROC
   625                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   626                                  (LONG_PTR) data->wndproc);
   627 #else
   628                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   629                               (LONG_PTR) data->wndproc);
   630 #endif
   631             }
   632         }
   633         SDL_free(data);
   634     }
   635     window->driverdata = NULL;
   636 }
   637 
   638 SDL_bool
   639 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   640 {
   641     const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
   642     if (info->version.major <= SDL_MAJOR_VERSION) {
   643         info->subsystem = SDL_SYSWM_WINDOWS;
   644         info->info.win.window = data->hwnd;
   645         info->info.win.hdc = data->hdc;
   646         return SDL_TRUE;
   647     } else {
   648         SDL_SetError("Application not compiled with SDL %d.%d\n",
   649                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   650         return SDL_FALSE;
   651     }
   652 }
   653 
   654 
   655 /*
   656  * Creates a HelperWindow used for DirectInput events.
   657  */
   658 int
   659 SDL_HelperWindowCreate(void)
   660 {
   661     HINSTANCE hInstance = GetModuleHandle(NULL);
   662     WNDCLASS wce;
   663 
   664     /* Make sure window isn't created twice. */
   665     if (SDL_HelperWindow != NULL) {
   666         return 0;
   667     }
   668 
   669     /* Create the class. */
   670     SDL_zero(wce);
   671     wce.lpfnWndProc = DefWindowProc;
   672     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   673     wce.hInstance = hInstance;
   674 
   675     /* Register the class. */
   676     SDL_HelperWindowClass = RegisterClass(&wce);
   677     if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
   678         return WIN_SetError("Unable to create Helper Window Class");
   679     }
   680 
   681     /* Create the window. */
   682     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   683                                       SDL_HelperWindowName,
   684                                       WS_OVERLAPPED, CW_USEDEFAULT,
   685                                       CW_USEDEFAULT, CW_USEDEFAULT,
   686                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   687                                       hInstance, NULL);
   688     if (SDL_HelperWindow == NULL) {
   689         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   690         return WIN_SetError("Unable to create Helper Window");
   691     }
   692 
   693     return 0;
   694 }
   695 
   696 
   697 /*
   698  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   699  */
   700 void
   701 SDL_HelperWindowDestroy(void)
   702 {
   703     HINSTANCE hInstance = GetModuleHandle(NULL);
   704 
   705     /* Destroy the window. */
   706     if (SDL_HelperWindow != NULL) {
   707         if (DestroyWindow(SDL_HelperWindow) == 0) {
   708             WIN_SetError("Unable to destroy Helper Window");
   709             return;
   710         }
   711         SDL_HelperWindow = NULL;
   712     }
   713 
   714     /* Unregister the class. */
   715     if (SDL_HelperWindowClass != 0) {
   716         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   717             WIN_SetError("Unable to destroy Helper Window Class");
   718             return;
   719         }
   720         SDL_HelperWindowClass = 0;
   721     }
   722 }
   723 
   724 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   725 {
   726 #ifdef WM_MOUSELEAVE
   727     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   728     TRACKMOUSEEVENT trackMouseEvent;
   729 
   730     if (!data || !data->hwnd) {
   731         /* The window wasn't fully initialized */
   732         return;
   733     }
   734 
   735     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   736     trackMouseEvent.dwFlags = TME_LEAVE;
   737     trackMouseEvent.hwndTrack = data->hwnd;
   738 
   739     TrackMouseEvent(&trackMouseEvent);
   740 #endif /* WM_MOUSELEAVE */
   741 }
   742 
   743 void
   744 WIN_UpdateClipCursor(SDL_Window *window)
   745 {
   746     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   747     SDL_Mouse *mouse = SDL_GetMouse();
   748 
   749     if (data->focus_click_pending) {
   750         return;
   751     }
   752 
   753     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   754         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   755         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   756             LONG cx, cy;
   757             RECT rect;
   758             GetWindowRect(data->hwnd, &rect);
   759 
   760             cx = (rect.left + rect.right) / 2;
   761             cy = (rect.top + rect.bottom) / 2;
   762 
   763             /* Make an absurdly small clip rect */
   764             rect.left = cx - 1;
   765             rect.right = cx + 1;
   766             rect.top = cy - 1;
   767             rect.bottom = cy + 1;
   768 
   769             ClipCursor(&rect);
   770         } else {
   771             RECT rect;
   772             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   773                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   774                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   775                 ClipCursor(&rect);
   776             }
   777         }
   778     } else {
   779         ClipCursor(NULL);
   780     }
   781 }
   782 
   783 int
   784 WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   785 {
   786     return 0;  /* just succeed, the real work is done elsewhere. */
   787 }
   788 
   789 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   790 
   791 /* vi: set ts=4 sw=4 expandtab: */