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