src/video/windows/SDL_windowswindow.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 05 Jun 2018 12:46:09 -0700
changeset 12006 1b7ed3438a7f
parent 11939 69afb0599152
child 12067 0e37a23d93cb
permissions -rw-r--r--
Fix creating a minimized window in SDL to not cause focus to be stolen (because ShowWindow( hwnd, SW_MINIMIZE ) would be called after creation, thus changing focus to the prior window based on some per-app list in windows, rather than the window being created with WS_MINIMIZED to start with).

This means we have to consider SDL_WINDOW_MINIMIZED a window creation flag, but on non-windows platforms we just remove it and let the normal FinishWindowCreation re-apply and do the minimize as I have no idea what is right on them or if anything should change.

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