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