src/video/windows/SDL_windowswindow.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 25 Jun 2014 17:06:12 -0400
changeset 8953 dc80dc0bd22e
parent 8916 96d944f74851
parent 8938 c73bac338b90
child 8978 7753e4fd3d1d
permissions -rw-r--r--
Merged Ryan's SDL-gui-backend branch.

Adds three APIs, and implements them on X11, Cocoa, and Windows:

- SDL_CaptureMouse()
- SDL_GetGlobalMouseState()
- SDL_SetWindowHitTest()
     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;
   375 
   376     if (window->title) {
   377         title = WIN_UTF8ToString(window->title);
   378     } else {
   379         title = NULL;
   380     }
   381     SetWindowText(hwnd, title ? title : TEXT(""));
   382     SDL_free(title);
   383 }
   384 
   385 void
   386 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   387 {
   388     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   389     HICON hicon = NULL;
   390     BYTE *icon_bmp;
   391     int icon_len, y;
   392     SDL_RWops *dst;
   393 
   394     /* Create temporary bitmap buffer */
   395     icon_len = 40 + icon->h * icon->w * 4;
   396     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   397     dst = SDL_RWFromMem(icon_bmp, icon_len);
   398     if (!dst) {
   399         SDL_stack_free(icon_bmp);
   400         return;
   401     }
   402 
   403     /* Write the BITMAPINFO header */
   404     SDL_WriteLE32(dst, 40);
   405     SDL_WriteLE32(dst, icon->w);
   406     SDL_WriteLE32(dst, icon->h * 2);
   407     SDL_WriteLE16(dst, 1);
   408     SDL_WriteLE16(dst, 32);
   409     SDL_WriteLE32(dst, BI_RGB);
   410     SDL_WriteLE32(dst, icon->h * icon->w * 4);
   411     SDL_WriteLE32(dst, 0);
   412     SDL_WriteLE32(dst, 0);
   413     SDL_WriteLE32(dst, 0);
   414     SDL_WriteLE32(dst, 0);
   415 
   416     /* Write the pixels upside down into the bitmap buffer */
   417     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   418     y = icon->h;
   419     while (y--) {
   420         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   421         SDL_RWwrite(dst, src, icon->pitch, 1);
   422     }
   423 
   424     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   425 
   426     SDL_RWclose(dst);
   427     SDL_stack_free(icon_bmp);
   428 
   429     /* Set the icon for the window */
   430     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   431 
   432     /* Set the icon in the task manager (should we do this?) */
   433     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   434 }
   435 
   436 void
   437 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   438 {
   439     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   440 }
   441 
   442 void
   443 WIN_SetWindowSize(_THIS, SDL_Window * window)
   444 {
   445     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   446 }
   447 
   448 void
   449 WIN_ShowWindow(_THIS, SDL_Window * window)
   450 {
   451     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   452     ShowWindow(hwnd, SW_SHOW);
   453 }
   454 
   455 void
   456 WIN_HideWindow(_THIS, SDL_Window * window)
   457 {
   458     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   459     ShowWindow(hwnd, SW_HIDE);
   460 }
   461 
   462 void
   463 WIN_RaiseWindow(_THIS, SDL_Window * window)
   464 {
   465     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE);
   466 }
   467 
   468 void
   469 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   470 {
   471     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   472     HWND hwnd = data->hwnd;
   473     data->expected_resize = SDL_TRUE;
   474     ShowWindow(hwnd, SW_MAXIMIZE);
   475     data->expected_resize = SDL_FALSE;
   476 }
   477 
   478 void
   479 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   480 {
   481     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   482     ShowWindow(hwnd, SW_MINIMIZE);
   483 }
   484 
   485 void
   486 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   487 {
   488     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   489     HWND hwnd = data->hwnd;
   490     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   491 
   492     if (bordered) {
   493         style &= ~STYLE_BORDERLESS;
   494         style |= STYLE_NORMAL;
   495     } else {
   496         style &= ~STYLE_NORMAL;
   497         style |= STYLE_BORDERLESS;
   498     }
   499 
   500     data->in_border_change = SDL_TRUE;
   501     SetWindowLong( hwnd, GWL_STYLE, style );
   502     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
   503     data->in_border_change = SDL_FALSE;
   504 }
   505 
   506 void
   507 WIN_RestoreWindow(_THIS, SDL_Window * window)
   508 {
   509     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   510     HWND hwnd = data->hwnd;
   511     data->expected_resize = SDL_TRUE;
   512     ShowWindow(hwnd, SW_RESTORE);
   513     data->expected_resize = SDL_FALSE;
   514 }
   515 
   516 void
   517 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   518 {
   519     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   520     HWND hwnd = data->hwnd;
   521     RECT rect;
   522     SDL_Rect bounds;
   523     DWORD style;
   524     HWND top;
   525     BOOL menu;
   526     int x, y;
   527     int w, h;
   528 
   529     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
   530         top = HWND_TOPMOST;
   531     } else {
   532         top = HWND_NOTOPMOST;
   533     }
   534 
   535     style = GetWindowLong(hwnd, GWL_STYLE);
   536     style &= ~STYLE_MASK;
   537     style |= GetWindowStyle(window);
   538 
   539     WIN_GetDisplayBounds(_this, display, &bounds);
   540 
   541     if (fullscreen) {
   542         x = bounds.x;
   543         y = bounds.y;
   544         w = bounds.w;
   545         h = bounds.h;
   546     } else {
   547         rect.left = 0;
   548         rect.top = 0;
   549         rect.right = window->windowed.w;
   550         rect.bottom = window->windowed.h;
   551         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   552         AdjustWindowRectEx(&rect, style, menu, 0);
   553         w = (rect.right - rect.left);
   554         h = (rect.bottom - rect.top);
   555         x = window->windowed.x + rect.left;
   556         y = window->windowed.y + rect.top;
   557     }
   558     SetWindowLong(hwnd, GWL_STYLE, style);
   559     data->expected_resize = SDL_TRUE;
   560     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
   561     data->expected_resize = SDL_FALSE;
   562 }
   563 
   564 int
   565 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   566 {
   567     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   568     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   569     HDC hdc;
   570     BOOL succeeded = FALSE;
   571 
   572     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   573     if (hdc) {
   574         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   575         if (!succeeded) {
   576             WIN_SetError("SetDeviceGammaRamp()");
   577         }
   578         DeleteDC(hdc);
   579     }
   580     return succeeded ? 0 : -1;
   581 }
   582 
   583 int
   584 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   585 {
   586     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   587     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   588     HDC hdc;
   589     BOOL succeeded = FALSE;
   590 
   591     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   592     if (hdc) {
   593         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   594         if (!succeeded) {
   595             WIN_SetError("GetDeviceGammaRamp()");
   596         }
   597         DeleteDC(hdc);
   598     }
   599     return succeeded ? 0 : -1;
   600 }
   601 
   602 void
   603 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   604 {
   605     WIN_UpdateClipCursor(window);
   606 
   607     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   608         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   609 
   610         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   611             flags |= SWP_NOACTIVATE;
   612         }
   613         WIN_SetWindowPositionInternal(_this, window, flags);
   614     }
   615 }
   616 
   617 void
   618 WIN_DestroyWindow(_THIS, SDL_Window * window)
   619 {
   620     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   621 
   622     window->driverdata = NULL;
   623 
   624     if (data) {
   625         ReleaseDC(data->hwnd, data->hdc);
   626         if (data->created) {
   627             DestroyWindow(data->hwnd);
   628         } else {
   629             /* Restore any original event handler... */
   630             if (data->wndproc != NULL) {
   631 #ifdef GWLP_WNDPROC
   632                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   633                                  (LONG_PTR) data->wndproc);
   634 #else
   635                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   636                               (LONG_PTR) data->wndproc);
   637 #endif
   638             }
   639         }
   640         SDL_free(data);
   641     }
   642 }
   643 
   644 SDL_bool
   645 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   646 {
   647     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   648     if (info->version.major <= SDL_MAJOR_VERSION) {
   649         info->subsystem = SDL_SYSWM_WINDOWS;
   650         info->info.win.window = hwnd;
   651         return SDL_TRUE;
   652     } else {
   653         SDL_SetError("Application not compiled with SDL %d.%d\n",
   654                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   655         return SDL_FALSE;
   656     }
   657 }
   658 
   659 
   660 /*
   661  * Creates a HelperWindow used for DirectInput events.
   662  */
   663 int
   664 SDL_HelperWindowCreate(void)
   665 {
   666     HINSTANCE hInstance = GetModuleHandle(NULL);
   667     WNDCLASS wce;
   668 
   669     /* Make sure window isn't created twice. */
   670     if (SDL_HelperWindow != NULL) {
   671         return 0;
   672     }
   673 
   674     /* Create the class. */
   675     SDL_zero(wce);
   676     wce.lpfnWndProc = DefWindowProc;
   677     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   678     wce.hInstance = hInstance;
   679 
   680     /* Register the class. */
   681     SDL_HelperWindowClass = RegisterClass(&wce);
   682     if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
   683         return WIN_SetError("Unable to create Helper Window Class");
   684     }
   685 
   686     /* Create the window. */
   687     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   688                                       SDL_HelperWindowName,
   689                                       WS_OVERLAPPED, CW_USEDEFAULT,
   690                                       CW_USEDEFAULT, CW_USEDEFAULT,
   691                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   692                                       hInstance, NULL);
   693     if (SDL_HelperWindow == NULL) {
   694         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   695         return WIN_SetError("Unable to create Helper Window");
   696     }
   697 
   698     return 0;
   699 }
   700 
   701 
   702 /*
   703  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   704  */
   705 void
   706 SDL_HelperWindowDestroy(void)
   707 {
   708     HINSTANCE hInstance = GetModuleHandle(NULL);
   709 
   710     /* Destroy the window. */
   711     if (SDL_HelperWindow != NULL) {
   712         if (DestroyWindow(SDL_HelperWindow) == 0) {
   713             WIN_SetError("Unable to destroy Helper Window");
   714             return;
   715         }
   716         SDL_HelperWindow = NULL;
   717     }
   718 
   719     /* Unregister the class. */
   720     if (SDL_HelperWindowClass != 0) {
   721         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   722             WIN_SetError("Unable to destroy Helper Window Class");
   723             return;
   724         }
   725         SDL_HelperWindowClass = 0;
   726     }
   727 }
   728 
   729 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   730 {
   731 #ifdef WM_MOUSELEAVE
   732     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   733     TRACKMOUSEEVENT trackMouseEvent;
   734 
   735     if (!data || !data->hwnd) {
   736         /* The window wasn't fully initialized */
   737         return;
   738     }
   739 
   740     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   741     trackMouseEvent.dwFlags = TME_LEAVE;
   742     trackMouseEvent.hwndTrack = data->hwnd;
   743 
   744     TrackMouseEvent(&trackMouseEvent);
   745 #endif /* WM_MOUSELEAVE */
   746 }
   747 
   748 void
   749 WIN_UpdateClipCursor(SDL_Window *window)
   750 {
   751     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   752     SDL_Mouse *mouse = SDL_GetMouse();
   753 
   754     if (data->focus_click_pending) {
   755         return;
   756     }
   757 
   758     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   759         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   760         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   761             LONG cx, cy;
   762             RECT rect;
   763             GetWindowRect(data->hwnd, &rect);
   764 
   765             cx = (rect.left + rect.right) / 2;
   766             cy = (rect.top + rect.bottom) / 2;
   767 
   768             /* Make an absurdly small clip rect */
   769             rect.left = cx - 1;
   770             rect.right = cx + 1;
   771             rect.top = cy - 1;
   772             rect.bottom = cy + 1;
   773 
   774             ClipCursor(&rect);
   775         } else {
   776             RECT rect;
   777             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   778                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   779                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   780                 ClipCursor(&rect);
   781             }
   782         }
   783     } else {
   784         ClipCursor(NULL);
   785     }
   786 }
   787 
   788 int
   789 WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   790 {
   791     return 0;  /* just succeed, the real work is done elsewhere. */
   792 }
   793 
   794 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   795 
   796 /* vi: set ts=4 sw=4 expandtab: */