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