sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_windowswindow.c (32126B)


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