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