src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 26 Aug 2018 10:34:23 -0700
changeset 12153 de4288fa5b0b
parent 12070 1d65571b57dd
child 12231 e653f009e6c0
child 12349 a67dedb293c8
permissions -rw-r--r--
Only reset the clip rect if it's currently the rect we previously clipped.
This prevents us from clearing the clip rect globally when another application has set it.

There's also an experimental change to regularly update the clip rect for a window defensively, in case someone else has reset it. It works well, but I don't know if it's cheap enough to call as frequently as it would be called now, and might have other undesirable side effects.

Also fixed whitespace and SDL coding style
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 /* For borderless Windows, still want the following flags:
    55    - WS_CAPTION: this seems to enable the Windows minimize animation
    56    - WS_SYSMENU: enables system context menu on task bar
    57    - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc.
    58    This will also cause the task bar to overlap the window and other windowed behaviors, so only use this for windows that shouldn't appear to be fullscreen
    59  */
    60 
    61 #define STYLE_BASIC         (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
    62 #define STYLE_FULLSCREEN    (WS_POPUP)
    63 #define STYLE_BORDERLESS    (WS_POPUP)
    64 #define STYLE_BORDERLESS_WINDOWED (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
    65 #define STYLE_NORMAL        (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
    66 #define STYLE_RESIZABLE     (WS_THICKFRAME | WS_MAXIMIZEBOX)
    67 #define STYLE_MASK          (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
    68 
    69 static DWORD
    70 GetWindowStyle(SDL_Window * window)
    71 {
    72     DWORD style = 0;
    73 
    74     if (window->flags & SDL_WINDOW_FULLSCREEN) {
    75         style |= STYLE_FULLSCREEN;
    76     } else {
    77         if (window->flags & SDL_WINDOW_BORDERLESS) {
    78             /* SDL 2.1:
    79                This behavior more closely matches other platform where the window is borderless
    80                but still interacts with the window manager (e.g. task bar shows above it, it can
    81                be resized to fit within usable desktop area, etc.) so this should be the behavior
    82                for a future SDL release.
    83 
    84                If you want a borderless window the size of the desktop that looks like a fullscreen
    85                window, then you should use the SDL_WINDOW_FULLSCREEN_DESKTOP flag.
    86              */
    87             if (SDL_GetHintBoolean("SDL_BORDERLESS_WINDOWED_STYLE", SDL_FALSE)) {
    88                 style |= STYLE_BORDERLESS_WINDOWED;
    89             } else {
    90                 style |= STYLE_BORDERLESS;
    91             }
    92         } else {
    93             style |= STYLE_NORMAL;
    94         }
    95 
    96         /* You can have a borderless resizable window */
    97         if (window->flags & SDL_WINDOW_RESIZABLE) {
    98             style |= STYLE_RESIZABLE;
    99         }
   100 
   101         /* Need to set initialize minimize style, or when we call ShowWindow with WS_MINIMIZE it will activate a random window */
   102         if (window->flags & SDL_WINDOW_MINIMIZED) {
   103             style |= WS_MINIMIZE;
   104         }
   105     }
   106     return style;
   107 }
   108 
   109 static void
   110 WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x, int *y, int *width, int *height, SDL_bool use_current)
   111 {
   112     RECT rect;
   113 
   114     rect.left = 0;
   115     rect.top = 0;
   116     rect.right = (use_current ? window->w : window->windowed.w);
   117     rect.bottom = (use_current ? window->h : window->windowed.h);
   118 
   119     /* borderless windows will have WM_NCCALCSIZE return 0 for the non-client area. When this happens, it looks like windows will send a resize message
   120        expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
   121      */
   122     if (!(window->flags & SDL_WINDOW_BORDERLESS))
   123         AdjustWindowRectEx(&rect, style, menu, 0);
   124 
   125     *x = (use_current ? window->x : window->windowed.x) + rect.left;
   126     *y = (use_current ? window->y : window->windowed.y) + rect.top;
   127     *width = (rect.right - rect.left);
   128     *height = (rect.bottom - rect.top);
   129 }
   130 
   131 static void
   132 WIN_AdjustWindowRect(SDL_Window *window, int *x, int *y, int *width, int *height, SDL_bool use_current)
   133 {
   134     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   135     HWND hwnd = data->hwnd;
   136     DWORD style;
   137     BOOL menu;
   138 
   139     style = GetWindowLong(hwnd, GWL_STYLE);
   140     menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   141     WIN_AdjustWindowRectWithStyle(window, style, menu, x, y, width, height, use_current);
   142 }
   143 
   144 static void
   145 WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
   146 {
   147     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   148     HWND hwnd = data->hwnd;
   149     HWND top;
   150     int x, y;
   151     int w, h;
   152 
   153     /* Figure out what the window area will be */
   154     if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) {
   155         top = HWND_TOPMOST;
   156     } else {
   157         top = HWND_NOTOPMOST;
   158     }
   159 
   160     WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_TRUE);    
   161 
   162     data->expected_resize = SDL_TRUE;
   163     SetWindowPos(hwnd, top, x, y, w, h, flags);
   164     data->expected_resize = SDL_FALSE;
   165 }
   166 
   167 static int
   168 SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool created)
   169 {
   170     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   171     SDL_WindowData *data;
   172 
   173     /* Allocate the window data */
   174     data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
   175     if (!data) {
   176         return SDL_OutOfMemory();
   177     }
   178     data->window = window;
   179     data->hwnd = hwnd;
   180     data->parent = parent;
   181     data->hdc = GetDC(hwnd);
   182     data->hinstance = (HINSTANCE) GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
   183     data->created = created;
   184     data->mouse_button_flags = 0;
   185     data->videodata = videodata;
   186     data->initializing = SDL_TRUE;
   187 
   188     window->driverdata = data;
   189 
   190     /* Associate the data with the window */
   191     if (!SetProp(hwnd, TEXT("SDL_WindowData"), data)) {
   192         ReleaseDC(hwnd, data->hdc);
   193         SDL_free(data);
   194         return WIN_SetError("SetProp() failed");
   195     }
   196 
   197     /* Set up the window proc function */
   198 #ifdef GWLP_WNDPROC
   199     data->wndproc = (WNDPROC) GetWindowLongPtr(hwnd, GWLP_WNDPROC);
   200     if (data->wndproc == WIN_WindowProc) {
   201         data->wndproc = NULL;
   202     } else {
   203         SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) WIN_WindowProc);
   204     }
   205 #else
   206     data->wndproc = (WNDPROC) GetWindowLong(hwnd, GWL_WNDPROC);
   207     if (data->wndproc == WIN_WindowProc) {
   208         data->wndproc = NULL;
   209     } else {
   210         SetWindowLong(hwnd, GWL_WNDPROC, (LONG_PTR) WIN_WindowProc);
   211     }
   212 #endif
   213 
   214     /* Fill in the SDL window with the window data */
   215     {
   216         RECT rect;
   217         if (GetClientRect(hwnd, &rect)) {
   218             int w = rect.right;
   219             int h = rect.bottom;
   220             if ((window->windowed.w && window->windowed.w != w) || (window->windowed.h && window->windowed.h != h)) {
   221                 /* We tried to create a window larger than the desktop and Windows didn't allow it.  Override! */
   222                 int x, y;
   223                 /* Figure out what the window area will be */
   224                 WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
   225                 SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE);
   226             } else {
   227                 window->w = w;
   228                 window->h = h;
   229             }
   230         }
   231     }
   232     {
   233         POINT point;
   234         point.x = 0;
   235         point.y = 0;
   236         if (ClientToScreen(hwnd, &point)) {
   237             window->x = point.x;
   238             window->y = point.y;
   239         }
   240     }
   241     {
   242         DWORD style = GetWindowLong(hwnd, GWL_STYLE);
   243         if (style & WS_VISIBLE) {
   244             window->flags |= SDL_WINDOW_SHOWN;
   245         } else {
   246             window->flags &= ~SDL_WINDOW_SHOWN;
   247         }
   248         if (style & WS_POPUP) {
   249             window->flags |= SDL_WINDOW_BORDERLESS;
   250         } else {
   251             window->flags &= ~SDL_WINDOW_BORDERLESS;
   252         }
   253         if (style & WS_THICKFRAME) {
   254             window->flags |= SDL_WINDOW_RESIZABLE;
   255         } else {
   256             window->flags &= ~SDL_WINDOW_RESIZABLE;
   257         }
   258 #ifdef WS_MAXIMIZE
   259         if (style & WS_MAXIMIZE) {
   260             window->flags |= SDL_WINDOW_MAXIMIZED;
   261         } else
   262 #endif
   263         {
   264             window->flags &= ~SDL_WINDOW_MAXIMIZED;
   265         }
   266 #ifdef WS_MINIMIZE
   267         if (style & WS_MINIMIZE) {
   268             window->flags |= SDL_WINDOW_MINIMIZED;
   269         } else
   270 #endif
   271         {
   272             window->flags &= ~SDL_WINDOW_MINIMIZED;
   273         }
   274     }
   275     if (GetFocus() == hwnd) {
   276         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   277         SDL_SetKeyboardFocus(data->window);
   278 
   279         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   280             RECT rect;
   281             GetClientRect(hwnd, &rect);
   282             ClientToScreen(hwnd, (LPPOINT) & rect);
   283             ClientToScreen(hwnd, (LPPOINT) & rect + 1);
   284             ClipCursor(&rect);
   285         }
   286     }
   287 
   288     /* Enable multi-touch */
   289     if (videodata->RegisterTouchWindow) {
   290         videodata->RegisterTouchWindow(hwnd, (TWF_FINETOUCH|TWF_WANTPALM));
   291     }
   292 
   293     data->initializing = SDL_FALSE;
   294 
   295     /* All done! */
   296     return 0;
   297 }
   298 
   299 
   300 
   301 int
   302 WIN_CreateWindow(_THIS, SDL_Window * window)
   303 {
   304     HWND hwnd, parent = NULL;
   305     DWORD style = STYLE_BASIC;
   306     int x, y;
   307     int w, h;
   308 
   309     if (window->flags & SDL_WINDOW_SKIP_TASKBAR) {
   310         parent = CreateWindow(SDL_Appname, TEXT(""), STYLE_BASIC, 0, 0, 32, 32, NULL, NULL, SDL_Instance, NULL);
   311     }
   312 
   313     style |= GetWindowStyle(window);
   314 
   315     /* Figure out what the window area will be */
   316     WIN_AdjustWindowRectWithStyle(window, style, FALSE, &x, &y, &w, &h, SDL_FALSE);
   317 
   318     hwnd =
   319         CreateWindow(SDL_Appname, TEXT(""), style, x, y, w, h, parent, NULL,
   320                      SDL_Instance, NULL);
   321     if (!hwnd) {
   322         return WIN_SetError("Couldn't create window");
   323     }
   324 
   325     WIN_PumpEvents(_this);
   326 
   327     if (SetupWindowData(_this, window, hwnd, parent, SDL_TRUE) < 0) {
   328         DestroyWindow(hwnd);
   329         if (parent) {
   330             DestroyWindow(parent);
   331         }
   332         return -1;
   333     }
   334 
   335     /* Inform Windows of the frame change so we can respond to WM_NCCALCSIZE */
   336     SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
   337 
   338     if (window->flags & SDL_WINDOW_MINIMIZED) {
   339         ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
   340     }
   341 
   342     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   343         return 0;
   344     }
   345 
   346     /* The rest of this macro mess is for OpenGL or OpenGL ES windows */
   347 #if SDL_VIDEO_OPENGL_ES2
   348     if (_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES
   349 #if SDL_VIDEO_OPENGL_WGL
   350         && (!_this->gl_data || WIN_GL_UseEGL(_this))
   351 #endif /* SDL_VIDEO_OPENGL_WGL */
   352     ) {
   353 #if SDL_VIDEO_OPENGL_EGL
   354         if (WIN_GLES_SetupWindow(_this, window) < 0) {
   355             WIN_DestroyWindow(_this, window);
   356             return -1;
   357         }
   358         return 0;
   359 #else
   360         return SDL_SetError("Could not create GLES window surface (EGL support not configured)");
   361 #endif /* SDL_VIDEO_OPENGL_EGL */ 
   362     }
   363 #endif /* SDL_VIDEO_OPENGL_ES2 */
   364 
   365 #if SDL_VIDEO_OPENGL_WGL
   366     if (WIN_GL_SetupWindow(_this, window) < 0) {
   367         WIN_DestroyWindow(_this, window);
   368         return -1;
   369     }
   370 #else
   371     return SDL_SetError("Could not create GL window (WGL support not configured)");
   372 #endif
   373 
   374     return 0;
   375 }
   376 
   377 int
   378 WIN_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   379 {
   380     HWND hwnd = (HWND) data;
   381     LPTSTR title;
   382     int titleLen;
   383 
   384     /* Query the title from the existing window */
   385     titleLen = GetWindowTextLength(hwnd);
   386     title = SDL_stack_alloc(TCHAR, titleLen + 1);
   387     if (title) {
   388         titleLen = GetWindowText(hwnd, title, titleLen);
   389     } else {
   390         titleLen = 0;
   391     }
   392     if (titleLen > 0) {
   393         window->title = WIN_StringToUTF8(title);
   394     }
   395     if (title) {
   396         SDL_stack_free(title);
   397     }
   398 
   399     if (SetupWindowData(_this, window, hwnd, GetParent(hwnd), SDL_FALSE) < 0) {
   400         return -1;
   401     }
   402 
   403 #if SDL_VIDEO_OPENGL_WGL
   404     {
   405         const char *hint = SDL_GetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT);
   406         if (hint) {
   407             /* This hint is a pointer (in string form) of the address of
   408                the window to share a pixel format with
   409             */
   410             SDL_Window *otherWindow = NULL;
   411             SDL_sscanf(hint, "%p", (void**)&otherWindow);
   412 
   413             /* Do some error checking on the pointer */
   414             if (otherWindow != NULL && otherWindow->magic == &_this->window_magic) {
   415                 /* If the otherWindow has SDL_WINDOW_OPENGL set, set it for the new window as well */
   416                 if (otherWindow->flags & SDL_WINDOW_OPENGL) {
   417                     window->flags |= SDL_WINDOW_OPENGL;
   418                     if (!WIN_GL_SetPixelFormatFrom(_this, otherWindow, window)) {
   419                         return -1;
   420                     }
   421                 }
   422             }
   423         }
   424     }
   425 #endif
   426     return 0;
   427 }
   428 
   429 void
   430 WIN_SetWindowTitle(_THIS, SDL_Window * window)
   431 {
   432     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   433     LPTSTR title = WIN_UTF8ToString(window->title);
   434     SetWindowText(hwnd, title);
   435     SDL_free(title);
   436 }
   437 
   438 void
   439 WIN_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
   440 {
   441     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   442     HICON hicon = NULL;
   443     BYTE *icon_bmp;
   444     int icon_len, mask_len, y;
   445     SDL_RWops *dst;
   446 
   447     /* Create temporary buffer for ICONIMAGE structure */
   448     mask_len = (icon->h * (icon->w + 7)/8);
   449     icon_len = 40 + icon->h * icon->w * sizeof(Uint32) + mask_len;
   450     icon_bmp = SDL_stack_alloc(BYTE, icon_len);
   451     dst = SDL_RWFromMem(icon_bmp, icon_len);
   452     if (!dst) {
   453         SDL_stack_free(icon_bmp);
   454         return;
   455     }
   456 
   457     /* Write the BITMAPINFO header */
   458     SDL_WriteLE32(dst, 40);
   459     SDL_WriteLE32(dst, icon->w);
   460     SDL_WriteLE32(dst, icon->h * 2);
   461     SDL_WriteLE16(dst, 1);
   462     SDL_WriteLE16(dst, 32);
   463     SDL_WriteLE32(dst, BI_RGB);
   464     SDL_WriteLE32(dst, icon->h * icon->w * sizeof(Uint32));
   465     SDL_WriteLE32(dst, 0);
   466     SDL_WriteLE32(dst, 0);
   467     SDL_WriteLE32(dst, 0);
   468     SDL_WriteLE32(dst, 0);
   469 
   470     /* Write the pixels upside down into the bitmap buffer */
   471     SDL_assert(icon->format->format == SDL_PIXELFORMAT_ARGB8888);
   472     y = icon->h;
   473     while (y--) {
   474         Uint8 *src = (Uint8 *) icon->pixels + y * icon->pitch;
   475         SDL_RWwrite(dst, src, icon->w * sizeof(Uint32), 1);
   476     }
   477 
   478     /* Write the mask */
   479     SDL_memset(icon_bmp + icon_len - mask_len, 0xFF, mask_len);
   480 
   481     hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
   482 
   483     SDL_RWclose(dst);
   484     SDL_stack_free(icon_bmp);
   485 
   486     /* Set the icon for the window */
   487     SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) hicon);
   488 
   489     /* Set the icon in the task manager (should we do this?) */
   490     SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) hicon);
   491 }
   492 
   493 void
   494 WIN_SetWindowPosition(_THIS, SDL_Window * window)
   495 {
   496     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   497 }
   498 
   499 void
   500 WIN_SetWindowSize(_THIS, SDL_Window * window)
   501 {
   502     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
   503 }
   504 
   505 int
   506 WIN_GetWindowBordersSize(_THIS, SDL_Window * window, int *top, int *left, int *bottom, int *right)
   507 {
   508     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   509     RECT rcClient, rcWindow;
   510     POINT ptDiff;
   511 
   512     /* rcClient stores the size of the inner window, while rcWindow stores the outer size relative to the top-left
   513      * screen position; so the top/left values of rcClient are always {0,0} and bottom/right are {height,width} */
   514     GetClientRect(hwnd, &rcClient);
   515     GetWindowRect(hwnd, &rcWindow);
   516 
   517     /* convert the top/left values to make them relative to
   518      * the window; they will end up being slightly negative */
   519     ptDiff.y = rcWindow.top;
   520     ptDiff.x = rcWindow.left;
   521 
   522     ScreenToClient(hwnd, &ptDiff);
   523 
   524     rcWindow.top  = ptDiff.y;
   525     rcWindow.left = ptDiff.x;
   526 
   527     /* convert the bottom/right values to make them relative to the window,
   528      * these will be slightly bigger than the inner width/height */
   529     ptDiff.y = rcWindow.bottom;
   530     ptDiff.x = rcWindow.right;
   531 
   532     ScreenToClient(hwnd, &ptDiff);
   533 
   534     rcWindow.bottom = ptDiff.y;
   535     rcWindow.right  = ptDiff.x;
   536 
   537     /* Now that both the inner and outer rects use the same coordinate system we can substract them to get the border size.
   538      * Keep in mind that the top/left coordinates of rcWindow are negative because the border lies slightly before {0,0},
   539      * so switch them around because SDL2 wants them in positive. */
   540     *top    = rcClient.top    - rcWindow.top;
   541     *left   = rcClient.left   - rcWindow.left;
   542     *bottom = rcWindow.bottom - rcClient.bottom;
   543     *right  = rcWindow.right  - rcClient.right;
   544 
   545     return 0;
   546 }
   547 
   548 void
   549 WIN_ShowWindow(_THIS, SDL_Window * window)
   550 {
   551     DWORD style;
   552     HWND hwnd;
   553     int nCmdShow;
   554     
   555     hwnd = ((SDL_WindowData *)window->driverdata)->hwnd;
   556     nCmdShow = SW_SHOW;
   557     style = GetWindowLong(hwnd, GWL_EXSTYLE);
   558     if (style & WS_EX_NOACTIVATE) {
   559         nCmdShow = SW_SHOWNOACTIVATE;
   560     }
   561     ShowWindow(hwnd, nCmdShow);
   562 }
   563 
   564 void
   565 WIN_HideWindow(_THIS, SDL_Window * window)
   566 {
   567     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   568     ShowWindow(hwnd, SW_HIDE);
   569 }
   570 
   571 void
   572 WIN_RaiseWindow(_THIS, SDL_Window * window)
   573 {
   574     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   575     SetForegroundWindow(hwnd);
   576 }
   577 
   578 void
   579 WIN_MaximizeWindow(_THIS, SDL_Window * window)
   580 {
   581     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   582     HWND hwnd = data->hwnd;
   583     data->expected_resize = SDL_TRUE;
   584     ShowWindow(hwnd, SW_MAXIMIZE);
   585     data->expected_resize = SDL_FALSE;
   586 }
   587 
   588 void
   589 WIN_MinimizeWindow(_THIS, SDL_Window * window)
   590 {
   591     HWND hwnd = ((SDL_WindowData *) window->driverdata)->hwnd;
   592     ShowWindow(hwnd, SW_MINIMIZE);
   593 }
   594 
   595 void
   596 WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
   597 {
   598     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   599     HWND hwnd = data->hwnd;
   600     DWORD style;
   601 
   602     style = GetWindowLong(hwnd, GWL_STYLE);
   603     style &= ~STYLE_MASK;
   604     style |= GetWindowStyle(window);
   605 
   606     data->in_border_change = SDL_TRUE;
   607     SetWindowLong(hwnd, GWL_STYLE, style);
   608     WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
   609     data->in_border_change = SDL_FALSE;
   610 }
   611 
   612 void
   613 WIN_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
   614 {
   615     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   616     HWND hwnd = data->hwnd;
   617     DWORD style;
   618 
   619     style = GetWindowLong(hwnd, GWL_STYLE);
   620     style &= ~STYLE_MASK;
   621     style |= GetWindowStyle(window);
   622 
   623     SetWindowLong(hwnd, GWL_STYLE, style);
   624 }
   625 
   626 void
   627 WIN_RestoreWindow(_THIS, SDL_Window * window)
   628 {
   629     SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   630     HWND hwnd = data->hwnd;
   631     data->expected_resize = SDL_TRUE;
   632     ShowWindow(hwnd, SW_RESTORE);
   633     data->expected_resize = SDL_FALSE;
   634 }
   635 
   636 void
   637 WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   638 {
   639     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   640     HWND hwnd = data->hwnd;
   641     SDL_Rect bounds;
   642     DWORD style;
   643     HWND top;
   644     int x, y;
   645     int w, h;
   646 
   647     if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
   648         top = HWND_TOPMOST;
   649     } else {
   650         top = HWND_NOTOPMOST;
   651     }
   652 
   653     style = GetWindowLong(hwnd, GWL_STYLE);
   654     style &= ~STYLE_MASK;
   655     style |= GetWindowStyle(window);
   656 
   657     WIN_GetDisplayBounds(_this, display, &bounds);
   658 
   659     if (fullscreen) {
   660         x = bounds.x;
   661         y = bounds.y;
   662         w = bounds.w;
   663         h = bounds.h;
   664 
   665         /* Unset the maximized flag.  This fixes
   666            https://bugzilla.libsdl.org/show_bug.cgi?id=3215
   667         */
   668         if (style & WS_MAXIMIZE) {
   669             data->windowed_mode_was_maximized = SDL_TRUE;
   670             style &= ~WS_MAXIMIZE;
   671         }
   672     } else {
   673         BOOL menu;
   674 
   675         /* Restore window-maximization state, as applicable.
   676            Special care is taken to *not* do this if and when we're
   677            alt-tab'ing away (to some other window; as indicated by
   678            in_window_deactivation), otherwise
   679            https://bugzilla.libsdl.org/show_bug.cgi?id=3215 can reproduce!
   680         */
   681         if (data->windowed_mode_was_maximized && !data->in_window_deactivation) {
   682             style |= WS_MAXIMIZE;
   683             data->windowed_mode_was_maximized = SDL_FALSE;
   684         }
   685 
   686         menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
   687         WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
   688     }
   689     SetWindowLong(hwnd, GWL_STYLE, style);
   690     data->expected_resize = SDL_TRUE;
   691     SetWindowPos(hwnd, top, x, y, w, h, SWP_NOCOPYBITS | SWP_NOACTIVATE);
   692     data->expected_resize = SDL_FALSE;
   693 }
   694 
   695 int
   696 WIN_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
   697 {
   698     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   699     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   700     HDC hdc;
   701     BOOL succeeded = FALSE;
   702 
   703     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   704     if (hdc) {
   705         succeeded = SetDeviceGammaRamp(hdc, (LPVOID)ramp);
   706         if (!succeeded) {
   707             WIN_SetError("SetDeviceGammaRamp()");
   708         }
   709         DeleteDC(hdc);
   710     }
   711     return succeeded ? 0 : -1;
   712 }
   713 
   714 int
   715 WIN_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
   716 {
   717     SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   718     SDL_DisplayData *data = (SDL_DisplayData *) display->driverdata;
   719     HDC hdc;
   720     BOOL succeeded = FALSE;
   721 
   722     hdc = CreateDC(data->DeviceName, NULL, NULL, NULL);
   723     if (hdc) {
   724         succeeded = GetDeviceGammaRamp(hdc, (LPVOID)ramp);
   725         if (!succeeded) {
   726             WIN_SetError("GetDeviceGammaRamp()");
   727         }
   728         DeleteDC(hdc);
   729     }
   730     return succeeded ? 0 : -1;
   731 }
   732 
   733 void
   734 WIN_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
   735 {
   736     WIN_UpdateClipCursor(window);
   737 
   738     if (window->flags & SDL_WINDOW_FULLSCREEN) {
   739         UINT flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOSIZE;
   740 
   741         if (!(window->flags & SDL_WINDOW_SHOWN)) {
   742             flags |= SWP_NOACTIVATE;
   743         }
   744         WIN_SetWindowPositionInternal(_this, window, flags);
   745     }
   746 }
   747 
   748 void
   749 WIN_DestroyWindow(_THIS, SDL_Window * window)
   750 {
   751     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   752 
   753     if (data) {
   754         ReleaseDC(data->hwnd, data->hdc);
   755         RemoveProp(data->hwnd, TEXT("SDL_WindowData"));
   756         if (data->created) {
   757             DestroyWindow(data->hwnd);
   758             if (data->parent) {
   759                 DestroyWindow(data->parent);
   760             }
   761         } else {
   762             /* Restore any original event handler... */
   763             if (data->wndproc != NULL) {
   764 #ifdef GWLP_WNDPROC
   765                 SetWindowLongPtr(data->hwnd, GWLP_WNDPROC,
   766                                  (LONG_PTR) data->wndproc);
   767 #else
   768                 SetWindowLong(data->hwnd, GWL_WNDPROC,
   769                               (LONG_PTR) data->wndproc);
   770 #endif
   771             }
   772         }
   773         SDL_free(data);
   774     }
   775     window->driverdata = NULL;
   776 }
   777 
   778 SDL_bool
   779 WIN_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   780 {
   781     const SDL_WindowData *data = (const SDL_WindowData *) window->driverdata;
   782     if (info->version.major <= SDL_MAJOR_VERSION) {
   783         int versionnum = SDL_VERSIONNUM(info->version.major, info->version.minor, info->version.patch);
   784 
   785         info->subsystem = SDL_SYSWM_WINDOWS;
   786         info->info.win.window = data->hwnd;
   787 
   788         if (versionnum >= SDL_VERSIONNUM(2, 0, 4)) {
   789             info->info.win.hdc = data->hdc;
   790         }
   791 
   792         if (versionnum >= SDL_VERSIONNUM(2, 0, 5)) {
   793             info->info.win.hinstance = data->hinstance;
   794         }
   795 
   796         return SDL_TRUE;
   797     } else {
   798         SDL_SetError("Application not compiled with SDL %d.%d",
   799                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   800         return SDL_FALSE;
   801     }
   802 }
   803 
   804 
   805 /*
   806  * Creates a HelperWindow used for DirectInput events.
   807  */
   808 int
   809 SDL_HelperWindowCreate(void)
   810 {
   811     HINSTANCE hInstance = GetModuleHandle(NULL);
   812     WNDCLASS wce;
   813 
   814     /* Make sure window isn't created twice. */
   815     if (SDL_HelperWindow != NULL) {
   816         return 0;
   817     }
   818 
   819     /* Create the class. */
   820     SDL_zero(wce);
   821     wce.lpfnWndProc = DefWindowProc;
   822     wce.lpszClassName = (LPCWSTR) SDL_HelperWindowClassName;
   823     wce.hInstance = hInstance;
   824 
   825     /* Register the class. */
   826     SDL_HelperWindowClass = RegisterClass(&wce);
   827     if (SDL_HelperWindowClass == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) {
   828         return WIN_SetError("Unable to create Helper Window Class");
   829     }
   830 
   831     /* Create the window. */
   832     SDL_HelperWindow = CreateWindowEx(0, SDL_HelperWindowClassName,
   833                                       SDL_HelperWindowName,
   834                                       WS_OVERLAPPED, CW_USEDEFAULT,
   835                                       CW_USEDEFAULT, CW_USEDEFAULT,
   836                                       CW_USEDEFAULT, HWND_MESSAGE, NULL,
   837                                       hInstance, NULL);
   838     if (SDL_HelperWindow == NULL) {
   839         UnregisterClass(SDL_HelperWindowClassName, hInstance);
   840         return WIN_SetError("Unable to create Helper Window");
   841     }
   842 
   843     return 0;
   844 }
   845 
   846 
   847 /*
   848  * Destroys the HelperWindow previously created with SDL_HelperWindowCreate.
   849  */
   850 void
   851 SDL_HelperWindowDestroy(void)
   852 {
   853     HINSTANCE hInstance = GetModuleHandle(NULL);
   854 
   855     /* Destroy the window. */
   856     if (SDL_HelperWindow != NULL) {
   857         if (DestroyWindow(SDL_HelperWindow) == 0) {
   858             WIN_SetError("Unable to destroy Helper Window");
   859             return;
   860         }
   861         SDL_HelperWindow = NULL;
   862     }
   863 
   864     /* Unregister the class. */
   865     if (SDL_HelperWindowClass != 0) {
   866         if ((UnregisterClass(SDL_HelperWindowClassName, hInstance)) == 0) {
   867             WIN_SetError("Unable to destroy Helper Window Class");
   868             return;
   869         }
   870         SDL_HelperWindowClass = 0;
   871     }
   872 }
   873 
   874 void WIN_OnWindowEnter(_THIS, SDL_Window * window)
   875 {
   876     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   877 
   878     if (!data || !data->hwnd) {
   879         /* The window wasn't fully initialized */
   880         return;
   881     }
   882 
   883     if (window->flags & SDL_WINDOW_ALWAYS_ON_TOP) {
   884         WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOSIZE | SWP_NOACTIVATE);
   885     }
   886 
   887 #ifdef WM_MOUSELEAVE
   888     {
   889         TRACKMOUSEEVENT trackMouseEvent;
   890 
   891         trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
   892         trackMouseEvent.dwFlags = TME_LEAVE;
   893         trackMouseEvent.hwndTrack = data->hwnd;
   894 
   895         TrackMouseEvent(&trackMouseEvent);
   896     }
   897 #endif /* WM_MOUSELEAVE */
   898 }
   899 
   900 void
   901 WIN_UpdateClipCursor(SDL_Window *window)
   902 {
   903     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   904     SDL_Mouse *mouse = SDL_GetMouse();
   905     RECT rect;
   906 
   907     if (data->focus_click_pending) {
   908         return;
   909     }
   910 
   911     if ((mouse->relative_mode || (window->flags & SDL_WINDOW_INPUT_GRABBED)) &&
   912         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   913         if (mouse->relative_mode && !mouse->relative_mode_warp) {
   914             LONG cx, cy;
   915             GetWindowRect(data->hwnd, &rect);
   916 
   917             cx = (rect.left + rect.right) / 2;
   918             cy = (rect.top + rect.bottom) / 2;
   919 
   920             /* Make an absurdly small clip rect */
   921             rect.left = cx - 1;
   922             rect.right = cx + 1;
   923             rect.top = cy - 1;
   924             rect.bottom = cy + 1;
   925 
   926             if (ClipCursor(&rect)) {
   927                 data->cursor_clipped_rect = rect;
   928             }
   929         } else {
   930             if (GetClientRect(data->hwnd, &rect) && !IsRectEmpty(&rect)) {
   931                 ClientToScreen(data->hwnd, (LPPOINT) & rect);
   932                 ClientToScreen(data->hwnd, (LPPOINT) & rect + 1);
   933                 if (ClipCursor(&rect)) {
   934                     data->cursor_clipped_rect = rect;
   935                 }
   936             }
   937         }
   938     } else if (GetClipCursor(&rect) && SDL_memcmp(&rect, &data->cursor_clipped_rect, sizeof(rect)) == 0) {
   939         ClipCursor(NULL);
   940         SDL_zero(data->cursor_clipped_rect);
   941     }
   942 }
   943 
   944 int
   945 WIN_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   946 {
   947     return 0;  /* just succeed, the real work is done elsewhere. */
   948 }
   949 
   950 int
   951 WIN_SetWindowOpacity(_THIS, SDL_Window * window, float opacity)
   952 {
   953     const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   954     const HWND hwnd = data->hwnd;
   955     const LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
   956 
   957     SDL_assert(style != 0);
   958 
   959     if (opacity == 1.0f) {
   960         /* want it fully opaque, just mark it unlayered if necessary. */
   961         if (style & WS_EX_LAYERED) {
   962             if (SetWindowLong(hwnd, GWL_EXSTYLE, style & ~WS_EX_LAYERED) == 0) {
   963                 return WIN_SetError("SetWindowLong()");
   964             }
   965         }
   966     } else {
   967         const BYTE alpha = (BYTE) ((int) (opacity * 255.0f));
   968         /* want it transparent, mark it layered if necessary. */
   969         if ((style & WS_EX_LAYERED) == 0) {
   970             if (SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED) == 0) {
   971                 return WIN_SetError("SetWindowLong()");
   972             }
   973         }
   974 
   975         if (SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA) == 0) {
   976             return WIN_SetError("SetLayeredWindowAttributes()");
   977         }
   978     }
   979 
   980     return 0;
   981 }
   982 
   983 void
   984 WIN_AcceptDragAndDrop(SDL_Window * window, SDL_bool accept)
   985 {
   986     const SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   987     DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
   988 }
   989 
   990 #endif /* SDL_VIDEO_DRIVER_WINDOWS */
   991 
   992 /* vi: set ts=4 sw=4 expandtab: */