src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 24 Feb 2014 22:49:30 -0800
changeset 8253 75ad8ebb3768
parent 8238 9e09e1561e00
child 8778 d67a044fbec6
permissions -rw-r--r--
Make sure we don't clip the cursor while clicking on the window title bar
     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 = TRUE;
   112     SetWindowPos(hwnd, top, x, y, w, h, flags);
   113     data->expected_resize = 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             SDL_Window *otherWindow = NULL;
   349             SDL_sscanf(hint, "%p", (void**)&otherWindow);
   350 
   351             // Do some error checking on the pointer
   352             if (otherWindow != NULL && otherWindow->magic == &_this->window_magic)
   353             {
   354                 // If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well
   355                 if (otherWindow->flags & SDL_WINDOW_OPENGL)
   356                 {
   357                     window->flags |= SDL_WINDOW_OPENGL;
   358                     if(!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
   359                         return -1;
   360                     }
   361                 }
   362             }
   363         }
   364     }
   365 #endif
   366     return 0;
   367 }
   368 
   369 void
   370 WIN_SetWindowTitle(_THIS, SDL_Window * window)
   371 {
   372     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   373     LPTSTR title;
   374 
   375     if (window->title) {
   376         title = WIN_UTF8ToString(window->title);
   377     } else {
   378         title = NULL;
   379     }
   380     SetWindowText(hwnd, title ? title : TEXT(""));
   381     SDL_free(title);
   382 }
   383 
   384 void
   385 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   386 {
   387     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   388     HICON hicon = NULL;
   389     BYTE *icon_bmp;
   390     int icon_len, y;
   391     SDL_RWops *dst;
   392 
   393     /* Create temporary bitmap buffer */
   394     icon_len = 40 + icon->h * icon->w * 4;
   395     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   396     dst = SDL_RWFromMem(icon_bmp, icon_len);
   397     if (!dst) {
   398         SDL_stack_free(icon_bmp);
   399         return;
   400     }
   401 
   402     /* Write the BITMAPINFO header */
   403     SDL_WriteLE32(dst, 40);
   404     SDL_WriteLE32(dst, icon->w);
   405     SDL_WriteLE32(dst, icon->h * 2);
   406     SDL_WriteLE16(dst, 1);
   407     SDL_WriteLE16(dst, 32);
   408     SDL_WriteLE32(dst, BI_RGB);
   409     SDL_WriteLE32(dst, icon->h * icon->w * 4);
   410     SDL_WriteLE32(dst, 0);
   411     SDL_WriteLE32(dst, 0);
   412     SDL_WriteLE32(dst, 0);
   413     SDL_WriteLE32(dst, 0);
   414 
   415     /* Write the pixels upside down into the bitmap buffer */
   416     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   417     y = icon->h;
   418     while (y--) {
   419         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   420         SDL_RWwrite(dst, src, icon->pitch, 1);
   421     }
   422 
   423     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   424 
   425     SDL_RWclose(dst);
   426     SDL_stack_free(icon_bmp);
   427 
   428     /* Set the icon for the window */
   429     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   430 
   431     /* Set the icon in the task manager (should we do this?) */
   432     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   433 }
   434 
   435 void
   436 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   437 {
   438     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   439 }
   440 
   441 void
   442 WIN_SetWindowSize(_THIS, SDL_Window * window)
   443 {
   444     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   445 }
   446 
   447 void
   448 WIN_ShowWindow(_THIS, SDL_Window * window)
   449 {
   450     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   451     ShowWindow(hwnd, SW_SHOW);
   452 }
   453 
   454 void
   455 WIN_HideWindow(_THIS, SDL_Window * window)
   456 {
   457     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   458     ShowWindow(hwnd, SW_HIDE);
   459 }
   460 
   461 void
   462 WIN_RaiseWindow(_THIS, SDL_Window * window)
   463 {
   464     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE);
   465 }
   466 
   467 void
   468 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   469 {
   470     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   471     HWND hwnd = data->hwnd;
   472     data->expected_resize = TRUE;
   473     ShowWindow(hwnd, SW_MAXIMIZE);
   474     data->expected_resize = FALSE;
   475 }
   476 
   477 void
   478 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   479 {
   480     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   481     ShowWindow(hwnd, SW_MINIMIZE);
   482 }
   483 
   484 void
   485 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   486 {
   487     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   488     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   489 
   490     if (bordered) {
   491         style &= ~STYLE_BORDERLESS;
   492         style |= STYLE_NORMAL;
   493     } else {
   494         style &= ~STYLE_NORMAL;
   495         style |= STYLE_BORDERLESS;
   496     }
   497 
   498     SetWindowLong(hwnd, GWL_STYLE, style);
   499     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOREPOSITION | SWP_NOZORDER |SWP_NOACTIVATE | SWP_NOSENDCHANGING);
   500 }
   501 
   502 void
   503 WIN_RestoreWindow(_THIS, SDL_Window * window)
   504 {
   505     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   506     HWND hwnd = data->hwnd;
   507     data->expected_resize = TRUE;
   508     ShowWindow(hwnd, SW_RESTORE);
   509     data->expected_resize = FALSE;
   510 }
   511 
   512 void
   513 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   514 {
   515     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   516     HWND hwnd = data->hwnd;
   517     RECT rect;
   518     SDL_Rect bounds;
   519     DWORD style;
   520     HWND top;
   521     BOOL menu;
   522     int x, y;
   523     int w, h;
   524 
   525     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
   526         top = HWND_TOPMOST;
   527     } else {
   528         top = HWND_NOTOPMOST;
   529     }
   530 
   531     style = GetWindowLong(hwnd, GWL_STYLE);
   532     style &= ~STYLE_MASK;
   533     style |= GetWindowStyle(window);
   534 
   535     WIN_GetDisplayBounds(_this, display, &bounds);
   536 
   537     if (fullscreen) {
   538         x = bounds.x;
   539         y = bounds.y;
   540         w = bounds.w;
   541         h = bounds.h;
   542     } else {
   543         rect.left = 0;
   544         rect.top = 0;
   545         rect.right = window->windowed.w;
   546         rect.bottom = window->windowed.h;
   547         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   548         AdjustWindowRectEx(&rect, style, menu, 0);
   549         w = (rect.right - rect.left);
   550         h = (rect.bottom - rect.top);
   551         x = window->windowed.x + rect.left;
   552         y = window->windowed.y + rect.top;
   553     }
   554     SetWindowLong(hwnd, GWL_STYLE, style);
   555     data->expected_resize = TRUE;
   556     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
   557     data->expected_resize = FALSE;
   558 }
   559 
   560 int
   561 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   562 {
   563     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   564     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   565     HDC hdc;
   566     BOOL succeeded = FALSE;
   567 
   568     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   569     if (hdc) {
   570         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   571         if (!succeeded) {
   572             WIN_SetError("SetDeviceGammaRamp()");
   573         }
   574         DeleteDC(hdc);
   575     }
   576     return succeeded ? 0 : -1;
   577 }
   578 
   579 int
   580 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   581 {
   582     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   583     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   584     HDC hdc;
   585     BOOL succeeded = FALSE;
   586 
   587     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   588     if (hdc) {
   589         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   590         if (!succeeded) {
   591             WIN_SetError("GetDeviceGammaRamp()");
   592         }
   593         DeleteDC(hdc);
   594     }
   595     return succeeded ? 0 : -1;
   596 }
   597 
   598 void
   599 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   600 {
   601     WIN_UpdateClipCursor(window);
   602 
   603     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   604         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   605 
   606         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   607             flags |= SWP_NOACTIVATE;
   608         }
   609         WIN_SetWindowPositionInternal(_this, window, flags);
   610     }
   611 }
   612 
   613 void
   614 WIN_DestroyWindow(_THIS, SDL_Window * window)
   615 {
   616     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   617 
   618     if (data) {
   619         ReleaseDC(data->hwnd, data->hdc);
   620         if (data->created) {
   621             DestroyWindow(data->hwnd);
   622         } else {
   623             /* Restore any original event handler... */
   624             if (data->wndproc != NULL) {
   625 #ifdef GWLP_WNDPROC
   626                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   627                                  (LONG_PTR) data->wndproc);
   628 #else
   629                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   630                               (LONG_PTR) data->wndproc);
   631 #endif
   632             }
   633         }
   634         SDL_free(data);
   635     }
   636 }
   637 
   638 SDL_bool
   639 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   640 {
   641     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   642     if (info->version.major <= SDL_MAJOR_VERSION) {
   643         info->subsystem = SDL_SYSWM_WINDOWS;
   644         info->info.win.window = hwnd;
   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     /* Don't clip the cursor while we're in the modal resize or move loop */
   749     if (data->in_title_click || data->in_modal_loop) {
   750         ClipCursor(NULL);
   751         return;
   752     }
   753 
   754     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   755         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   756         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   757             LONG cx, cy;
   758             RECT rect;
   759             GetWindowRect(data->hwnd, &rect);
   760 
   761             cx = (rect.left + rect.right) / 2;
   762             cy = (rect.top + rect.bottom) / 2;
   763 
   764             /* Make an absurdly small clip rect */
   765             rect.left = cx - 1;
   766             rect.right = cx + 1;
   767             rect.top = cy - 1;
   768             rect.bottom = cy + 1;
   769 
   770             ClipCursor(&rect);
   771         } else {
   772             RECT rect;
   773             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   774                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   775                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   776                 ClipCursor(&rect);
   777             }
   778         }
   779     } else {
   780         ClipCursor(NULL);
   781     }
   782 }
   783 
   784 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   785 
   786 /* vi: set ts=4 sw=4 expandtab: */