1 //========================================================================
2 // GLFW 3.5 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
6 //
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
10 //
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
14 //
15 // 1. The origin of this software must not be misrepresented; you must not
16 //    claim that you wrote the original software. If you use this software
17 //    in a product, an acknowledgment in the product documentation would
18 //    be appreciated but is not required.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 //    be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 //    distribution.
25 //
26 //========================================================================
27 
28 #include "internal.h"
29 
30 #if defined(_GLFW_WIN32)
31 
32 #include <limits.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <windowsx.h>
37 #include <shellapi.h>
38 
39 // Returns the window style for the specified window
40 //
getWindowStyle(const _GLFWwindow* window)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 //
getWindowExStyle(const _GLFWwindow* window)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 //
chooseImage(int count, const GLFWimage* images, int width, int height)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 //
createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon)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 //
applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)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 //
updateCursorImage(_GLFWwindow* window)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 //
captureCursor(_GLFWwindow* window)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 //
releaseCursor(void)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 //
enableRawMouseMotion(_GLFWwindow* window)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 //
disableRawMouseMotion(_GLFWwindow* window)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 //
disableCursor(_GLFWwindow* window)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 //
enableCursor(_GLFWwindow* window)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 //
cursorInContentArea(_GLFWwindow* window)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 //
updateWindowStyles(const _GLFWwindow* window)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 //
updateFramebufferTransparency(const _GLFWwindow* window)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 //
getKeyMods(void)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 
fitToMonitor(_GLFWwindow* window)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 //
acquireMonitor(_GLFWwindow* window)443 static void acquireMonitor(_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 //
releaseMonitor(_GLFWwindow* window)464 static void releaseMonitor(_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 acquireMonitor
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 //
maximizeWindowManually(_GLFWwindow* window)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 //
windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)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                     releaseMonitor(window);
1055                 else
1056                 {
1057                     acquireMonitor(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 //
createNativeWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig)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 
_glfwCreateWindowWin32(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig)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         acquireMonitor(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 
_glfwDestroyWindowWin32(_GLFWwindow* window)1557 void _glfwDestroyWindowWin32(_GLFWwindow* window)
1558 {
1559     if (window->monitor)
1560         releaseMonitor(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 
_glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)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 
_glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images)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 
_glfwGetWindowPosWin32(_GLFWwindow* window, int* xpos, int* ypos)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 
_glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos)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 
_glfwGetWindowSizeWin32(_GLFWwindow* window, int* width, int* height)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 
_glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)1675 void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
1676 {
1677     if (window->monitor)
1678     {
1679         if (window->monitor->window == window)
1680         {
1681             acquireMonitor(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 
_glfwSetWindowSizeLimitsWin32(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight)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 
_glfwSetWindowAspectRatioWin32(_GLFWwindow* window, int numer, int denom)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 
_glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height)1741 void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height)
1742 {
1743     _glfwGetWindowSizeWin32(window, width, height);
1744 }
1745 
_glfwGetWindowFrameSizeWin32(_GLFWwindow* window, int* left, int* top, int* right, int* bottom)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 
_glfwGetWindowContentScaleWin32(_GLFWwindow* window, float* xscale, float* yscale)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 
_glfwIconifyWindowWin32(_GLFWwindow* window)1785 void _glfwIconifyWindowWin32(_GLFWwindow* window)
1786 {
1787     ShowWindow(window->win32.handle, SW_MINIMIZE);
1788 }
1789 
_glfwRestoreWindowWin32(_GLFWwindow* window)1790 void _glfwRestoreWindowWin32(_GLFWwindow* window)
1791 {
1792     ShowWindow(window->win32.handle, SW_RESTORE);
1793 }
1794 
_glfwMaximizeWindowWin32(_GLFWwindow* window)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 
_glfwShowWindowWin32(_GLFWwindow* window)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 
_glfwHideWindowWin32(_GLFWwindow* window)1824 void _glfwHideWindowWin32(_GLFWwindow* window)
1825 {
1826     ShowWindow(window->win32.handle, SW_HIDE);
1827 }
1828 
_glfwRequestWindowAttentionWin32(_GLFWwindow* window)1829 void _glfwRequestWindowAttentionWin32(_GLFWwindow* window)
1830 {
1831     FlashWindow(window->win32.handle, TRUE);
1832 }
1833 
_glfwFocusWindowWin32(_GLFWwindow* window)1834 void _glfwFocusWindowWin32(_GLFWwindow* window)
1835 {
1836     BringWindowToTop(window->win32.handle);
1837     SetForegroundWindow(window->win32.handle);
1838     SetFocus(window->win32.handle);
1839 }
1840 
_glfwSetWindowMonitorWin32(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate)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                 acquireMonitor(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         releaseMonitor(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         acquireMonitor(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 
_glfwWindowFocusedWin32(_GLFWwindow* window)1951 GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window)
1952 {
1953     return window->win32.handle == GetActiveWindow();
1954 }
1955 
_glfwWindowIconifiedWin32(_GLFWwindow* window)1956 GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window)
1957 {
1958     return IsIconic(window->win32.handle);
1959 }
1960 
_glfwWindowVisibleWin32(_GLFWwindow* window)1961 GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window)
1962 {
1963     return IsWindowVisible(window->win32.handle);
1964 }
1965 
_glfwWindowMaximizedWin32(_GLFWwindow* window)1966 GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window)
1967 {
1968     return IsZoomed(window->win32.handle);
1969 }
1970 
_glfwWindowHoveredWin32(_GLFWwindow* window)1971 GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window)
1972 {
1973     return cursorInContentArea(window);
1974 }
1975 
_glfwFramebufferTransparentWin32(_GLFWwindow* window)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 
_glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled)2003 void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled)
2004 {
2005     updateWindowStyles(window);
2006 }
2007 
_glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled)2008 void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled)
2009 {
2010     updateWindowStyles(window);
2011 }
2012 
_glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled)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 
_glfwSetWindowMousePassthroughWin32(_GLFWwindow* window, GLFWbool enabled)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 
_glfwGetWindowOpacityWin32(_GLFWwindow* window)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 
_glfwSetWindowOpacityWin32(_GLFWwindow* window, float opacity)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 
_glfwSetRawMouseMotionWin32(_GLFWwindow *window, GLFWbool enabled)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 
_glfwRawMouseMotionSupportedWin32(void)2097 GLFWbool _glfwRawMouseMotionSupportedWin32(void)
2098 {
2099     return GLFW_TRUE;
2100 }
2101 
_glfwPollEventsWin32(void)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 
_glfwWaitEventsWin32(void)2185 void _glfwWaitEventsWin32(void)
2186 {
2187     WaitMessage();
2188 
2189     _glfwPollEventsWin32();
2190 }
2191 
_glfwWaitEventsTimeoutWin32(double timeout)2192 void _glfwWaitEventsTimeoutWin32(double timeout)
2193 {
2194     MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLINPUT);
2195 
2196     _glfwPollEventsWin32();
2197 }
2198 
_glfwPostEmptyEventWin32(void)2199 void _glfwPostEmptyEventWin32(void)
2200 {
2201     PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
2202 }
2203 
_glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos)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 
_glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos)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 
_glfwSetCursorModeWin32(_GLFWwindow* window, int mode)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 
_glfwGetScancodeNameWin32(int scancode)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 
_glfwGetKeyScancodeWin32(int key)2285 int _glfwGetKeyScancodeWin32(int key)
2286 {
2287     return _glfw.win32.scancodes[key];
2288 }
2289 
_glfwCreateCursorWin32(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot)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 
_glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape)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 
_glfwDestroyCursorWin32(_GLFWcursor* cursor)2355 void _glfwDestroyCursorWin32(_GLFWcursor* cursor)
2356 {
2357     if (cursor->win32.handle)
2358         DestroyIcon((HICON) cursor->win32.handle);
2359 }
2360 
_glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor)2361 void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor)
2362 {
2363     if (cursorInContentArea(window))
2364         updateCursorImage(window);
2365 }
2366 
_glfwSetClipboardStringWin32(const char* string)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 
_glfwGetClipboardStringWin32(void)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 
_glfwGetEGLPlatformWin32(EGLint** attribs)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 
_glfwGetEGLNativeDisplayWin32(void)2507 EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void)
2508 {
2509     return GetDC(_glfw.win32.helperWindowHandle);
2510 }
2511 
_glfwGetEGLNativeWindowWin32(_GLFWwindow* window)2512 EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window)
2513 {
2514     return window->win32.handle;
2515 }
2516 
_glfwGetRequiredInstanceExtensionsWin32(char** extensions)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 
_glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily)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 
_glfwCreateWindowSurfaceWin32(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface)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 
glfwGetWin32Window(GLFWwindow* handle)2578 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
2579 {
2580     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
2581 
2582     if (_glfw.platform.platformID != GLFW_PLATFORM_WIN32)
2583     {
2584         _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
2585                         "Win32: Platform not initialized");
2586         return NULL;
2587     }
2588 
2589     _GLFWwindow* window = (_GLFWwindow*) handle;
2590     assert(window != NULL);
2591 
2592     return window->win32.handle;
2593 }
2594 
2595 #endif // _GLFW_WIN32
2596 
2597