src/video/windows/SDL_windowswindow.c
author Sam Lantinga
Fri, 27 Jan 2017 06:05:50 -0800
changeset 10856 486aa38c6a88
parent 10816 c8d44526965e
child 10945 1300a3135d61
permissions -rw-r--r--
Added Thrustmaster Wheel FFB entry to the list of wheels
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
   131     data->created = created;
   132     data->mouse_button_flags = 0;
   133     data->videodata = videodata;
   134     data->initializing = SDL_TRUE;
   135 
   136     window->driverdata = data;
   137 
   138     /* Associate the data with the window */
   139     if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
   140         ReleaseDC(hwnd, data->hdc);
   141         SDL_free(data);
   142         return WIN_SetError("SetProp() failed");
   143     }
   144 
   145     /* Set up the window proc function */
   146 #ifdef GWLP_WNDPROC
   147     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
   148     if (data->wndproc == WIN_WindowProc) {
   149         data->wndproc = NULL;
   150     } else {
   151         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
   152     }
   153 #else
   154     data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
   155     if (data->wndproc == WIN_WindowProc) {
   156         data->wndproc = NULL;
   157     } else {
   158         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
   159     }
   160 #endif
   161 
   162     /* Fill in the SDL window with the window data */
   163     {
   164         RECT rect;
   165         if (GetClientRect(hwnd, &rect)) {
   166             int w = rect.right;
   167             int h = rect.bottom;
   168             if ((window->w && window->w != w) || (window->h && window->h != h)) {
   169                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
   170                 RECT rect;
   171                 DWORD style;
   172                 BOOL menu;
   173                 int x, y;
   174                 int w, h;
   175 
   176                 /* Figure out what the window area will be */
   177                 style = GetWindowLong(hwnd, GWL_STYLE);
   178                 rect.left = 0;
   179                 rect.top = 0;
   180                 rect.right = window->w;
   181                 rect.bottom = window->h;
   182                 menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   183                 AdjustWindowRectEx(&rect, style, menu, 0);
   184                 w = (rect.right - rect.left);
   185                 h = (rect.bottom - rect.top);
   186                 x = window->x + rect.left;
   187                 y = window->y + rect.top;
   188 
   189                 SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
   190             } else {
   191                 window->w = w;
   192                 window->h = h;
   193             }
   194         }
   195     }
   196     {
   197         POINT point;
   198         point.x = 0;
   199         point.y = 0;
   200         if (ClientToScreen(hwnd, &point)) {
   201             window->x = point.x;
   202             window->y = point.y;
   203         }
   204     }
   205     {
   206         DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   207         if (style & WS_VISIBLE) {
   208             window->flags |= SDL_WINDOW_SHOWN;
   209         } else {
   210             window->flags &= ~SDL_WINDOW_SHOWN;
   211         }
   212         if (style & (WS_BORDER | WS_THICKFRAME)) {
   213             window->flags &= ~SDL_WINDOW_BORDERLESS;
   214         } else {
   215             window->flags |= SDL_WINDOW_BORDERLESS;
   216         }
   217         if (style & WS_THICKFRAME) {
   218             window->flags |= SDL_WINDOW_RESIZABLE;
   219         } else {
   220             window->flags &= ~SDL_WINDOW_RESIZABLE;
   221         }
   222 #ifdef WS_MAXIMIZE
   223         if (style & WS_MAXIMIZE) {
   224             window->flags |= SDL_WINDOW_MAXIMIZED;
   225         } else
   226 #endif
   227         {
   228             window->flags &= ~SDL_WINDOW_MAXIMIZED;
   229         }
   230 #ifdef WS_MINIMIZE
   231         if (style & WS_MINIMIZE) {
   232             window->flags |= SDL_WINDOW_MINIMIZED;
   233         } else
   234 #endif
   235         {
   236             window->flags &= ~SDL_WINDOW_MINIMIZED;
   237         }
   238     }
   239     if (GetFocus() == hwnd) {
   240         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   241         SDL_SetKeyboardFocus(data->window);
   242 
   243         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   244             RECT rect;
   245             GetClientRect(hwnd, &rect);
   246             ClientToScreen(hwnd, (LPPOINT) & rect);
   247             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   248             ClipCursor(&rect);
   249         }
   250     }
   251 
   252     /* Enable multi-touch */
   253     if (videodata->RegisterTouchWindow) {
   254         videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
   255     }
   256 
   257     /* Enable dropping files */
   258     DragAcceptFiles(hwnd, TRUE);
   259 
   260     data->initializing = SDL_FALSE;
   261 
   262     /* All done! */
   263     return 0;
   264 }
   265 
   266 
   267 
   268 int
   269 WIN_CreateWindow(_THIS, SDL_Window * window)
   270 {
   271     HWND hwnd;
   272     RECT rect;
   273     DWORD style = STYLE_BASIC;
   274     int x, y;
   275     int w, h;
   276 
   277     style |= GetWindowStyle(window);
   278 
   279     /* Figure out what the window area will be */
   280     rect.left = window->x;
   281     rect.top = window->y;
   282     rect.right = window->x + window->w;
   283     rect.bottom = window->y + window->h;
   284     AdjustWindowRectEx(&rect, style, FALSE, 0);
   285     x = rect.left;
   286     y = rect.top;
   287     w = (rect.right - rect.left);
   288     h = (rect.bottom - rect.top);
   289 
   290     hwnd =
   291         CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, NULL, NULL,
   292                      SDL_Instance, NULL);
   293     if (!hwnd) {
   294         return WIN_SetError("Couldn't create window");
   295     }
   296 
   297     WIN_PumpEvents(_this);
   298 
   299     if (SetupWindowData(_this, window, hwnd, SDL_TRUE) < 0) {
   300         DestroyWindow(hwnd);
   301         return -1;
   302     }
   303 
   304     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   305         return 0;
   306     }
   307 
   308     /* The rest of this macro mess is for OpenGL or OpenGL ES windows */
   309 #if SDL_VIDEO_OPENGL_ES2
   310     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   311 #if SDL_VIDEO_OPENGL_WGL
   312         && (!_this->gl_data || WIN_GL_UseEGL(_this))
   313 #endif /* SDL_VIDEO_OPENGL_WGL */
   314     ) {
   315 #if SDL_VIDEO_OPENGL_EGL
   316         if (WIN_GLES_SetupWindow(_this, window) < 0) {
   317             WIN_DestroyWindow(_this, window);
   318             return -1;
   319         }
   320         return 0;
   321 #else
   322         return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
   323 #endif /* SDL_VIDEO_OPENGL_EGL */ 
   324     }
   325 #endif /* SDL_VIDEO_OPENGL_ES2 */
   326 
   327 #if SDL_VIDEO_OPENGL_WGL
   328     if (WIN_GL_SetupWindow(_this, window) < 0) {
   329         WIN_DestroyWindow(_this, window);
   330         return -1;
   331     }
   332 #else
   333     return SDL_SetError("Could not create GL window (WGL support not configured)");
   334 #endif
   335 
   336     return 0;
   337 }
   338 
   339 int
   340 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   341 {
   342     HWND hwnd = (HWND) data;
   343     LPTSTR title;
   344     int titleLen;
   345 
   346     /* Query the title from the existing window */
   347     titleLen = GetWindowTextLength(hwnd);
   348     title = SDL_stack_alloc(TCHAR, titleLen + 1);
   349     if (title) {
   350         titleLen = GetWindowText(hwnd, title, titleLen);
   351     } else {
   352         titleLen = 0;
   353     }
   354     if (titleLen > 0) {
   355         window->title = WIN_StringToUTF8(title);
   356     }
   357     if (title) {
   358         SDL_stack_free(title);
   359     }
   360 
   361     if (SetupWindowData(_this, window, hwnd, SDL_FALSE) < 0) {
   362         return -1;
   363     }
   364 
   365 #if SDL_VIDEO_OPENGL_WGL
   366     {
   367         const char *hint = SDL_GetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT);
   368         if (hint) {
   369             /* This hint is a pointer (in string form) of the address of
   370                the window to share a pixel format with
   371             */
   372             SDL_Window *otherWindow = NULL;
   373             SDL_sscanf(hint, "%p", (void**)&otherWindow);
   374 
   375             /* Do some error checking on the pointer */
   376             if (otherWindow != NULL && otherWindow->magic == &_this->window_magic)
   377             {
   378                 /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
   379                 if (otherWindow->flags & SDL_WINDOW_OPENGL)
   380                 {
   381                     window->flags |= SDL_WINDOW_OPENGL;
   382                     if(!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
   383                         return -1;
   384                     }
   385                 }
   386             }
   387         }
   388     }
   389 #endif
   390     return 0;
   391 }
   392 
   393 void
   394 WIN_SetWindowTitle(_THIS, SDL_Window * window)
   395 {
   396     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   397     LPTSTR title = WIN_UTF8ToString(window->title);
   398     SetWindowText(hwnd, title);
   399     SDL_free(title);
   400 }
   401 
   402 void
   403 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   404 {
   405     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   406     HICON hicon = NULL;
   407     BYTE *icon_bmp;
   408     int icon_len, y;
   409     SDL_RWops *dst;
   410 
   411     /* Create temporary bitmap buffer */
   412     icon_len = 40 + icon->h * icon->w * sizeof(Uint32);
   413     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   414     dst = SDL_RWFromMem(icon_bmp, icon_len);
   415     if (!dst) {
   416         SDL_stack_free(icon_bmp);
   417         return;
   418     }
   419 
   420     /* Write the BITMAPINFO header */
   421     SDL_WriteLE32(dst, 40);
   422     SDL_WriteLE32(dst, icon->w);
   423     SDL_WriteLE32(dst, icon->h * 2);
   424     SDL_WriteLE16(dst, 1);
   425     SDL_WriteLE16(dst, 32);
   426     SDL_WriteLE32(dst, BI_RGB);
   427     SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32));
   428     SDL_WriteLE32(dst, 0);
   429     SDL_WriteLE32(dst, 0);
   430     SDL_WriteLE32(dst, 0);
   431     SDL_WriteLE32(dst, 0);
   432 
   433     /* Write the pixels upside down into the bitmap buffer */
   434     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   435     y = icon->h;
   436     while (y--) {
   437         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   438         SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1);
   439     }
   440 
   441     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   442 
   443     SDL_RWclose(dst);
   444     SDL_stack_free(icon_bmp);
   445 
   446     /* Set the icon for the window */
   447     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   448 
   449     /* Set the icon in the task manager (should we do this?) */
   450     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   451 }
   452 
   453 void
   454 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   455 {
   456     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   457 }
   458 
   459 void
   460 WIN_SetWindowSize(_THIS, SDL_Window * window)
   461 {
   462     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   463 }
   464 
   465 void
   466 WIN_ShowWindow(_THIS, SDL_Window * window)
   467 {
   468     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   469     ShowWindow(hwnd, SW_SHOW);
   470 }
   471 
   472 void
   473 WIN_HideWindow(_THIS, SDL_Window * window)
   474 {
   475     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   476     ShowWindow(hwnd, SW_HIDE);
   477 }
   478 
   479 void
   480 WIN_RaiseWindow(_THIS, SDL_Window * window)
   481 {
   482     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   483     SetForegroundWindow(hwnd);
   484 }
   485 
   486 void
   487 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   488 {
   489     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   490     HWND hwnd = data->hwnd;
   491     data->expected_resize = SDL_TRUE;
   492     ShowWindow(hwnd, SW_MAXIMIZE);
   493     data->expected_resize = SDL_FALSE;
   494 }
   495 
   496 void
   497 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   498 {
   499     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   500     ShowWindow(hwnd, SW_MINIMIZE);
   501 }
   502 
   503 void
   504 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   505 {
   506     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   507     HWND hwnd = data->hwnd;
   508     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   509 
   510     if (bordered) {
   511         style &= ~STYLE_BORDERLESS;
   512         style |= STYLE_NORMAL;
   513     } else {
   514         style &= ~STYLE_NORMAL;
   515         style |= STYLE_BORDERLESS;
   516     }
   517 
   518     data->in_border_change = SDL_TRUE;
   519     SetWindowLong(hwnd, GWL_STYLE, style);
   520     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
   521     data->in_border_change = SDL_FALSE;
   522 }
   523 
   524 void
   525 WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
   526 {
   527     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   528     HWND hwnd = data->hwnd;
   529     DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   530 
   531     if (resizable) {
   532         style |= STYLE_RESIZABLE;
   533     } else {
   534         style &= ~STYLE_RESIZABLE;
   535     }
   536 
   537     SetWindowLong(hwnd, GWL_STYLE, style);
   538 }
   539 
   540 void
   541 WIN_RestoreWindow(_THIS, SDL_Window * window)
   542 {
   543     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   544     HWND hwnd = data->hwnd;
   545     data->expected_resize = SDL_TRUE;
   546     ShowWindow(hwnd, SW_RESTORE);
   547     data->expected_resize = SDL_FALSE;
   548 }
   549 
   550 void
   551 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   552 {
   553     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   554     HWND hwnd = data->hwnd;
   555     RECT rect;
   556     SDL_Rect bounds;
   557     DWORD style;
   558     HWND top;
   559     BOOL menu;
   560     int x, y;
   561     int w, h;
   562 
   563     if (SDL_ShouldAllowTopmost() && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) {
   564         top = HWND_TOPMOST;
   565     } else {
   566         top = HWND_NOTOPMOST;
   567     }
   568 
   569     style = GetWindowLong(hwnd, GWL_STYLE);
   570     style &= ~STYLE_MASK;
   571     style |= GetWindowStyle(window);
   572 
   573     WIN_GetDisplayBounds(_this, display, &bounds);
   574 
   575     if (fullscreen) {
   576         x = bounds.x;
   577         y = bounds.y;
   578         w = bounds.w;
   579         h = bounds.h;
   580 
   581         /* Unset the maximized flag.  This fixes
   582            https://bugzilla.libsdl.org/show_bug.cgi?id=3215
   583         */
   584         if (style & WS_MAXIMIZE) {
   585             data->windowed_mode_was_maximized = SDL_TRUE;
   586             style &= ~WS_MAXIMIZE;
   587         }
   588     } else {
   589         /* Restore window-maximization state, as applicable.
   590            Special care is taken to *not* do this if and when we're
   591            alt-tab'ing away (to some other window; as indicated by
   592            in_window_deactivation), otherwise
   593            https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
   594         */
   595         if (data->windowed_mode_was_maximized && !data->in_window_deactivation) {
   596             style |= WS_MAXIMIZE;
   597             data->windowed_mode_was_maximized = SDL_FALSE;
   598         }
   599         rect.left = 0;
   600         rect.top = 0;
   601         rect.right = window->windowed.w;
   602         rect.bottom = window->windowed.h;
   603         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   604         AdjustWindowRectEx(&rect, style, menu, 0);
   605         w = (rect.right - rect.left);
   606         h = (rect.bottom - rect.top);
   607         x = window->windowed.x + rect.left;
   608         y = window->windowed.y + rect.top;
   609     }
   610     SetWindowLong(hwnd, GWL_STYLE, style);
   611     data->expected_resize = SDL_TRUE;
   612     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
   613     data->expected_resize = SDL_FALSE;
   614 }
   615 
   616 int
   617 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   618 {
   619     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   620     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   621     HDC hdc;
   622     BOOL succeeded = FALSE;
   623 
   624     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   625     if (hdc) {
   626         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   627         if (!succeeded) {
   628             WIN_SetError("SetDeviceGammaRamp()");
   629         }
   630         DeleteDC(hdc);
   631     }
   632     return succeeded ? 0 : -1;
   633 }
   634 
   635 int
   636 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   637 {
   638     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   639     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   640     HDC hdc;
   641     BOOL succeeded = FALSE;
   642 
   643     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   644     if (hdc) {
   645         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   646         if (!succeeded) {
   647             WIN_SetError("GetDeviceGammaRamp()");
   648         }
   649         DeleteDC(hdc);
   650     }
   651     return succeeded ? 0 : -1;
   652 }
   653 
   654 void
   655 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   656 {
   657     WIN_UpdateClipCursor(window);
   658 
   659     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   660         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   661 
   662         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   663             flags |= SWP_NOACTIVATE;
   664         }
   665         WIN_SetWindowPositionInternal(_this, window, flags);
   666     }
   667 }
   668 
   669 void
   670 WIN_DestroyWindow(_THIS, SDL_Window * window)
   671 {
   672     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   673 
   674     if (data) {
   675         ReleaseDC(data->hwnd, data->hdc);
   676         RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
   677         if (data->created) {
   678             DestroyWindow(data->hwnd);
   679         } else {
   680             /* Restore any original event handler... */
   681             if (data->wndproc != NULL) {
   682 #ifdef GWLP_WNDPROC
   683                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   684                                  (LONG_PTR) data->wndproc);
   685 #else
   686                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   687                               (LONG_PTR) data->wndproc);
   688 #endif
   689             }
   690         }
   691         SDL_free(data);
   692     }
   693     window->driverdata = NULL;
   694 }
   695 
   696 SDL_bool
   697 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   698 {
   699     const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
   700     if (info->version.major <= SDL_MAJOR_VERSION) {
   701         int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
   702 
   703         info->subsystem = SDL_SYSWM_WINDOWS;
   704         info->info.win.window = data->hwnd;
   705 
   706         if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) {
   707             info->info.win.hdc = data->hdc;
   708         }
   709 
   710         if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) {
   711             info->info.win.hinstance = data->hinstance;
   712         }
   713 
   714         return SDL_TRUE;
   715     } else {
   716         SDL_SetError("Application not compiled with SDL %d.%d\n",
   717                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   718         return SDL_FALSE;
   719     }
   720 }
   721 
   722 
   723 /*
   724  * Creates a HelperWindow used for DirectInput events.
   725  */
   726 int
   727 SDL_HelperWindowCreate(void)
   728 {
   729     HINSTANCE hInstance = GetModuleHandle(NULL);
   730     WNDCLASS wce;
   731 
   732     /* Make sure window isn't created twice. */
   733     if (SDL_HelperWindow != NULL) {
   734         return 0;
   735     }
   736 
   737     /* Create the class. */
   738     SDL_zero(wce);
   739     wce.lpfnWndProc = DefWindowProc;
   740     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   741     wce.hInstance = hInstance;
   742 
   743     /* Register the class. */
   744     SDL_HelperWindowClass = RegisterClass(&wce);
   745     if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
   746         return WIN_SetError("Unable to create Helper Window Class");
   747     }
   748 
   749     /* Create the window. */
   750     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   751                                       SDL_HelperWindowName,
   752                                       WS_OVERLAPPED, CW_USEDEFAULT,
   753                                       CW_USEDEFAULT, CW_USEDEFAULT,
   754                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   755                                       hInstance, NULL);
   756     if (SDL_HelperWindow == NULL) {
   757         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   758         return WIN_SetError("Unable to create Helper Window");
   759     }
   760 
   761     return 0;
   762 }
   763 
   764 
   765 /*
   766  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   767  */
   768 void
   769 SDL_HelperWindowDestroy(void)
   770 {
   771     HINSTANCE hInstance = GetModuleHandle(NULL);
   772 
   773     /* Destroy the window. */
   774     if (SDL_HelperWindow != NULL) {
   775         if (DestroyWindow(SDL_HelperWindow) == 0) {
   776             WIN_SetError("Unable to destroy Helper Window");
   777             return;
   778         }
   779         SDL_HelperWindow = NULL;
   780     }
   781 
   782     /* Unregister the class. */
   783     if (SDL_HelperWindowClass != 0) {
   784         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   785             WIN_SetError("Unable to destroy Helper Window Class");
   786             return;
   787         }
   788         SDL_HelperWindowClass = 0;
   789     }
   790 }
   791 
   792 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   793 {
   794 #ifdef WM_MOUSELEAVE
   795     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   796     TRACKMOUSEEVENT trackMouseEvent;
   797 
   798     if (!data || !data->hwnd) {
   799         /* The window wasn't fully initialized */
   800         return;
   801     }
   802 
   803     trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   804     trackMouseEvent.dwFlags = TME_LEAVE;
   805     trackMouseEvent.hwndTrack = data->hwnd;
   806 
   807     TrackMouseEvent(&trackMouseEvent);
   808 #endif /* WM_MOUSELEAVE */
   809 }
   810 
   811 void
   812 WIN_UpdateClipCursor(SDL_Window *window)
   813 {
   814     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   815     SDL_Mouse *mouse = SDL_GetMouse();
   816 
   817     if (data->focus_click_pending) {
   818         return;
   819     }
   820 
   821     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   822         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   823         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   824             LONG cx, cy;
   825             RECT rect;
   826             GetWindowRect(data->hwnd, &rect);
   827 
   828             cx = (rect.left + rect.right) / 2;
   829             cy = (rect.top + rect.bottom) / 2;
   830 
   831             /* Make an absurdly small clip rect */
   832             rect.left = cx - 1;
   833             rect.right = cx + 1;
   834             rect.top = cy - 1;
   835             rect.bottom = cy + 1;
   836 
   837             ClipCursor(&rect);
   838         } else {
   839             RECT rect;
   840             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   841                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   842                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   843                 ClipCursor(&rect);
   844             }
   845         }
   846     } else {
   847         ClipCursor(NULL);
   848     }
   849 }
   850 
   851 int
   852 WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   853 {
   854     return 0;  /* just succeed, the real work is done elsewhere. */
   855 }
   856 
   857 int
   858 WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
   859 {
   860     const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   861     const HWND hwnd = data->hwnd;
   862     const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
   863 
   864     SDL_assert(style != 0);
   865 
   866     if (opacity == 1.0f) {
   867         /* want it fully opaque, just mark it unlayered if necessary. */
   868         if (style & WS_EX_LAYERED) {
   869             if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
   870                 return WIN_SetError("SetWindowLong()");
   871             }
   872         }
   873     } else {
   874         const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
   875         /* want it transparent, mark it layered if necessary. */
   876         if ((style & WS_EX_LAYERED) == 0) {
   877             if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
   878                 return WIN_SetError("SetWindowLong()");
   879             }
   880         }
   881 
   882         if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
   883             return WIN_SetError("SetLayeredWindowAttributes()");
   884         }
   885     }
   886 
   887     return 0;
   888 }
   889 
   890 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   891 
   892 /* vi: set ts=4 sw=4 expandtab: */