volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

win32_window.c (81254B)


      1 //========================================================================
      2 // GLFW 3.4 Win32 (modified for raylib) - www.glfw.org; www.raylib.com
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2002-2006 Marcus Geelnard
      5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
      6 // Copyright (c) 2024 M374LX <wilsalx@gmail.com>
      7 //
      8 // This software is provided 'as-is', without any express or implied
      9 // warranty. In no event will the authors be held liable for any damages
     10 // arising from the use of this software.
     11 //
     12 // Permission is granted to anyone to use this software for any purpose,
     13 // including commercial applications, and to alter it and redistribute it
     14 // freely, subject to the following restrictions:
     15 //
     16 // 1. The origin of this software must not be misrepresented; you must not
     17 //    claim that you wrote the original software. If you use this software
     18 //    in a product, an acknowledgment in the product documentation would
     19 //    be appreciated but is not required.
     20 //
     21 // 2. Altered source versions must be plainly marked as such, and must not
     22 //    be misrepresented as being the original software.
     23 //
     24 // 3. This notice may not be removed or altered from any source
     25 //    distribution.
     26 //
     27 //========================================================================
     28 
     29 #include "internal.h"
     30 
     31 #if defined(_GLFW_WIN32)
     32 
     33 #include <limits.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <windowsx.h>
     37 #include <shellapi.h>
     38 
     39 // Returns the window style for the specified window
     40 //
     41 static DWORD getWindowStyle(const _GLFWwindow* window)
     42 {
     43     DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
     44 
     45     if (window->monitor)
     46         style |= WS_POPUP;
     47     else
     48     {
     49         style |= WS_SYSMENU | WS_MINIMIZEBOX;
     50 
     51         if (window->decorated)
     52         {
     53             style |= WS_CAPTION;
     54 
     55             if (window->resizable)
     56                 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
     57         }
     58         else
     59             style |= WS_POPUP;
     60     }
     61 
     62     return style;
     63 }
     64 
     65 // Returns the extended window style for the specified window
     66 //
     67 static DWORD getWindowExStyle(const _GLFWwindow* window)
     68 {
     69     DWORD style = WS_EX_APPWINDOW;
     70 
     71     if (window->monitor || window->floating)
     72         style |= WS_EX_TOPMOST;
     73 
     74     return style;
     75 }
     76 
     77 // Returns the image whose area most closely matches the desired one
     78 //
     79 static const GLFWimage* chooseImage(int count, const GLFWimage* images,
     80                                     int width, int height)
     81 {
     82     int i, leastDiff = INT_MAX;
     83     const GLFWimage* closest = NULL;
     84 
     85     for (i = 0;  i < count;  i++)
     86     {
     87         const int currDiff = abs(images[i].width * images[i].height -
     88                                  width * height);
     89         if (currDiff < leastDiff)
     90         {
     91             closest = images + i;
     92             leastDiff = currDiff;
     93         }
     94     }
     95 
     96     return closest;
     97 }
     98 
     99 // Creates an RGBA icon or cursor
    100 //
    101 static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon)
    102 {
    103     int i;
    104     HDC dc;
    105     HICON handle;
    106     HBITMAP color, mask;
    107     BITMAPV5HEADER bi;
    108     ICONINFO ii;
    109     unsigned char* target = NULL;
    110     unsigned char* source = image->pixels;
    111 
    112     ZeroMemory(&bi, sizeof(bi));
    113     bi.bV5Size        = sizeof(bi);
    114     bi.bV5Width       = image->width;
    115     bi.bV5Height      = -image->height;
    116     bi.bV5Planes      = 1;
    117     bi.bV5BitCount    = 32;
    118     bi.bV5Compression = BI_BITFIELDS;
    119     bi.bV5RedMask     = 0x00ff0000;
    120     bi.bV5GreenMask   = 0x0000ff00;
    121     bi.bV5BlueMask    = 0x000000ff;
    122     bi.bV5AlphaMask   = 0xff000000;
    123 
    124     dc = GetDC(NULL);
    125     color = CreateDIBSection(dc,
    126                              (BITMAPINFO*) &bi,
    127                              DIB_RGB_COLORS,
    128                              (void**) &target,
    129                              NULL,
    130                              (DWORD) 0);
    131     ReleaseDC(NULL, dc);
    132 
    133     if (!color)
    134     {
    135         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    136                              "Win32: Failed to create RGBA bitmap");
    137         return NULL;
    138     }
    139 
    140     mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
    141     if (!mask)
    142     {
    143         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    144                              "Win32: Failed to create mask bitmap");
    145         DeleteObject(color);
    146         return NULL;
    147     }
    148 
    149     for (i = 0;  i < image->width * image->height;  i++)
    150     {
    151         target[0] = source[2];
    152         target[1] = source[1];
    153         target[2] = source[0];
    154         target[3] = source[3];
    155         target += 4;
    156         source += 4;
    157     }
    158 
    159     ZeroMemory(&ii, sizeof(ii));
    160     ii.fIcon    = icon;
    161     ii.xHotspot = xhot;
    162     ii.yHotspot = yhot;
    163     ii.hbmMask  = mask;
    164     ii.hbmColor = color;
    165 
    166     handle = CreateIconIndirect(&ii);
    167 
    168     DeleteObject(color);
    169     DeleteObject(mask);
    170 
    171     if (!handle)
    172     {
    173         if (icon)
    174         {
    175             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    176                                  "Win32: Failed to create icon");
    177         }
    178         else
    179         {
    180             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    181                                  "Win32: Failed to create cursor");
    182         }
    183     }
    184 
    185     return handle;
    186 }
    187 
    188 // Enforce the content area aspect ratio based on which edge is being dragged
    189 //
    190 static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
    191 {
    192     RECT frame = {0};
    193     const float ratio = (float) window->numer / (float) window->denom;
    194     const DWORD style = getWindowStyle(window);
    195     const DWORD exStyle = getWindowExStyle(window);
    196 
    197     if (_glfwIsWindows10Version1607OrGreaterWin32())
    198     {
    199         AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
    200                                  GetDpiForWindow(window->win32.handle));
    201     }
    202     else
    203         AdjustWindowRectEx(&frame, style, FALSE, exStyle);
    204 
    205     if (edge == WMSZ_LEFT  || edge == WMSZ_BOTTOMLEFT ||
    206         edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
    207     {
    208         area->bottom = area->top + (frame.bottom - frame.top) +
    209             (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
    210     }
    211     else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
    212     {
    213         area->top = area->bottom - (frame.bottom - frame.top) -
    214             (int) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
    215     }
    216     else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
    217     {
    218         area->right = area->left + (frame.right - frame.left) +
    219             (int) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio);
    220     }
    221 }
    222 
    223 // Updates the cursor image according to its cursor mode
    224 //
    225 static void updateCursorImage(_GLFWwindow* window)
    226 {
    227     if (window->cursorMode == GLFW_CURSOR_NORMAL ||
    228         window->cursorMode == GLFW_CURSOR_CAPTURED)
    229     {
    230         if (window->cursor)
    231             SetCursor(window->cursor->win32.handle);
    232         else
    233             SetCursor(LoadCursorW(NULL, IDC_ARROW));
    234     }
    235     else
    236     {
    237         // NOTE: Via Remote Desktop, setting the cursor to NULL does not hide it.
    238         // HACK: When running locally, it is set to NULL, but when connected via Remote
    239         //       Desktop, this is a transparent cursor.
    240         SetCursor(_glfw.win32.blankCursor);
    241     }
    242 }
    243 
    244 // Sets the cursor clip rect to the window content area
    245 //
    246 static void captureCursor(_GLFWwindow* window)
    247 {
    248     RECT clipRect;
    249     GetClientRect(window->win32.handle, &clipRect);
    250     ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
    251     ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
    252     ClipCursor(&clipRect);
    253     _glfw.win32.capturedCursorWindow = window;
    254 }
    255 
    256 // Disabled clip cursor
    257 //
    258 static void releaseCursor(void)
    259 {
    260     ClipCursor(NULL);
    261     _glfw.win32.capturedCursorWindow = NULL;
    262 }
    263 
    264 // Enables WM_INPUT messages for the mouse for the specified window
    265 //
    266 static void enableRawMouseMotion(_GLFWwindow* window)
    267 {
    268     const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle };
    269 
    270     if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
    271     {
    272         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    273                              "Win32: Failed to register raw input device");
    274     }
    275 }
    276 
    277 // Disables WM_INPUT messages for the mouse
    278 //
    279 static void disableRawMouseMotion(_GLFWwindow* window)
    280 {
    281     const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL };
    282 
    283     if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
    284     {
    285         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
    286                              "Win32: Failed to remove raw input device");
    287     }
    288 }
    289 
    290 // Apply disabled cursor mode to a focused window
    291 //
    292 static void disableCursor(_GLFWwindow* window)
    293 {
    294     _glfw.win32.disabledCursorWindow = window;
    295     _glfwGetCursorPosWin32(window,
    296                            &_glfw.win32.restoreCursorPosX,
    297                            &_glfw.win32.restoreCursorPosY);
    298     updateCursorImage(window);
    299     _glfwCenterCursorInContentArea(window);
    300     captureCursor(window);
    301 
    302     if (window->rawMouseMotion)
    303         enableRawMouseMotion(window);
    304 }
    305 
    306 // Exit disabled cursor mode for the specified window
    307 //
    308 static void enableCursor(_GLFWwindow* window)
    309 {
    310     if (window->rawMouseMotion)
    311         disableRawMouseMotion(window);
    312 
    313     _glfw.win32.disabledCursorWindow = NULL;
    314     releaseCursor();
    315     _glfwSetCursorPosWin32(window,
    316                            _glfw.win32.restoreCursorPosX,
    317                            _glfw.win32.restoreCursorPosY);
    318     updateCursorImage(window);
    319 }
    320 
    321 // Returns whether the cursor is in the content area of the specified window
    322 //
    323 static GLFWbool cursorInContentArea(_GLFWwindow* window)
    324 {
    325     RECT area;
    326     POINT pos;
    327 
    328     if (!GetCursorPos(&pos))
    329         return GLFW_FALSE;
    330 
    331     if (WindowFromPoint(pos) != window->win32.handle)
    332         return GLFW_FALSE;
    333 
    334     GetClientRect(window->win32.handle, &area);
    335     ClientToScreen(window->win32.handle, (POINT*) &area.left);
    336     ClientToScreen(window->win32.handle, (POINT*) &area.right);
    337 
    338     return PtInRect(&area, pos);
    339 }
    340 
    341 // Update native window styles to match attributes
    342 //
    343 static void updateWindowStyles(const _GLFWwindow* window)
    344 {
    345     RECT rect;
    346     DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
    347     style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP);
    348     style |= getWindowStyle(window);
    349 
    350     GetClientRect(window->win32.handle, &rect);
    351 
    352     if (_glfwIsWindows10Version1607OrGreaterWin32())
    353     {
    354         AdjustWindowRectExForDpi(&rect, style, FALSE,
    355                                  getWindowExStyle(window),
    356                                  GetDpiForWindow(window->win32.handle));
    357     }
    358     else
    359         AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
    360 
    361     ClientToScreen(window->win32.handle, (POINT*) &rect.left);
    362     ClientToScreen(window->win32.handle, (POINT*) &rect.right);
    363     SetWindowLongW(window->win32.handle, GWL_STYLE, style);
    364     SetWindowPos(window->win32.handle, HWND_TOP,
    365                  rect.left, rect.top,
    366                  rect.right - rect.left, rect.bottom - rect.top,
    367                  SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
    368 }
    369 
    370 // Update window framebuffer transparency
    371 //
    372 static void updateFramebufferTransparency(const _GLFWwindow* window)
    373 {
    374     BOOL composition, opaque;
    375     DWORD color;
    376 
    377     if (!IsWindowsVistaOrGreater())
    378         return;
    379 
    380     if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
    381        return;
    382 
    383     if (IsWindows8OrGreater() ||
    384         (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque))
    385     {
    386         HRGN region = CreateRectRgn(0, 0, -1, -1);
    387         DWM_BLURBEHIND bb = {0};
    388         bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
    389         bb.hRgnBlur = region;
    390         bb.fEnable = TRUE;
    391 
    392         DwmEnableBlurBehindWindow(window->win32.handle, &bb);
    393         DeleteObject(region);
    394     }
    395     else
    396     {
    397         // HACK: Disable framebuffer transparency on Windows 7 when the
    398         //       colorization color is opaque, because otherwise the window
    399         //       contents is blended additively with the previous frame instead
    400         //       of replacing it
    401         DWM_BLURBEHIND bb = {0};
    402         bb.dwFlags = DWM_BB_ENABLE;
    403         DwmEnableBlurBehindWindow(window->win32.handle, &bb);
    404     }
    405 }
    406 
    407 // Retrieves and translates modifier keys
    408 //
    409 static int getKeyMods(void)
    410 {
    411     int mods = 0;
    412 
    413     if (GetKeyState(VK_SHIFT) & 0x8000)
    414         mods |= GLFW_MOD_SHIFT;
    415     if (GetKeyState(VK_CONTROL) & 0x8000)
    416         mods |= GLFW_MOD_CONTROL;
    417     if (GetKeyState(VK_MENU) & 0x8000)
    418         mods |= GLFW_MOD_ALT;
    419     if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
    420         mods |= GLFW_MOD_SUPER;
    421     if (GetKeyState(VK_CAPITAL) & 1)
    422         mods |= GLFW_MOD_CAPS_LOCK;
    423     if (GetKeyState(VK_NUMLOCK) & 1)
    424         mods |= GLFW_MOD_NUM_LOCK;
    425 
    426     return mods;
    427 }
    428 
    429 static void fitToMonitor(_GLFWwindow* window)
    430 {
    431     MONITORINFO mi = { sizeof(mi) };
    432     GetMonitorInfoW(window->monitor->win32.handle, &mi);
    433     SetWindowPos(window->win32.handle, HWND_TOPMOST,
    434                  mi.rcMonitor.left,
    435                  mi.rcMonitor.top,
    436                  mi.rcMonitor.right - mi.rcMonitor.left,
    437                  mi.rcMonitor.bottom - mi.rcMonitor.top,
    438                  SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
    439 }
    440 
    441 // Make the specified window and its video mode active on its monitor
    442 //
    443 static void acquireMonitorWin32(_GLFWwindow* window)
    444 {
    445     if (!_glfw.win32.acquiredMonitorCount)
    446     {
    447         SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
    448 
    449         // HACK: When mouse trails are enabled the cursor becomes invisible when
    450         //       the OpenGL ICD switches to page flipping
    451         SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
    452         SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0);
    453     }
    454 
    455     if (!window->monitor->window)
    456         _glfw.win32.acquiredMonitorCount++;
    457 
    458     _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
    459     _glfwInputMonitorWindow(window->monitor, window);
    460 }
    461 
    462 // Remove the window and restore the original video mode
    463 //
    464 static void releaseMonitorWin32(_GLFWwindow* window)
    465 {
    466     if (window->monitor->window != window)
    467         return;
    468 
    469     _glfw.win32.acquiredMonitorCount--;
    470     if (!_glfw.win32.acquiredMonitorCount)
    471     {
    472         SetThreadExecutionState(ES_CONTINUOUS);
    473 
    474         // HACK: Restore mouse trail length saved in acquireMonitorWin32
    475         SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
    476     }
    477 
    478     _glfwInputMonitorWindow(window->monitor, NULL);
    479     _glfwRestoreVideoModeWin32(window->monitor);
    480 }
    481 
    482 // Manually maximize the window, for when SW_MAXIMIZE cannot be used
    483 //
    484 static void maximizeWindowManually(_GLFWwindow* window)
    485 {
    486     RECT rect;
    487     DWORD style;
    488     MONITORINFO mi = { sizeof(mi) };
    489 
    490     GetMonitorInfoW(MonitorFromWindow(window->win32.handle,
    491                                       MONITOR_DEFAULTTONEAREST), &mi);
    492 
    493     rect = mi.rcWork;
    494 
    495     if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
    496     {
    497         rect.right = _glfw_min(rect.right, rect.left + window->maxwidth);
    498         rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight);
    499     }
    500 
    501     style = GetWindowLongW(window->win32.handle, GWL_STYLE);
    502     style |= WS_MAXIMIZE;
    503     SetWindowLongW(window->win32.handle, GWL_STYLE, style);
    504 
    505     if (window->decorated)
    506     {
    507         const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
    508 
    509         if (_glfwIsWindows10Version1607OrGreaterWin32())
    510         {
    511             const UINT dpi = GetDpiForWindow(window->win32.handle);
    512             AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
    513             OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi));
    514         }
    515         else
    516         {
    517             AdjustWindowRectEx(&rect, style, FALSE, exStyle);
    518             OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION));
    519         }
    520 
    521         rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom);
    522     }
    523 
    524     SetWindowPos(window->win32.handle, HWND_TOP,
    525                  rect.left,
    526                  rect.top,
    527                  rect.right - rect.left,
    528                  rect.bottom - rect.top,
    529                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
    530 }
    531 
    532 // Window procedure for user-created windows
    533 //
    534 static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    535 {
    536     _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
    537     if (!window)
    538     {
    539         if (uMsg == WM_NCCREATE)
    540         {
    541             if (_glfwIsWindows10Version1607OrGreaterWin32())
    542             {
    543                 const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;
    544                 const _GLFWwndconfig* wndconfig = cs->lpCreateParams;
    545 
    546                 // On per-monitor DPI aware V1 systems, only enable
    547                 // non-client scaling for windows that scale the client area
    548                 // We need WM_GETDPISCALEDSIZE from V2 to keep the client
    549                 // area static when the non-client area is scaled
    550                 if (wndconfig && wndconfig->scaleToMonitor)
    551                     EnableNonClientDpiScaling(hWnd);
    552             }
    553         }
    554 
    555         return DefWindowProcW(hWnd, uMsg, wParam, lParam);
    556     }
    557 
    558     switch (uMsg)
    559     {
    560         case WM_MOUSEACTIVATE:
    561         {
    562             // HACK: Postpone cursor disabling when the window was activated by
    563             //       clicking a caption button
    564             if (HIWORD(lParam) == WM_LBUTTONDOWN)
    565             {
    566                 if (LOWORD(lParam) != HTCLIENT)
    567                     window->win32.frameAction = GLFW_TRUE;
    568             }
    569 
    570             break;
    571         }
    572 
    573         case WM_CAPTURECHANGED:
    574         {
    575             // HACK: Disable the cursor once the caption button action has been
    576             //       completed or cancelled
    577             if (lParam == 0 && window->win32.frameAction)
    578             {
    579                 if (window->cursorMode == GLFW_CURSOR_DISABLED)
    580                     disableCursor(window);
    581                 else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
    582                     captureCursor(window);
    583 
    584                 window->win32.frameAction = GLFW_FALSE;
    585             }
    586 
    587             break;
    588         }
    589 
    590         case WM_SETFOCUS:
    591         {
    592             _glfwInputWindowFocus(window, GLFW_TRUE);
    593 
    594             // HACK: Do not disable cursor while the user is interacting with
    595             //       a caption button
    596             if (window->win32.frameAction)
    597                 break;
    598 
    599             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    600                 disableCursor(window);
    601             else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
    602                 captureCursor(window);
    603 
    604             return 0;
    605         }
    606 
    607         case WM_KILLFOCUS:
    608         {
    609             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    610                 enableCursor(window);
    611             else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
    612                 releaseCursor();
    613 
    614             if (window->monitor && window->autoIconify)
    615                 _glfwIconifyWindowWin32(window);
    616 
    617             _glfwInputWindowFocus(window, GLFW_FALSE);
    618             return 0;
    619         }
    620 
    621         case WM_SYSCOMMAND:
    622         {
    623             switch (wParam & 0xfff0)
    624             {
    625                 case SC_SCREENSAVE:
    626                 case SC_MONITORPOWER:
    627                 {
    628                     if (window->monitor)
    629                     {
    630                         // We are running in full screen mode, so disallow
    631                         // screen saver and screen blanking
    632                         return 0;
    633                     }
    634                     else
    635                         break;
    636                 }
    637 
    638                 // User trying to access application menu using ALT?
    639                 case SC_KEYMENU:
    640                 {
    641                     if (!window->win32.keymenu)
    642                         return 0;
    643 
    644                     break;
    645                 }
    646             }
    647             break;
    648         }
    649 
    650         case WM_CLOSE:
    651         {
    652             _glfwInputWindowCloseRequest(window);
    653             return 0;
    654         }
    655 
    656         case WM_INPUTLANGCHANGE:
    657         {
    658             _glfwUpdateKeyNamesWin32();
    659             break;
    660         }
    661 
    662         case WM_CHAR:
    663         case WM_SYSCHAR:
    664         {
    665             if (wParam >= 0xd800 && wParam <= 0xdbff)
    666                 window->win32.highSurrogate = (WCHAR) wParam;
    667             else
    668             {
    669                 uint32_t codepoint = 0;
    670 
    671                 if (wParam >= 0xdc00 && wParam <= 0xdfff)
    672                 {
    673                     if (window->win32.highSurrogate)
    674                     {
    675                         codepoint += (window->win32.highSurrogate - 0xd800) << 10;
    676                         codepoint += (WCHAR) wParam - 0xdc00;
    677                         codepoint += 0x10000;
    678                     }
    679                 }
    680                 else
    681                     codepoint = (WCHAR) wParam;
    682 
    683                 window->win32.highSurrogate = 0;
    684                 _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR);
    685             }
    686 
    687             if (uMsg == WM_SYSCHAR && window->win32.keymenu)
    688                 break;
    689 
    690             return 0;
    691         }
    692 
    693         case WM_UNICHAR:
    694         {
    695             if (wParam == UNICODE_NOCHAR)
    696             {
    697                 // WM_UNICHAR is not sent by Windows, but is sent by some
    698                 // third-party input method engine
    699                 // Returning TRUE here announces support for this message
    700                 return TRUE;
    701             }
    702 
    703             _glfwInputChar(window, (uint32_t) wParam, getKeyMods(), GLFW_TRUE);
    704             return 0;
    705         }
    706 
    707         case WM_KEYDOWN:
    708         case WM_SYSKEYDOWN:
    709         case WM_KEYUP:
    710         case WM_SYSKEYUP:
    711         {
    712             int key, scancode;
    713             const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS;
    714             const int mods = getKeyMods();
    715 
    716             scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
    717             if (!scancode)
    718             {
    719                 // NOTE: Some synthetic key messages have a scancode of zero
    720                 // HACK: Map the virtual key back to a usable scancode
    721                 scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
    722             }
    723 
    724             // HACK: Alt+PrtSc has a different scancode than just PrtSc
    725             if (scancode == 0x54)
    726                 scancode = 0x137;
    727 
    728             // HACK: Ctrl+Pause has a different scancode than just Pause
    729             if (scancode == 0x146)
    730                 scancode = 0x45;
    731 
    732             // HACK: CJK IME sets the extended bit for right Shift
    733             if (scancode == 0x136)
    734                 scancode = 0x36;
    735 
    736             key = _glfw.win32.keycodes[scancode];
    737 
    738             // The Ctrl keys require special handling
    739             if (wParam == VK_CONTROL)
    740             {
    741                 if (HIWORD(lParam) & KF_EXTENDED)
    742                 {
    743                     // Right side keys have the extended key bit set
    744                     key = GLFW_KEY_RIGHT_CONTROL;
    745                 }
    746                 else
    747                 {
    748                     // NOTE: Alt Gr sends Left Ctrl followed by Right Alt
    749                     // HACK: We only want one event for Alt Gr, so if we detect
    750                     //       this sequence we discard this Left Ctrl message now
    751                     //       and later report Right Alt normally
    752                     MSG next;
    753                     const DWORD time = GetMessageTime();
    754 
    755                     if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
    756                     {
    757                         if (next.message == WM_KEYDOWN ||
    758                             next.message == WM_SYSKEYDOWN ||
    759                             next.message == WM_KEYUP ||
    760                             next.message == WM_SYSKEYUP)
    761                         {
    762                             if (next.wParam == VK_MENU &&
    763                                 (HIWORD(next.lParam) & KF_EXTENDED) &&
    764                                 next.time == time)
    765                             {
    766                                 // Next message is Right Alt down so discard this
    767                                 break;
    768                             }
    769                         }
    770                     }
    771 
    772                     // This is a regular Left Ctrl message
    773                     key = GLFW_KEY_LEFT_CONTROL;
    774                 }
    775             }
    776             else if (wParam == VK_PROCESSKEY)
    777             {
    778                 // IME notifies that keys have been filtered by setting the
    779                 // virtual key-code to VK_PROCESSKEY
    780                 break;
    781             }
    782 
    783             if (action == GLFW_RELEASE && wParam == VK_SHIFT)
    784             {
    785                 // HACK: Release both Shift keys on Shift up event, as when both
    786                 //       are pressed the first release does not emit any event
    787                 // NOTE: The other half of this is in _glfwPollEventsWin32
    788                 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods);
    789                 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods);
    790             }
    791             else if (wParam == VK_SNAPSHOT)
    792             {
    793                 // HACK: Key down is not reported for the Print Screen key
    794                 _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
    795                 _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
    796             }
    797             else
    798                 _glfwInputKey(window, key, scancode, action, mods);
    799 
    800             break;
    801         }
    802 
    803         case WM_LBUTTONDOWN:
    804         case WM_RBUTTONDOWN:
    805         case WM_MBUTTONDOWN:
    806         case WM_XBUTTONDOWN:
    807         case WM_LBUTTONUP:
    808         case WM_RBUTTONUP:
    809         case WM_MBUTTONUP:
    810         case WM_XBUTTONUP:
    811         {
    812             int i, button, action;
    813 
    814             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
    815                 button = GLFW_MOUSE_BUTTON_LEFT;
    816             else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP)
    817                 button = GLFW_MOUSE_BUTTON_RIGHT;
    818             else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
    819                 button = GLFW_MOUSE_BUTTON_MIDDLE;
    820             else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
    821                 button = GLFW_MOUSE_BUTTON_4;
    822             else
    823                 button = GLFW_MOUSE_BUTTON_5;
    824 
    825             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN ||
    826                 uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN)
    827             {
    828                 action = GLFW_PRESS;
    829             }
    830             else
    831                 action = GLFW_RELEASE;
    832 
    833             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
    834             {
    835                 if (window->mouseButtons[i] == GLFW_PRESS)
    836                     break;
    837             }
    838 
    839             if (i > GLFW_MOUSE_BUTTON_LAST)
    840                 SetCapture(hWnd);
    841 
    842             _glfwInputMouseClick(window, button, action, getKeyMods());
    843 
    844             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
    845             {
    846                 if (window->mouseButtons[i] == GLFW_PRESS)
    847                     break;
    848             }
    849 
    850             if (i > GLFW_MOUSE_BUTTON_LAST)
    851                 ReleaseCapture();
    852 
    853             if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
    854                 return TRUE;
    855 
    856             return 0;
    857         }
    858 
    859         case WM_MOUSEMOVE:
    860         {
    861             const int x = GET_X_LPARAM(lParam);
    862             const int y = GET_Y_LPARAM(lParam);
    863 
    864             if (!window->win32.cursorTracked)
    865             {
    866                 TRACKMOUSEEVENT tme;
    867                 ZeroMemory(&tme, sizeof(tme));
    868                 tme.cbSize = sizeof(tme);
    869                 tme.dwFlags = TME_LEAVE;
    870                 tme.hwndTrack = window->win32.handle;
    871                 TrackMouseEvent(&tme);
    872 
    873                 window->win32.cursorTracked = GLFW_TRUE;
    874                 _glfwInputCursorEnter(window, GLFW_TRUE);
    875             }
    876 
    877             if (window->cursorMode == GLFW_CURSOR_DISABLED)
    878             {
    879                 const int dx = x - window->win32.lastCursorPosX;
    880                 const int dy = y - window->win32.lastCursorPosY;
    881 
    882                 if (_glfw.win32.disabledCursorWindow != window)
    883                     break;
    884                 if (window->rawMouseMotion)
    885                     break;
    886 
    887                 _glfwInputCursorPos(window,
    888                                     window->virtualCursorPosX + dx,
    889                                     window->virtualCursorPosY + dy);
    890             }
    891             else
    892                 _glfwInputCursorPos(window, x, y);
    893 
    894             window->win32.lastCursorPosX = x;
    895             window->win32.lastCursorPosY = y;
    896 
    897             return 0;
    898         }
    899 
    900         case WM_INPUT:
    901         {
    902             UINT size = 0;
    903             HRAWINPUT ri = (HRAWINPUT) lParam;
    904             RAWINPUT* data = NULL;
    905             int dx, dy;
    906 
    907             if (_glfw.win32.disabledCursorWindow != window)
    908                 break;
    909             if (!window->rawMouseMotion)
    910                 break;
    911 
    912             GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
    913             if (size > (UINT) _glfw.win32.rawInputSize)
    914             {
    915                 _glfw_free(_glfw.win32.rawInput);
    916                 _glfw.win32.rawInput = _glfw_calloc(size, 1);
    917                 _glfw.win32.rawInputSize = size;
    918             }
    919 
    920             size = _glfw.win32.rawInputSize;
    921             if (GetRawInputData(ri, RID_INPUT,
    922                                 _glfw.win32.rawInput, &size,
    923                                 sizeof(RAWINPUTHEADER)) == (UINT) -1)
    924             {
    925                 _glfwInputError(GLFW_PLATFORM_ERROR,
    926                                 "Win32: Failed to retrieve raw input data");
    927                 break;
    928             }
    929 
    930             data = _glfw.win32.rawInput;
    931             if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
    932             {
    933                 POINT pos = {0};
    934                 int width, height;
    935 
    936                 if (data->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP)
    937                 {
    938                     pos.x += GetSystemMetrics(SM_XVIRTUALSCREEN);
    939                     pos.y += GetSystemMetrics(SM_YVIRTUALSCREEN);
    940                     width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
    941                     height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
    942                 }
    943                 else
    944                 {
    945                     width = GetSystemMetrics(SM_CXSCREEN);
    946                     height = GetSystemMetrics(SM_CYSCREEN);
    947                 }
    948 
    949                 pos.x += (int) ((data->data.mouse.lLastX / 65535.f) * width);
    950                 pos.y += (int) ((data->data.mouse.lLastY / 65535.f) * height);
    951                 ScreenToClient(window->win32.handle, &pos);
    952 
    953                 dx = pos.x - window->win32.lastCursorPosX;
    954                 dy = pos.y - window->win32.lastCursorPosY;
    955             }
    956             else
    957             {
    958                 dx = data->data.mouse.lLastX;
    959                 dy = data->data.mouse.lLastY;
    960             }
    961 
    962             _glfwInputCursorPos(window,
    963                                 window->virtualCursorPosX + dx,
    964                                 window->virtualCursorPosY + dy);
    965 
    966             window->win32.lastCursorPosX += dx;
    967             window->win32.lastCursorPosY += dy;
    968             break;
    969         }
    970 
    971         case WM_MOUSELEAVE:
    972         {
    973             window->win32.cursorTracked = GLFW_FALSE;
    974             _glfwInputCursorEnter(window, GLFW_FALSE);
    975             return 0;
    976         }
    977 
    978         case WM_MOUSEWHEEL:
    979         {
    980             _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
    981             return 0;
    982         }
    983 
    984         case WM_MOUSEHWHEEL:
    985         {
    986             // This message is only sent on Windows Vista and later
    987             // NOTE: The X-axis is inverted for consistency with macOS and X11
    988             _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
    989             return 0;
    990         }
    991 
    992         case WM_ENTERSIZEMOVE:
    993         case WM_ENTERMENULOOP:
    994         {
    995             if (window->win32.frameAction)
    996                 break;
    997 
    998             // HACK: Enable the cursor while the user is moving or
    999             //       resizing the window or using the window menu
   1000             if (window->cursorMode == GLFW_CURSOR_DISABLED)
   1001                 enableCursor(window);
   1002             else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
   1003                 releaseCursor();
   1004 
   1005             break;
   1006         }
   1007 
   1008         case WM_EXITSIZEMOVE:
   1009         case WM_EXITMENULOOP:
   1010         {
   1011             if (window->win32.frameAction)
   1012                 break;
   1013 
   1014             // HACK: Disable the cursor once the user is done moving or
   1015             //       resizing the window or using the menu
   1016             if (window->cursorMode == GLFW_CURSOR_DISABLED)
   1017                 disableCursor(window);
   1018             else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
   1019                 captureCursor(window);
   1020 
   1021             break;
   1022         }
   1023 
   1024         case WM_SIZE:
   1025         {
   1026             const int width = LOWORD(lParam);
   1027             const int height = HIWORD(lParam);
   1028             const GLFWbool iconified = wParam == SIZE_MINIMIZED;
   1029             const GLFWbool maximized = wParam == SIZE_MAXIMIZED ||
   1030                                        (window->win32.maximized &&
   1031                                         wParam != SIZE_RESTORED);
   1032 
   1033             if (_glfw.win32.capturedCursorWindow == window)
   1034                 captureCursor(window);
   1035 
   1036             if (window->win32.iconified != iconified)
   1037                 _glfwInputWindowIconify(window, iconified);
   1038 
   1039             if (window->win32.maximized != maximized)
   1040                 _glfwInputWindowMaximize(window, maximized);
   1041 
   1042             if (width != window->win32.width || height != window->win32.height)
   1043             {
   1044                 window->win32.width = width;
   1045                 window->win32.height = height;
   1046 
   1047                 _glfwInputFramebufferSize(window, width, height);
   1048                 _glfwInputWindowSize(window, width, height);
   1049             }
   1050 
   1051             if (window->monitor && window->win32.iconified != iconified)
   1052             {
   1053                 if (iconified)
   1054                     releaseMonitorWin32(window);
   1055                 else
   1056                 {
   1057                     acquireMonitorWin32(window);
   1058                     fitToMonitor(window);
   1059                 }
   1060             }
   1061 
   1062             window->win32.iconified = iconified;
   1063             window->win32.maximized = maximized;
   1064             return 0;
   1065         }
   1066 
   1067         case WM_MOVE:
   1068         {
   1069             if (_glfw.win32.capturedCursorWindow == window)
   1070                 captureCursor(window);
   1071 
   1072             // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
   1073             // those macros do not handle negative window positions correctly
   1074             _glfwInputWindowPos(window,
   1075                                 GET_X_LPARAM(lParam),
   1076                                 GET_Y_LPARAM(lParam));
   1077             return 0;
   1078         }
   1079 
   1080         case WM_SIZING:
   1081         {
   1082             if (window->numer == GLFW_DONT_CARE ||
   1083                 window->denom == GLFW_DONT_CARE)
   1084             {
   1085                 break;
   1086             }
   1087 
   1088             applyAspectRatio(window, (int) wParam, (RECT*) lParam);
   1089             return TRUE;
   1090         }
   1091 
   1092         case WM_GETMINMAXINFO:
   1093         {
   1094             RECT frame = {0};
   1095             MINMAXINFO* mmi = (MINMAXINFO*) lParam;
   1096             const DWORD style = getWindowStyle(window);
   1097             const DWORD exStyle = getWindowExStyle(window);
   1098 
   1099             if (window->monitor)
   1100                 break;
   1101 
   1102             if (_glfwIsWindows10Version1607OrGreaterWin32())
   1103             {
   1104                 AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
   1105                                          GetDpiForWindow(window->win32.handle));
   1106             }
   1107             else
   1108                 AdjustWindowRectEx(&frame, style, FALSE, exStyle);
   1109 
   1110             if (window->minwidth != GLFW_DONT_CARE &&
   1111                 window->minheight != GLFW_DONT_CARE)
   1112             {
   1113                 mmi->ptMinTrackSize.x = window->minwidth + frame.right - frame.left;
   1114                 mmi->ptMinTrackSize.y = window->minheight + frame.bottom - frame.top;
   1115             }
   1116 
   1117             if (window->maxwidth != GLFW_DONT_CARE &&
   1118                 window->maxheight != GLFW_DONT_CARE)
   1119             {
   1120                 mmi->ptMaxTrackSize.x = window->maxwidth + frame.right - frame.left;
   1121                 mmi->ptMaxTrackSize.y = window->maxheight + frame.bottom - frame.top;
   1122             }
   1123 
   1124             if (!window->decorated)
   1125             {
   1126                 MONITORINFO mi;
   1127                 const HMONITOR mh = MonitorFromWindow(window->win32.handle,
   1128                                                       MONITOR_DEFAULTTONEAREST);
   1129 
   1130                 ZeroMemory(&mi, sizeof(mi));
   1131                 mi.cbSize = sizeof(mi);
   1132                 GetMonitorInfoW(mh, &mi);
   1133 
   1134                 mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
   1135                 mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
   1136                 mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left;
   1137                 mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top;
   1138             }
   1139 
   1140             return 0;
   1141         }
   1142 
   1143         case WM_PAINT:
   1144         {
   1145             _glfwInputWindowDamage(window);
   1146             break;
   1147         }
   1148 
   1149         case WM_ERASEBKGND:
   1150         {
   1151             return TRUE;
   1152         }
   1153 
   1154         case WM_NCACTIVATE:
   1155         case WM_NCPAINT:
   1156         {
   1157             // Prevent title bar from being drawn after restoring a minimized
   1158             // undecorated window
   1159             if (!window->decorated)
   1160                 return TRUE;
   1161 
   1162             break;
   1163         }
   1164 
   1165         case WM_DWMCOMPOSITIONCHANGED:
   1166         case WM_DWMCOLORIZATIONCOLORCHANGED:
   1167         {
   1168             if (window->win32.transparent)
   1169                 updateFramebufferTransparency(window);
   1170             return 0;
   1171         }
   1172 
   1173         case WM_GETDPISCALEDSIZE:
   1174         {
   1175             if (window->win32.scaleToMonitor)
   1176                 break;
   1177 
   1178             // Adjust the window size to keep the content area size constant
   1179             if (_glfwIsWindows10Version1703OrGreaterWin32())
   1180             {
   1181                 RECT source = {0}, target = {0};
   1182                 SIZE* size = (SIZE*) lParam;
   1183 
   1184                 AdjustWindowRectExForDpi(&source, getWindowStyle(window),
   1185                                          FALSE, getWindowExStyle(window),
   1186                                          GetDpiForWindow(window->win32.handle));
   1187                 AdjustWindowRectExForDpi(&target, getWindowStyle(window),
   1188                                          FALSE, getWindowExStyle(window),
   1189                                          LOWORD(wParam));
   1190 
   1191                 size->cx += (target.right - target.left) -
   1192                             (source.right - source.left);
   1193                 size->cy += (target.bottom - target.top) -
   1194                             (source.bottom - source.top);
   1195                 return TRUE;
   1196             }
   1197 
   1198             break;
   1199         }
   1200 
   1201         case WM_DPICHANGED:
   1202         {
   1203             const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
   1204             const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
   1205 
   1206             // Resize windowed mode windows that either permit rescaling or that
   1207             // need it to compensate for non-client area scaling
   1208             if (!window->monitor &&
   1209                 (window->win32.scaleToMonitor ||
   1210                  _glfwIsWindows10Version1703OrGreaterWin32()))
   1211             {
   1212                 RECT* suggested = (RECT*) lParam;
   1213                 SetWindowPos(window->win32.handle, HWND_TOP,
   1214                              suggested->left,
   1215                              suggested->top,
   1216                              suggested->right - suggested->left,
   1217                              suggested->bottom - suggested->top,
   1218                              SWP_NOACTIVATE | SWP_NOZORDER);
   1219             }
   1220 
   1221             _glfwInputWindowContentScale(window, xscale, yscale);
   1222             break;
   1223         }
   1224 
   1225         case WM_SETCURSOR:
   1226         {
   1227             if (LOWORD(lParam) == HTCLIENT)
   1228             {
   1229                 updateCursorImage(window);
   1230                 return TRUE;
   1231             }
   1232 
   1233             break;
   1234         }
   1235 
   1236         case WM_DROPFILES:
   1237         {
   1238             HDROP drop = (HDROP) wParam;
   1239             POINT pt;
   1240             int i;
   1241 
   1242             const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
   1243             char** paths = _glfw_calloc(count, sizeof(char*));
   1244 
   1245             // Move the mouse to the position of the drop
   1246             DragQueryPoint(drop, &pt);
   1247             _glfwInputCursorPos(window, pt.x, pt.y);
   1248 
   1249             for (i = 0;  i < count;  i++)
   1250             {
   1251                 const UINT length = DragQueryFileW(drop, i, NULL, 0);
   1252                 WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR));
   1253 
   1254                 DragQueryFileW(drop, i, buffer, length + 1);
   1255                 paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
   1256 
   1257                 _glfw_free(buffer);
   1258             }
   1259 
   1260             _glfwInputDrop(window, count, (const char**) paths);
   1261 
   1262             for (i = 0;  i < count;  i++)
   1263                 _glfw_free(paths[i]);
   1264             _glfw_free(paths);
   1265 
   1266             DragFinish(drop);
   1267             return 0;
   1268         }
   1269     }
   1270 
   1271     return DefWindowProcW(hWnd, uMsg, wParam, lParam);
   1272 }
   1273 
   1274 // Creates the GLFW window
   1275 //
   1276 static int createNativeWindow(_GLFWwindow* window,
   1277                               const _GLFWwndconfig* wndconfig,
   1278                               const _GLFWfbconfig* fbconfig)
   1279 {
   1280     int frameX, frameY, frameWidth, frameHeight;
   1281     WCHAR* wideTitle;
   1282     DWORD style = getWindowStyle(window);
   1283     DWORD exStyle = getWindowExStyle(window);
   1284 
   1285     if (!_glfw.win32.mainWindowClass)
   1286     {
   1287         WNDCLASSEXW wc = { sizeof(wc) };
   1288         wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
   1289         wc.lpfnWndProc   = windowProc;
   1290         wc.hInstance     = _glfw.win32.instance;
   1291         wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
   1292 #if defined(_GLFW_WNDCLASSNAME)
   1293         wc.lpszClassName = _GLFW_WNDCLASSNAME;
   1294 #else
   1295         wc.lpszClassName = L"GLFW30";
   1296 #endif
   1297         // Load user-provided icon if available
   1298         wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
   1299                               L"GLFW_ICON", IMAGE_ICON,
   1300                               0, 0, LR_DEFAULTSIZE | LR_SHARED);
   1301         if (!wc.hIcon)
   1302         {
   1303             // No user-provided icon found, load default icon
   1304             wc.hIcon = LoadImageW(NULL,
   1305                                   IDI_APPLICATION, IMAGE_ICON,
   1306                                   0, 0, LR_DEFAULTSIZE | LR_SHARED);
   1307         }
   1308 
   1309         _glfw.win32.mainWindowClass = RegisterClassExW(&wc);
   1310         if (!_glfw.win32.mainWindowClass)
   1311         {
   1312             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1313                                  "Win32: Failed to register window class");
   1314             return GLFW_FALSE;
   1315         }
   1316     }
   1317 
   1318     if (GetSystemMetrics(SM_REMOTESESSION))
   1319     {
   1320         // NOTE: On Remote Desktop, setting the cursor to NULL does not hide it
   1321         // HACK: Create a transparent cursor and always set that instead of NULL
   1322         //       When not on Remote Desktop, this handle is NULL and normal hiding is used
   1323         if (!_glfw.win32.blankCursor)
   1324         {
   1325             const int cursorWidth = GetSystemMetrics(SM_CXCURSOR);
   1326             const int cursorHeight = GetSystemMetrics(SM_CYCURSOR);
   1327 
   1328             unsigned char* cursorPixels = _glfw_calloc(cursorWidth * cursorHeight, 4);
   1329             if (!cursorPixels)
   1330                 return GLFW_FALSE;
   1331 
   1332             // NOTE: Windows checks whether the image is fully transparent and if so
   1333             //       just ignores the alpha channel and makes the whole cursor opaque
   1334             // HACK: Make one pixel slightly less transparent
   1335             cursorPixels[3] = 1;
   1336 
   1337             const GLFWimage cursorImage = { cursorWidth, cursorHeight, cursorPixels };
   1338             _glfw.win32.blankCursor = createIcon(&cursorImage, 0, 0, FALSE);
   1339             _glfw_free(cursorPixels);
   1340 
   1341             if (!_glfw.win32.blankCursor)
   1342                 return GLFW_FALSE;
   1343         }
   1344     }
   1345 
   1346     if (window->monitor)
   1347     {
   1348         MONITORINFO mi = { sizeof(mi) };
   1349         GetMonitorInfoW(window->monitor->win32.handle, &mi);
   1350 
   1351         // NOTE: This window placement is temporary and approximate, as the
   1352         //       correct position and size cannot be known until the monitor
   1353         //       video mode has been picked in _glfwSetVideoModeWin32
   1354         frameX = mi.rcMonitor.left;
   1355         frameY = mi.rcMonitor.top;
   1356         frameWidth  = mi.rcMonitor.right - mi.rcMonitor.left;
   1357         frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
   1358     }
   1359     else
   1360     {
   1361         RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
   1362 
   1363         window->win32.maximized = wndconfig->maximized;
   1364         if (wndconfig->maximized)
   1365             style |= WS_MAXIMIZE;
   1366 
   1367         AdjustWindowRectEx(&rect, style, FALSE, exStyle);
   1368 
   1369         if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
   1370         {
   1371             frameX = CW_USEDEFAULT;
   1372             frameY = CW_USEDEFAULT;
   1373         }
   1374         else
   1375         {
   1376             frameX = wndconfig->xpos + rect.left;
   1377             frameY = wndconfig->ypos + rect.top;
   1378         }
   1379 
   1380         frameWidth  = rect.right - rect.left;
   1381         frameHeight = rect.bottom - rect.top;
   1382     }
   1383 
   1384     wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
   1385     if (!wideTitle)
   1386         return GLFW_FALSE;
   1387 
   1388     window->win32.handle = CreateWindowExW(exStyle,
   1389                                            MAKEINTATOM(_glfw.win32.mainWindowClass),
   1390                                            wideTitle,
   1391                                            style,
   1392                                            frameX, frameY,
   1393                                            frameWidth, frameHeight,
   1394                                            NULL, // No parent window
   1395                                            NULL, // No window menu
   1396                                            _glfw.win32.instance,
   1397                                            (LPVOID) wndconfig);
   1398 
   1399     _glfw_free(wideTitle);
   1400 
   1401     if (!window->win32.handle)
   1402     {
   1403         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   1404                              "Win32: Failed to create window");
   1405         return GLFW_FALSE;
   1406     }
   1407 
   1408     SetPropW(window->win32.handle, L"GLFW", window);
   1409 
   1410     if (IsWindows7OrGreater())
   1411     {
   1412         ChangeWindowMessageFilterEx(window->win32.handle,
   1413                                     WM_DROPFILES, MSGFLT_ALLOW, NULL);
   1414         ChangeWindowMessageFilterEx(window->win32.handle,
   1415                                     WM_COPYDATA, MSGFLT_ALLOW, NULL);
   1416         ChangeWindowMessageFilterEx(window->win32.handle,
   1417                                     WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
   1418     }
   1419 
   1420     window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
   1421     window->win32.keymenu = wndconfig->win32.keymenu;
   1422     window->win32.showDefault = wndconfig->win32.showDefault;
   1423 
   1424     if (!window->monitor)
   1425     {
   1426         RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
   1427         WINDOWPLACEMENT wp = { sizeof(wp) };
   1428         const HMONITOR mh = MonitorFromWindow(window->win32.handle,
   1429                                               MONITOR_DEFAULTTONEAREST);
   1430 
   1431         // Adjust window rect to account for DPI scaling of the window frame and
   1432         // (if enabled) DPI scaling of the content area
   1433         // This cannot be done until we know what monitor the window was placed on
   1434         // Only update the restored window rect as the window may be maximized
   1435 
   1436         if (wndconfig->scaleToMonitor)
   1437         {
   1438             float xscale, yscale;
   1439             _glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale);
   1440 
   1441             if (xscale > 0.f && yscale > 0.f)
   1442             {
   1443                 rect.right = (int) (rect.right * xscale);
   1444                 rect.bottom = (int) (rect.bottom * yscale);
   1445             }
   1446         }
   1447 
   1448         if (_glfwIsWindows10Version1607OrGreaterWin32())
   1449         {
   1450             AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
   1451                                      GetDpiForWindow(window->win32.handle));
   1452         }
   1453         else
   1454             AdjustWindowRectEx(&rect, style, FALSE, exStyle);
   1455 
   1456         GetWindowPlacement(window->win32.handle, &wp);
   1457         OffsetRect(&rect,
   1458                    wp.rcNormalPosition.left - rect.left,
   1459                    wp.rcNormalPosition.top - rect.top);
   1460 
   1461         wp.rcNormalPosition = rect;
   1462         wp.showCmd = SW_HIDE;
   1463         SetWindowPlacement(window->win32.handle, &wp);
   1464 
   1465         // Adjust rect of maximized undecorated window, because by default Windows will
   1466         // make such a window cover the whole monitor instead of its workarea
   1467 
   1468         if (wndconfig->maximized && !wndconfig->decorated)
   1469         {
   1470             MONITORINFO mi = { sizeof(mi) };
   1471             GetMonitorInfoW(mh, &mi);
   1472 
   1473             SetWindowPos(window->win32.handle, HWND_TOP,
   1474                          mi.rcWork.left,
   1475                          mi.rcWork.top,
   1476                          mi.rcWork.right - mi.rcWork.left,
   1477                          mi.rcWork.bottom - mi.rcWork.top,
   1478                          SWP_NOACTIVATE | SWP_NOZORDER);
   1479         }
   1480     }
   1481 
   1482     DragAcceptFiles(window->win32.handle, TRUE);
   1483 
   1484     if (fbconfig->transparent)
   1485     {
   1486         updateFramebufferTransparency(window);
   1487         window->win32.transparent = GLFW_TRUE;
   1488     }
   1489 
   1490     _glfwGetWindowSizeWin32(window, &window->win32.width, &window->win32.height);
   1491 
   1492     return GLFW_TRUE;
   1493 }
   1494 
   1495 GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window,
   1496                                 const _GLFWwndconfig* wndconfig,
   1497                                 const _GLFWctxconfig* ctxconfig,
   1498                                 const _GLFWfbconfig* fbconfig)
   1499 {
   1500     if (!createNativeWindow(window, wndconfig, fbconfig))
   1501         return GLFW_FALSE;
   1502 
   1503     if (ctxconfig->client != GLFW_NO_API)
   1504     {
   1505         if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
   1506         {
   1507             if (!_glfwInitWGL())
   1508                 return GLFW_FALSE;
   1509             if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
   1510                 return GLFW_FALSE;
   1511         }
   1512         else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
   1513         {
   1514             if (!_glfwInitEGL())
   1515                 return GLFW_FALSE;
   1516             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
   1517                 return GLFW_FALSE;
   1518         }
   1519         else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
   1520         {
   1521             if (!_glfwInitOSMesa())
   1522                 return GLFW_FALSE;
   1523             if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
   1524                 return GLFW_FALSE;
   1525         }
   1526 
   1527         if (!_glfwRefreshContextAttribs(window, ctxconfig))
   1528             return GLFW_FALSE;
   1529     }
   1530 
   1531     if (wndconfig->mousePassthrough)
   1532         _glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE);
   1533 
   1534     if (window->monitor)
   1535     {
   1536         _glfwShowWindowWin32(window);
   1537         _glfwFocusWindowWin32(window);
   1538         acquireMonitorWin32(window);
   1539         fitToMonitor(window);
   1540 
   1541         if (wndconfig->centerCursor)
   1542             _glfwCenterCursorInContentArea(window);
   1543     }
   1544     else
   1545     {
   1546         if (wndconfig->visible)
   1547         {
   1548             _glfwShowWindowWin32(window);
   1549             if (wndconfig->focused)
   1550                 _glfwFocusWindowWin32(window);
   1551         }
   1552     }
   1553 
   1554     return GLFW_TRUE;
   1555 }
   1556 
   1557 void _glfwDestroyWindowWin32(_GLFWwindow* window)
   1558 {
   1559     if (window->monitor)
   1560         releaseMonitorWin32(window);
   1561 
   1562     if (window->context.destroy)
   1563         window->context.destroy(window);
   1564 
   1565     if (_glfw.win32.disabledCursorWindow == window)
   1566         enableCursor(window);
   1567 
   1568     if (_glfw.win32.capturedCursorWindow == window)
   1569         releaseCursor();
   1570 
   1571     if (window->win32.handle)
   1572     {
   1573         RemovePropW(window->win32.handle, L"GLFW");
   1574         DestroyWindow(window->win32.handle);
   1575         window->win32.handle = NULL;
   1576     }
   1577 
   1578     if (window->win32.bigIcon)
   1579         DestroyIcon(window->win32.bigIcon);
   1580 
   1581     if (window->win32.smallIcon)
   1582         DestroyIcon(window->win32.smallIcon);
   1583 }
   1584 
   1585 void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)
   1586 {
   1587     WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title);
   1588     if (!wideTitle)
   1589         return;
   1590 
   1591     SetWindowTextW(window->win32.handle, wideTitle);
   1592     _glfw_free(wideTitle);
   1593 }
   1594 
   1595 void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images)
   1596 {
   1597     HICON bigIcon = NULL, smallIcon = NULL;
   1598 
   1599     if (count)
   1600     {
   1601         const GLFWimage* bigImage = chooseImage(count, images,
   1602                                                 GetSystemMetrics(SM_CXICON),
   1603                                                 GetSystemMetrics(SM_CYICON));
   1604         const GLFWimage* smallImage = chooseImage(count, images,
   1605                                                   GetSystemMetrics(SM_CXSMICON),
   1606                                                   GetSystemMetrics(SM_CYSMICON));
   1607 
   1608         bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
   1609         smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
   1610     }
   1611     else
   1612     {
   1613         bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON);
   1614         smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
   1615     }
   1616 
   1617     SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
   1618     SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
   1619 
   1620     if (window->win32.bigIcon)
   1621         DestroyIcon(window->win32.bigIcon);
   1622 
   1623     if (window->win32.smallIcon)
   1624         DestroyIcon(window->win32.smallIcon);
   1625 
   1626     if (count)
   1627     {
   1628         window->win32.bigIcon = bigIcon;
   1629         window->win32.smallIcon = smallIcon;
   1630     }
   1631 }
   1632 
   1633 void _glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos)
   1634 {
   1635     POINT pos = { 0, 0 };
   1636     ClientToScreen(window->win32.handle, &pos);
   1637 
   1638     if (xpos)
   1639         *xpos = pos.x;
   1640     if (ypos)
   1641         *ypos = pos.y;
   1642 }
   1643 
   1644 void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos)
   1645 {
   1646     RECT rect = { xpos, ypos, xpos, ypos };
   1647 
   1648     if (_glfwIsWindows10Version1607OrGreaterWin32())
   1649     {
   1650         AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
   1651                                  FALSE, getWindowExStyle(window),
   1652                                  GetDpiForWindow(window->win32.handle));
   1653     }
   1654     else
   1655     {
   1656         AdjustWindowRectEx(&rect, getWindowStyle(window),
   1657                            FALSE, getWindowExStyle(window));
   1658     }
   1659 
   1660     SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
   1661                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
   1662 }
   1663 
   1664 void _glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height)
   1665 {
   1666     RECT area;
   1667     GetClientRect(window->win32.handle, &area);
   1668 
   1669     if (width)
   1670         *width = area.right;
   1671     if (height)
   1672         *height = area.bottom;
   1673 }
   1674 
   1675 void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
   1676 {
   1677     if (window->monitor)
   1678     {
   1679         if (window->monitor->window == window)
   1680         {
   1681             acquireMonitorWin32(window);
   1682             fitToMonitor(window);
   1683         }
   1684     }
   1685     else
   1686     {
   1687         RECT rect = { 0, 0, width, height };
   1688 
   1689         if (_glfwIsWindows10Version1607OrGreaterWin32())
   1690         {
   1691             AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
   1692                                      FALSE, getWindowExStyle(window),
   1693                                      GetDpiForWindow(window->win32.handle));
   1694         }
   1695         else
   1696         {
   1697             AdjustWindowRectEx(&rect, getWindowStyle(window),
   1698                                FALSE, getWindowExStyle(window));
   1699         }
   1700 
   1701         SetWindowPos(window->win32.handle, HWND_TOP,
   1702                      0, 0, rect.right - rect.left, rect.bottom - rect.top,
   1703                      SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
   1704     }
   1705 }
   1706 
   1707 void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window,
   1708                                    int minwidth, int minheight,
   1709                                    int maxwidth, int maxheight)
   1710 {
   1711     RECT area;
   1712 
   1713     if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
   1714         (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE))
   1715     {
   1716         return;
   1717     }
   1718 
   1719     GetWindowRect(window->win32.handle, &area);
   1720     MoveWindow(window->win32.handle,
   1721                area.left, area.top,
   1722                area.right - area.left,
   1723                area.bottom - area.top, TRUE);
   1724 }
   1725 
   1726 void _glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom)
   1727 {
   1728     RECT area;
   1729 
   1730     if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
   1731         return;
   1732 
   1733     GetWindowRect(window->win32.handle, &area);
   1734     applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area);
   1735     MoveWindow(window->win32.handle,
   1736                area.left, area.top,
   1737                area.right - area.left,
   1738                area.bottom - area.top, TRUE);
   1739 }
   1740 
   1741 void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height)
   1742 {
   1743     _glfwGetWindowSizeWin32(window, width, height);
   1744 }
   1745 
   1746 void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
   1747                                   int* left, int* top,
   1748                                   int* right, int* bottom)
   1749 {
   1750     RECT rect;
   1751     int width, height;
   1752 
   1753     _glfwGetWindowSizeWin32(window, &width, &height);
   1754     SetRect(&rect, 0, 0, width, height);
   1755 
   1756     if (_glfwIsWindows10Version1607OrGreaterWin32())
   1757     {
   1758         AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
   1759                                  FALSE, getWindowExStyle(window),
   1760                                  GetDpiForWindow(window->win32.handle));
   1761     }
   1762     else
   1763     {
   1764         AdjustWindowRectEx(&rect, getWindowStyle(window),
   1765                            FALSE, getWindowExStyle(window));
   1766     }
   1767 
   1768     if (left)
   1769         *left = -rect.left;
   1770     if (top)
   1771         *top = -rect.top;
   1772     if (right)
   1773         *right = rect.right - width;
   1774     if (bottom)
   1775         *bottom = rect.bottom - height;
   1776 }
   1777 
   1778 void _glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale)
   1779 {
   1780     const HANDLE handle = MonitorFromWindow(window->win32.handle,
   1781                                             MONITOR_DEFAULTTONEAREST);
   1782     _glfwGetHMONITORContentScaleWin32(handle, xscale, yscale);
   1783 }
   1784 
   1785 void _glfwIconifyWindowWin32(_GLFWwindow* window)
   1786 {
   1787     ShowWindow(window->win32.handle, SW_MINIMIZE);
   1788 }
   1789 
   1790 void _glfwRestoreWindowWin32(_GLFWwindow* window)
   1791 {
   1792     ShowWindow(window->win32.handle, SW_RESTORE);
   1793 }
   1794 
   1795 void _glfwMaximizeWindowWin32(_GLFWwindow* window)
   1796 {
   1797     if (IsWindowVisible(window->win32.handle))
   1798         ShowWindow(window->win32.handle, SW_MAXIMIZE);
   1799     else
   1800         maximizeWindowManually(window);
   1801 }
   1802 
   1803 void _glfwShowWindowWin32(_GLFWwindow* window)
   1804 {
   1805     int showCommand = SW_SHOWNA;
   1806 
   1807     if (window->win32.showDefault)
   1808     {
   1809         // NOTE: GLFW windows currently do not seem to match the Windows 10 definition of
   1810         //       a main window, so even SW_SHOWDEFAULT does nothing
   1811         //       This definition is undocumented and can change (source: Raymond Chen)
   1812         // HACK: Apply the STARTUPINFO show command manually if available
   1813         STARTUPINFOW si = { sizeof(si) };
   1814         GetStartupInfoW(&si);
   1815         if (si.dwFlags & STARTF_USESHOWWINDOW)
   1816             showCommand = si.wShowWindow;
   1817 
   1818         window->win32.showDefault = GLFW_FALSE;
   1819     }
   1820 
   1821     ShowWindow(window->win32.handle, showCommand);
   1822 }
   1823 
   1824 void _glfwHideWindowWin32(_GLFWwindow* window)
   1825 {
   1826     ShowWindow(window->win32.handle, SW_HIDE);
   1827 }
   1828 
   1829 void _glfwRequestWindowAttentionWin32(_GLFWwindow* window)
   1830 {
   1831     FlashWindow(window->win32.handle, TRUE);
   1832 }
   1833 
   1834 void _glfwFocusWindowWin32(_GLFWwindow* window)
   1835 {
   1836     BringWindowToTop(window->win32.handle);
   1837     SetForegroundWindow(window->win32.handle);
   1838     SetFocus(window->win32.handle);
   1839 }
   1840 
   1841 void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
   1842                                 _GLFWmonitor* monitor,
   1843                                 int xpos, int ypos,
   1844                                 int width, int height,
   1845                                 int refreshRate)
   1846 {
   1847     if (window->monitor == monitor)
   1848     {
   1849         if (monitor)
   1850         {
   1851             if (monitor->window == window)
   1852             {
   1853                 acquireMonitorWin32(window);
   1854                 fitToMonitor(window);
   1855             }
   1856         }
   1857         else
   1858         {
   1859             RECT rect = { xpos, ypos, xpos + width, ypos + height };
   1860 
   1861             if (_glfwIsWindows10Version1607OrGreaterWin32())
   1862             {
   1863                 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
   1864                                          FALSE, getWindowExStyle(window),
   1865                                          GetDpiForWindow(window->win32.handle));
   1866             }
   1867             else
   1868             {
   1869                 AdjustWindowRectEx(&rect, getWindowStyle(window),
   1870                                    FALSE, getWindowExStyle(window));
   1871             }
   1872 
   1873             SetWindowPos(window->win32.handle, HWND_TOP,
   1874                          rect.left, rect.top,
   1875                          rect.right - rect.left, rect.bottom - rect.top,
   1876                          SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
   1877         }
   1878 
   1879         return;
   1880     }
   1881 
   1882     if (window->monitor)
   1883         releaseMonitorWin32(window);
   1884 
   1885     _glfwInputWindowMonitor(window, monitor);
   1886 
   1887     if (window->monitor)
   1888     {
   1889         MONITORINFO mi = { sizeof(mi) };
   1890         UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
   1891 
   1892         if (window->decorated)
   1893         {
   1894             DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
   1895             style &= ~WS_OVERLAPPEDWINDOW;
   1896             style |= getWindowStyle(window);
   1897             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
   1898             flags |= SWP_FRAMECHANGED;
   1899         }
   1900 
   1901         acquireMonitorWin32(window);
   1902 
   1903         GetMonitorInfoW(window->monitor->win32.handle, &mi);
   1904         SetWindowPos(window->win32.handle, HWND_TOPMOST,
   1905                      mi.rcMonitor.left,
   1906                      mi.rcMonitor.top,
   1907                      mi.rcMonitor.right - mi.rcMonitor.left,
   1908                      mi.rcMonitor.bottom - mi.rcMonitor.top,
   1909                      flags);
   1910     }
   1911     else
   1912     {
   1913         HWND after;
   1914         RECT rect = { xpos, ypos, xpos + width, ypos + height };
   1915         DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
   1916         UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
   1917 
   1918         if (window->decorated)
   1919         {
   1920             style &= ~WS_POPUP;
   1921             style |= getWindowStyle(window);
   1922             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
   1923 
   1924             flags |= SWP_FRAMECHANGED;
   1925         }
   1926 
   1927         if (window->floating)
   1928             after = HWND_TOPMOST;
   1929         else
   1930             after = HWND_NOTOPMOST;
   1931 
   1932         if (_glfwIsWindows10Version1607OrGreaterWin32())
   1933         {
   1934             AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
   1935                                      FALSE, getWindowExStyle(window),
   1936                                      GetDpiForWindow(window->win32.handle));
   1937         }
   1938         else
   1939         {
   1940             AdjustWindowRectEx(&rect, getWindowStyle(window),
   1941                                FALSE, getWindowExStyle(window));
   1942         }
   1943 
   1944         SetWindowPos(window->win32.handle, after,
   1945                      rect.left, rect.top,
   1946                      rect.right - rect.left, rect.bottom - rect.top,
   1947                      flags);
   1948     }
   1949 }
   1950 
   1951 GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window)
   1952 {
   1953     return window->win32.handle == GetActiveWindow();
   1954 }
   1955 
   1956 GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window)
   1957 {
   1958     return IsIconic(window->win32.handle);
   1959 }
   1960 
   1961 GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window)
   1962 {
   1963     return IsWindowVisible(window->win32.handle);
   1964 }
   1965 
   1966 GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window)
   1967 {
   1968     return IsZoomed(window->win32.handle);
   1969 }
   1970 
   1971 GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window)
   1972 {
   1973     return cursorInContentArea(window);
   1974 }
   1975 
   1976 GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window)
   1977 {
   1978     BOOL composition, opaque;
   1979     DWORD color;
   1980 
   1981     if (!window->win32.transparent)
   1982         return GLFW_FALSE;
   1983 
   1984     if (!IsWindowsVistaOrGreater())
   1985         return GLFW_FALSE;
   1986 
   1987     if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
   1988         return GLFW_FALSE;
   1989 
   1990     if (!IsWindows8OrGreater())
   1991     {
   1992         // HACK: Disable framebuffer transparency on Windows 7 when the
   1993         //       colorization color is opaque, because otherwise the window
   1994         //       contents is blended additively with the previous frame instead
   1995         //       of replacing it
   1996         if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque)
   1997             return GLFW_FALSE;
   1998     }
   1999 
   2000     return GLFW_TRUE;
   2001 }
   2002 
   2003 void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled)
   2004 {
   2005     updateWindowStyles(window);
   2006 }
   2007 
   2008 void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled)
   2009 {
   2010     updateWindowStyles(window);
   2011 }
   2012 
   2013 void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled)
   2014 {
   2015     const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST;
   2016     SetWindowPos(window->win32.handle, after, 0, 0, 0, 0,
   2017                  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
   2018 }
   2019 
   2020 void _glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled)
   2021 {
   2022     COLORREF key = 0;
   2023     BYTE alpha = 0;
   2024     DWORD flags = 0;
   2025     DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
   2026 
   2027     if (exStyle & WS_EX_LAYERED)
   2028         GetLayeredWindowAttributes(window->win32.handle, &key, &alpha, &flags);
   2029 
   2030     if (enabled)
   2031         exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
   2032     else
   2033     {
   2034         exStyle &= ~WS_EX_TRANSPARENT;
   2035         // NOTE: Window opacity also needs the layered window style so do not
   2036         //       remove it if the window is alpha blended
   2037         if (exStyle & WS_EX_LAYERED)
   2038         {
   2039             if (!(flags & LWA_ALPHA))
   2040                 exStyle &= ~WS_EX_LAYERED;
   2041         }
   2042     }
   2043 
   2044     SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
   2045 
   2046     if (enabled)
   2047         SetLayeredWindowAttributes(window->win32.handle, key, alpha, flags);
   2048 }
   2049 
   2050 float _glfwGetWindowOpacityWin32(_GLFWwindow* window)
   2051 {
   2052     BYTE alpha;
   2053     DWORD flags;
   2054 
   2055     if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) &&
   2056         GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags))
   2057     {
   2058         if (flags & LWA_ALPHA)
   2059             return alpha / 255.f;
   2060     }
   2061 
   2062     return 1.f;
   2063 }
   2064 
   2065 void _glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity)
   2066 {
   2067     LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
   2068     if (opacity < 1.f || (exStyle & WS_EX_TRANSPARENT))
   2069     {
   2070         const BYTE alpha = (BYTE) (255 * opacity);
   2071         exStyle |= WS_EX_LAYERED;
   2072         SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
   2073         SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA);
   2074     }
   2075     else if (exStyle & WS_EX_TRANSPARENT)
   2076     {
   2077         SetLayeredWindowAttributes(window->win32.handle, 0, 0, 0);
   2078     }
   2079     else
   2080     {
   2081         exStyle &= ~WS_EX_LAYERED;
   2082         SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
   2083     }
   2084 }
   2085 
   2086 void _glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled)
   2087 {
   2088     if (_glfw.win32.disabledCursorWindow != window)
   2089         return;
   2090 
   2091     if (enabled)
   2092         enableRawMouseMotion(window);
   2093     else
   2094         disableRawMouseMotion(window);
   2095 }
   2096 
   2097 GLFWbool _glfwRawMouseMotionSupportedWin32(void)
   2098 {
   2099     return GLFW_TRUE;
   2100 }
   2101 
   2102 void _glfwPollEventsWin32(void)
   2103 {
   2104     MSG msg;
   2105     HWND handle;
   2106     _GLFWwindow* window;
   2107 
   2108     while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
   2109     {
   2110         if (msg.message == WM_QUIT)
   2111         {
   2112             // NOTE: While GLFW does not itself post WM_QUIT, other processes
   2113             //       may post it to this one, for example Task Manager
   2114             // HACK: Treat WM_QUIT as a close on all windows
   2115 
   2116             window = _glfw.windowListHead;
   2117             while (window)
   2118             {
   2119                 _glfwInputWindowCloseRequest(window);
   2120                 window = window->next;
   2121             }
   2122         }
   2123         else
   2124         {
   2125             TranslateMessage(&msg);
   2126             DispatchMessageW(&msg);
   2127         }
   2128     }
   2129 
   2130     // HACK: Release modifier keys that the system did not emit KEYUP for
   2131     // NOTE: Shift keys on Windows tend to "stick" when both are pressed as
   2132     //       no key up message is generated by the first key release
   2133     // NOTE: Windows key is not reported as released by the Win+V hotkey
   2134     //       Other Win hotkeys are handled implicitly by _glfwInputWindowFocus
   2135     //       because they change the input focus
   2136     // NOTE: The other half of this is in the WM_*KEY* handler in windowProc
   2137     handle = GetActiveWindow();
   2138     if (handle)
   2139     {
   2140         window = GetPropW(handle, L"GLFW");
   2141         if (window)
   2142         {
   2143             int i;
   2144             const int keys[4][2] =
   2145             {
   2146                 { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT },
   2147                 { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT },
   2148                 { VK_LWIN, GLFW_KEY_LEFT_SUPER },
   2149                 { VK_RWIN, GLFW_KEY_RIGHT_SUPER }
   2150             };
   2151 
   2152             for (i = 0;  i < 4;  i++)
   2153             {
   2154                 const int vk = keys[i][0];
   2155                 const int key = keys[i][1];
   2156                 const int scancode = _glfw.win32.scancodes[key];
   2157 
   2158                 if ((GetKeyState(vk) & 0x8000))
   2159                     continue;
   2160                 if (window->keys[key] != GLFW_PRESS)
   2161                     continue;
   2162 
   2163                 _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods());
   2164             }
   2165         }
   2166     }
   2167 
   2168     window = _glfw.win32.disabledCursorWindow;
   2169     if (window)
   2170     {
   2171         int width, height;
   2172         _glfwGetWindowSizeWin32(window, &width, &height);
   2173 
   2174         // NOTE: Re-center the cursor only if it has moved since the last call,
   2175         //       to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
   2176         // The re-center is required in order to prevent the mouse cursor stopping at the edges of the screen.
   2177         if (window->win32.lastCursorPosX != width / 2 ||
   2178             window->win32.lastCursorPosY != height / 2)
   2179         {
   2180             _glfwSetCursorPosWin32(window, width / 2, height / 2);
   2181         }
   2182     }
   2183 }
   2184 
   2185 void _glfwWaitEventsWin32(void)
   2186 {
   2187     WaitMessage();
   2188 
   2189     _glfwPollEventsWin32();
   2190 }
   2191 
   2192 void _glfwWaitEventsTimeoutWin32(double timeout)
   2193 {
   2194     MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLINPUT);
   2195 
   2196     _glfwPollEventsWin32();
   2197 }
   2198 
   2199 void _glfwPostEmptyEventWin32(void)
   2200 {
   2201     PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
   2202 }
   2203 
   2204 void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos)
   2205 {
   2206     POINT pos;
   2207 
   2208     if (GetCursorPos(&pos))
   2209     {
   2210         ScreenToClient(window->win32.handle, &pos);
   2211 
   2212         if (xpos)
   2213             *xpos = pos.x;
   2214         if (ypos)
   2215             *ypos = pos.y;
   2216     }
   2217 }
   2218 
   2219 void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos)
   2220 {
   2221     POINT pos = { (int) xpos, (int) ypos };
   2222 
   2223     // Store the new position so it can be recognized later
   2224     window->win32.lastCursorPosX = pos.x;
   2225     window->win32.lastCursorPosY = pos.y;
   2226 
   2227     ClientToScreen(window->win32.handle, &pos);
   2228     SetCursorPos(pos.x, pos.y);
   2229 }
   2230 
   2231 void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode)
   2232 {
   2233     if (_glfwWindowFocusedWin32(window))
   2234     {
   2235         if (mode == GLFW_CURSOR_DISABLED)
   2236         {
   2237             _glfwGetCursorPosWin32(window,
   2238                                    &_glfw.win32.restoreCursorPosX,
   2239                                    &_glfw.win32.restoreCursorPosY);
   2240             _glfwCenterCursorInContentArea(window);
   2241             if (window->rawMouseMotion)
   2242                 enableRawMouseMotion(window);
   2243         }
   2244         else if (_glfw.win32.disabledCursorWindow == window)
   2245         {
   2246             if (window->rawMouseMotion)
   2247                 disableRawMouseMotion(window);
   2248         }
   2249 
   2250         if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
   2251             captureCursor(window);
   2252         else
   2253             releaseCursor();
   2254 
   2255         if (mode == GLFW_CURSOR_DISABLED)
   2256             _glfw.win32.disabledCursorWindow = window;
   2257         else if (_glfw.win32.disabledCursorWindow == window)
   2258         {
   2259             _glfw.win32.disabledCursorWindow = NULL;
   2260             _glfwSetCursorPosWin32(window,
   2261                                    _glfw.win32.restoreCursorPosX,
   2262                                    _glfw.win32.restoreCursorPosY);
   2263         }
   2264     }
   2265 
   2266     if (cursorInContentArea(window))
   2267         updateCursorImage(window);
   2268 }
   2269 
   2270 const char* _glfwGetScancodeNameWin32(int scancode)
   2271 {
   2272     if (scancode < 0 || scancode > (KF_EXTENDED | 0xff))
   2273     {
   2274         _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
   2275         return NULL;
   2276     }
   2277 
   2278     const int key = _glfw.win32.keycodes[scancode];
   2279     if (key == GLFW_KEY_UNKNOWN)
   2280         return NULL;
   2281 
   2282     return _glfw.win32.keynames[key];
   2283 }
   2284 
   2285 int _glfwGetKeyScancodeWin32(int key)
   2286 {
   2287     return _glfw.win32.scancodes[key];
   2288 }
   2289 
   2290 GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor,
   2291                                 const GLFWimage* image,
   2292                                 int xhot, int yhot)
   2293 {
   2294     cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
   2295     if (!cursor->win32.handle)
   2296         return GLFW_FALSE;
   2297 
   2298     return GLFW_TRUE;
   2299 }
   2300 
   2301 GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape)
   2302 {
   2303     int id = 0;
   2304 
   2305     switch (shape)
   2306     {
   2307         case GLFW_ARROW_CURSOR:
   2308             id = OCR_NORMAL;
   2309             break;
   2310         case GLFW_IBEAM_CURSOR:
   2311             id = OCR_IBEAM;
   2312             break;
   2313         case GLFW_CROSSHAIR_CURSOR:
   2314             id = OCR_CROSS;
   2315             break;
   2316         case GLFW_POINTING_HAND_CURSOR:
   2317             id = OCR_HAND;
   2318             break;
   2319         case GLFW_RESIZE_EW_CURSOR:
   2320             id = OCR_SIZEWE;
   2321             break;
   2322         case GLFW_RESIZE_NS_CURSOR:
   2323             id = OCR_SIZENS;
   2324             break;
   2325         case GLFW_RESIZE_NWSE_CURSOR:
   2326             id = OCR_SIZENWSE;
   2327             break;
   2328         case GLFW_RESIZE_NESW_CURSOR:
   2329             id = OCR_SIZENESW;
   2330             break;
   2331         case GLFW_RESIZE_ALL_CURSOR:
   2332             id = OCR_SIZEALL;
   2333             break;
   2334         case GLFW_NOT_ALLOWED_CURSOR:
   2335             id = OCR_NO;
   2336             break;
   2337         default:
   2338             _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor");
   2339             return GLFW_FALSE;
   2340     }
   2341 
   2342     cursor->win32.handle = LoadImageW(NULL,
   2343                                       MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0,
   2344                                       LR_DEFAULTSIZE | LR_SHARED);
   2345     if (!cursor->win32.handle)
   2346     {
   2347         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2348                              "Win32: Failed to create standard cursor");
   2349         return GLFW_FALSE;
   2350     }
   2351 
   2352     return GLFW_TRUE;
   2353 }
   2354 
   2355 void _glfwDestroyCursorWin32(_GLFWcursor* cursor)
   2356 {
   2357     if (cursor->win32.handle)
   2358         DestroyIcon((HICON) cursor->win32.handle);
   2359 }
   2360 
   2361 void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor)
   2362 {
   2363     if (cursorInContentArea(window))
   2364         updateCursorImage(window);
   2365 }
   2366 
   2367 void _glfwSetClipboardStringWin32(const char* string)
   2368 {
   2369     int characterCount, tries = 0;
   2370     HANDLE object;
   2371     WCHAR* buffer;
   2372 
   2373     characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
   2374     if (!characterCount)
   2375         return;
   2376 
   2377     object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
   2378     if (!object)
   2379     {
   2380         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2381                              "Win32: Failed to allocate global handle for clipboard");
   2382         return;
   2383     }
   2384 
   2385     buffer = GlobalLock(object);
   2386     if (!buffer)
   2387     {
   2388         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2389                              "Win32: Failed to lock global handle");
   2390         GlobalFree(object);
   2391         return;
   2392     }
   2393 
   2394     MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
   2395     GlobalUnlock(object);
   2396 
   2397     // NOTE: Retry clipboard opening a few times as some other application may have it
   2398     //       open and also the Windows Clipboard History reads it after each update
   2399     while (!OpenClipboard(_glfw.win32.helperWindowHandle))
   2400     {
   2401         Sleep(1);
   2402         tries++;
   2403 
   2404         if (tries == 3)
   2405         {
   2406             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2407                                  "Win32: Failed to open clipboard");
   2408             GlobalFree(object);
   2409             return;
   2410         }
   2411     }
   2412 
   2413     EmptyClipboard();
   2414     SetClipboardData(CF_UNICODETEXT, object);
   2415     CloseClipboard();
   2416 }
   2417 
   2418 const char* _glfwGetClipboardStringWin32(void)
   2419 {
   2420     HANDLE object;
   2421     WCHAR* buffer;
   2422     int tries = 0;
   2423 
   2424     // NOTE: Retry clipboard opening a few times as some other application may have it
   2425     //       open and also the Windows Clipboard History reads it after each update
   2426     while (!OpenClipboard(_glfw.win32.helperWindowHandle))
   2427     {
   2428         Sleep(1);
   2429         tries++;
   2430 
   2431         if (tries == 3)
   2432         {
   2433             _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2434                                  "Win32: Failed to open clipboard");
   2435             return NULL;
   2436         }
   2437     }
   2438 
   2439     object = GetClipboardData(CF_UNICODETEXT);
   2440     if (!object)
   2441     {
   2442         _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE,
   2443                              "Win32: Failed to convert clipboard to string");
   2444         CloseClipboard();
   2445         return NULL;
   2446     }
   2447 
   2448     buffer = GlobalLock(object);
   2449     if (!buffer)
   2450     {
   2451         _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
   2452                              "Win32: Failed to lock global handle");
   2453         CloseClipboard();
   2454         return NULL;
   2455     }
   2456 
   2457     _glfw_free(_glfw.win32.clipboardString);
   2458     _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer);
   2459 
   2460     GlobalUnlock(object);
   2461     CloseClipboard();
   2462 
   2463     return _glfw.win32.clipboardString;
   2464 }
   2465 
   2466 EGLenum _glfwGetEGLPlatformWin32(EGLint** attribs)
   2467 {
   2468     if (_glfw.egl.ANGLE_platform_angle)
   2469     {
   2470         int type = 0;
   2471 
   2472         if (_glfw.egl.ANGLE_platform_angle_opengl)
   2473         {
   2474             if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
   2475                 type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
   2476             else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES)
   2477                 type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
   2478         }
   2479 
   2480         if (_glfw.egl.ANGLE_platform_angle_d3d)
   2481         {
   2482             if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D9)
   2483                 type = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
   2484             else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D11)
   2485                 type = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
   2486         }
   2487 
   2488         if (_glfw.egl.ANGLE_platform_angle_vulkan)
   2489         {
   2490             if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN)
   2491                 type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
   2492         }
   2493 
   2494         if (type)
   2495         {
   2496             *attribs = _glfw_calloc(3, sizeof(EGLint));
   2497             (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
   2498             (*attribs)[1] = type;
   2499             (*attribs)[2] = EGL_NONE;
   2500             return EGL_PLATFORM_ANGLE_ANGLE;
   2501         }
   2502     }
   2503 
   2504     return 0;
   2505 }
   2506 
   2507 EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void)
   2508 {
   2509     return GetDC(_glfw.win32.helperWindowHandle);
   2510 }
   2511 
   2512 EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window)
   2513 {
   2514     return window->win32.handle;
   2515 }
   2516 
   2517 void _glfwGetRequiredInstanceExtensionsWin32(char** extensions)
   2518 {
   2519     if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface)
   2520         return;
   2521 
   2522     extensions[0] = "VK_KHR_surface";
   2523     extensions[1] = "VK_KHR_win32_surface";
   2524 }
   2525 
   2526 GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance,
   2527                                                         VkPhysicalDevice device,
   2528                                                         uint32_t queuefamily)
   2529 {
   2530     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR
   2531         vkGetPhysicalDeviceWin32PresentationSupportKHR =
   2532         (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
   2533         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
   2534     if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
   2535     {
   2536         _glfwInputError(GLFW_API_UNAVAILABLE,
   2537                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
   2538         return GLFW_FALSE;
   2539     }
   2540 
   2541     return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
   2542 }
   2543 
   2544 VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
   2545                                        _GLFWwindow* window,
   2546                                        const VkAllocationCallbacks* allocator,
   2547                                        VkSurfaceKHR* surface)
   2548 {
   2549     VkResult err;
   2550     VkWin32SurfaceCreateInfoKHR sci;
   2551     PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
   2552 
   2553     vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
   2554         vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
   2555     if (!vkCreateWin32SurfaceKHR)
   2556     {
   2557         _glfwInputError(GLFW_API_UNAVAILABLE,
   2558                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
   2559         return VK_ERROR_EXTENSION_NOT_PRESENT;
   2560     }
   2561 
   2562     memset(&sci, 0, sizeof(sci));
   2563     sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
   2564     sci.hinstance = _glfw.win32.instance;
   2565     sci.hwnd = window->win32.handle;
   2566 
   2567     err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
   2568     if (err)
   2569     {
   2570         _glfwInputError(GLFW_PLATFORM_ERROR,
   2571                         "Win32: Failed to create Vulkan surface: %s",
   2572                         _glfwGetVulkanResultString(err));
   2573     }
   2574 
   2575     return err;
   2576 }
   2577 
   2578 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
   2579 {
   2580     _GLFWwindow* window = (_GLFWwindow*) handle;
   2581     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
   2582 
   2583     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
   2584     {
   2585         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
   2586                         "Win32: Platform not initialized");
   2587         return NULL;
   2588     }
   2589 
   2590     return window->win32.handle;
   2591 }
   2592 
   2593 #endif // _GLFW_WIN32
   2594