• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //========================================================================
2 // GLFW 3.2 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2016 Camilla Berglund <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 #include <limits.h>
31 #include <stdlib.h>
32 #include <malloc.h>
33 #include <string.h>
34 #include <windowsx.h>
35 #include <shellapi.h>
36 
37 #define _GLFW_KEY_INVALID -2
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         if (window->decorated)
50         {
51             style |= WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;
52 
53             if (window->resizable)
54                 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
55         }
56         else
57             style |= WS_POPUP;
58     }
59 
60     return style;
61 }
62 
63 // Returns the extended window style for the specified window
64 //
getWindowExStyle(const _GLFWwindow * window)65 static DWORD getWindowExStyle(const _GLFWwindow* window)
66 {
67     DWORD style = WS_EX_APPWINDOW;
68 
69     if (window->monitor || window->floating)
70         style |= WS_EX_TOPMOST;
71 
72     return style;
73 }
74 
75 // Returns the image whose area most closely matches the desired one
76 //
chooseImage(int count,const GLFWimage * images,int width,int height)77 static const GLFWimage* chooseImage(int count, const GLFWimage* images,
78                                     int width, int height)
79 {
80     int i, leastDiff = INT_MAX;
81     const GLFWimage* closest = NULL;
82 
83     for (i = 0;  i < count;  i++)
84     {
85         const int currDiff = abs(images[i].width * images[i].height -
86                                  width * height);
87         if (currDiff < leastDiff)
88         {
89             closest = images + i;
90             leastDiff = currDiff;
91         }
92     }
93 
94     return closest;
95 }
96 
97 // Creates an RGBA icon or cursor
98 //
createIcon(const GLFWimage * image,int xhot,int yhot,GLFWbool icon)99 static HICON createIcon(const GLFWimage* image,
100                         int xhot, int yhot, GLFWbool icon)
101 {
102     int i;
103     HDC dc;
104     HICON handle;
105     HBITMAP color, mask;
106     BITMAPV5HEADER bi;
107     ICONINFO ii;
108     unsigned char* target = NULL;
109     unsigned char* source = image->pixels;
110 
111     ZeroMemory(&bi, sizeof(bi));
112     bi.bV5Size        = sizeof(BITMAPV5HEADER);
113     bi.bV5Width       = image->width;
114     bi.bV5Height      = -image->height;
115     bi.bV5Planes      = 1;
116     bi.bV5BitCount    = 32;
117     bi.bV5Compression = BI_BITFIELDS;
118     bi.bV5RedMask     = 0x00ff0000;
119     bi.bV5GreenMask   = 0x0000ff00;
120     bi.bV5BlueMask    = 0x000000ff;
121     bi.bV5AlphaMask   = 0xff000000;
122 
123     dc = GetDC(NULL);
124     color = CreateDIBSection(dc,
125                              (BITMAPINFO*) &bi,
126                              DIB_RGB_COLORS,
127                              (void**) &target,
128                              NULL,
129                              (DWORD) 0);
130     ReleaseDC(NULL, dc);
131 
132     if (!color)
133     {
134         _glfwInputError(GLFW_PLATFORM_ERROR,
135                         "Win32: Failed to create RGBA bitmap");
136         return NULL;
137     }
138 
139     mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
140     if (!mask)
141     {
142         _glfwInputError(GLFW_PLATFORM_ERROR,
143                         "Win32: Failed to create mask bitmap");
144         DeleteObject(color);
145         return NULL;
146     }
147 
148     for (i = 0;  i < image->width * image->height;  i++)
149     {
150         target[0] = source[2];
151         target[1] = source[1];
152         target[2] = source[0];
153         target[3] = source[3];
154         target += 4;
155         source += 4;
156     }
157 
158     ZeroMemory(&ii, sizeof(ii));
159     ii.fIcon    = icon;
160     ii.xHotspot = xhot;
161     ii.yHotspot = yhot;
162     ii.hbmMask  = mask;
163     ii.hbmColor = color;
164 
165     handle = CreateIconIndirect(&ii);
166 
167     DeleteObject(color);
168     DeleteObject(mask);
169 
170     if (!handle)
171     {
172         if (icon)
173             _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create icon");
174         else
175             _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create cursor");
176     }
177 
178     return handle;
179 }
180 
181 // Translate client window size to full window size according to styles
182 //
getFullWindowSize(DWORD style,DWORD exStyle,int clientWidth,int clientHeight,int * fullWidth,int * fullHeight)183 static void getFullWindowSize(DWORD style, DWORD exStyle,
184                               int clientWidth, int clientHeight,
185                               int* fullWidth, int* fullHeight)
186 {
187     RECT rect = { 0, 0, clientWidth, clientHeight };
188     AdjustWindowRectEx(&rect, style, FALSE, exStyle);
189     *fullWidth = rect.right - rect.left;
190     *fullHeight = rect.bottom - rect.top;
191 }
192 
193 // Enforce the client rect aspect ratio based on which edge is being dragged
194 //
applyAspectRatio(_GLFWwindow * window,int edge,RECT * area)195 static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
196 {
197     int xoff, yoff;
198     const float ratio = (float) window->numer / (float) window->denom;
199 
200     getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
201                       0, 0, &xoff, &yoff);
202 
203     if (edge == WMSZ_LEFT  || edge == WMSZ_BOTTOMLEFT ||
204         edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
205     {
206         area->bottom = area->top + yoff +
207             (int) ((area->right - area->left - xoff) / ratio);
208     }
209     else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
210     {
211         area->top = area->bottom - yoff -
212             (int) ((area->right - area->left - xoff) / ratio);
213     }
214     else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
215     {
216         area->right = area->left + xoff +
217             (int) ((area->bottom - area->top - yoff) * ratio);
218     }
219 }
220 
221 // Centers the cursor over the window client area
222 //
centerCursor(_GLFWwindow * window)223 static void centerCursor(_GLFWwindow* window)
224 {
225     int width, height;
226     _glfwPlatformGetWindowSize(window, &width, &height);
227     _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
228 }
229 
230 // Returns whether the cursor is in the client area of the specified window
231 //
cursorInClientArea(_GLFWwindow * window)232 static GLFWbool cursorInClientArea(_GLFWwindow* window)
233 {
234     RECT area;
235     POINT pos;
236 
237     if (!GetCursorPos(&pos))
238         return GLFW_FALSE;
239 
240     if (WindowFromPoint(pos) != window->win32.handle)
241         return GLFW_FALSE;
242 
243     GetClientRect(window->win32.handle, &area);
244     ClientToScreen(window->win32.handle, (POINT*) &area.left);
245     ClientToScreen(window->win32.handle, (POINT*) &area.right);
246 
247     return PtInRect(&area, pos);
248 }
249 
250 // Updates the cursor image according to its cursor mode
251 //
updateCursorImage(_GLFWwindow * window)252 static void updateCursorImage(_GLFWwindow* window)
253 {
254     if (window->cursorMode == GLFW_CURSOR_NORMAL)
255     {
256         if (window->cursor)
257             SetCursor(window->cursor->win32.handle);
258         else
259             SetCursor(LoadCursorW(NULL, IDC_ARROW));
260     }
261     else
262         SetCursor(NULL);
263 }
264 
265 // Updates the cursor clip rect
266 //
updateClipRect(_GLFWwindow * window)267 static void updateClipRect(_GLFWwindow* window)
268 {
269     if (window)
270     {
271         RECT clipRect;
272         GetClientRect(window->win32.handle, &clipRect);
273         ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
274         ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
275         ClipCursor(&clipRect);
276     }
277     else
278         ClipCursor(NULL);
279 }
280 
281 // Translates a GLFW standard cursor to a resource ID
282 //
translateCursorShape(int shape)283 static LPWSTR translateCursorShape(int shape)
284 {
285     switch (shape)
286     {
287         case GLFW_ARROW_CURSOR:
288             return IDC_ARROW;
289         case GLFW_IBEAM_CURSOR:
290             return IDC_IBEAM;
291         case GLFW_CROSSHAIR_CURSOR:
292             return IDC_CROSS;
293         case GLFW_HAND_CURSOR:
294             return IDC_HAND;
295         case GLFW_HRESIZE_CURSOR:
296             return IDC_SIZEWE;
297         case GLFW_VRESIZE_CURSOR:
298             return IDC_SIZENS;
299     }
300 
301     return NULL;
302 }
303 
304 // Retrieves and translates modifier keys
305 //
getKeyMods(void)306 static int getKeyMods(void)
307 {
308     int mods = 0;
309 
310     if (GetKeyState(VK_SHIFT) & (1 << 31))
311         mods |= GLFW_MOD_SHIFT;
312     if (GetKeyState(VK_CONTROL) & (1 << 31))
313         mods |= GLFW_MOD_CONTROL;
314     if (GetKeyState(VK_MENU) & (1 << 31))
315         mods |= GLFW_MOD_ALT;
316     if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31))
317         mods |= GLFW_MOD_SUPER;
318 
319     return mods;
320 }
321 
322 // Retrieves and translates modifier keys
323 //
getAsyncKeyMods(void)324 static int getAsyncKeyMods(void)
325 {
326     int mods = 0;
327 
328     if (GetAsyncKeyState(VK_SHIFT) & (1 << 31))
329         mods |= GLFW_MOD_SHIFT;
330     if (GetAsyncKeyState(VK_CONTROL) & (1 << 31))
331         mods |= GLFW_MOD_CONTROL;
332     if (GetAsyncKeyState(VK_MENU) & (1 << 31))
333         mods |= GLFW_MOD_ALT;
334     if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31))
335         mods |= GLFW_MOD_SUPER;
336 
337     return mods;
338 }
339 
340 // Translates a Windows key to the corresponding GLFW key
341 //
translateKey(WPARAM wParam,LPARAM lParam)342 static int translateKey(WPARAM wParam, LPARAM lParam)
343 {
344     if (wParam == VK_CONTROL)
345     {
346         // The CTRL keys require special handling
347 
348         MSG next;
349         DWORD time;
350 
351         // Is this an extended key (i.e. right key)?
352         if (lParam & 0x01000000)
353             return GLFW_KEY_RIGHT_CONTROL;
354 
355         // Here is a trick: "Alt Gr" sends LCTRL, then RALT. We only
356         // want the RALT message, so we try to see if the next message
357         // is a RALT message. In that case, this is a false LCTRL!
358         time = GetMessageTime();
359 
360         if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
361         {
362             if (next.message == WM_KEYDOWN ||
363                 next.message == WM_SYSKEYDOWN ||
364                 next.message == WM_KEYUP ||
365                 next.message == WM_SYSKEYUP)
366             {
367                 if (next.wParam == VK_MENU &&
368                     (next.lParam & 0x01000000) &&
369                     next.time == time)
370                 {
371                     // Next message is a RALT down message, which
372                     // means that this is not a proper LCTRL message
373                     return _GLFW_KEY_INVALID;
374                 }
375             }
376         }
377 
378         return GLFW_KEY_LEFT_CONTROL;
379     }
380 
381     if (wParam == VK_PROCESSKEY)
382     {
383         // IME notifies that keys have been filtered by setting the virtual
384         // key-code to VK_PROCESSKEY
385         return _GLFW_KEY_INVALID;
386     }
387 
388     return _glfw.win32.publicKeys[HIWORD(lParam) & 0x1FF];
389 }
390 
391 // Make the specified window and its video mode active on its monitor
392 //
acquireMonitor(_GLFWwindow * window)393 static GLFWbool acquireMonitor(_GLFWwindow* window)
394 {
395     GLFWvidmode mode;
396     GLFWbool status;
397     int xpos, ypos;
398 
399     status = _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
400 
401     _glfwPlatformGetVideoMode(window->monitor, &mode);
402     _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
403 
404     SetWindowPos(window->win32.handle, HWND_TOPMOST,
405                  xpos, ypos, mode.width, mode.height,
406                  SWP_NOACTIVATE | SWP_NOCOPYBITS);
407 
408     _glfwInputMonitorWindowChange(window->monitor, window);
409     return status;
410 }
411 
412 // Remove the window and restore the original video mode
413 //
releaseMonitor(_GLFWwindow * window)414 static void releaseMonitor(_GLFWwindow* window)
415 {
416     if (window->monitor->window != window)
417         return;
418 
419     _glfwInputMonitorWindowChange(window->monitor, NULL);
420     _glfwRestoreVideoModeWin32(window->monitor);
421 }
422 
423 // Window callback function (handles window messages)
424 //
windowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)425 static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
426                                    WPARAM wParam, LPARAM lParam)
427 {
428     _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
429     if (!window)
430     {
431         // This is the message handling for the hidden helper window
432 
433         switch (uMsg)
434         {
435             case WM_DEVICECHANGE:
436             {
437                 if (wParam == DBT_DEVNODES_CHANGED)
438                 {
439                     _glfwInputMonitorChange();
440                     return TRUE;
441                 }
442                 else if (wParam == DBT_DEVICEARRIVAL)
443                 {
444                     DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
445                     if (dbh)
446                     {
447                         if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
448                             _glfwDetectJoystickConnectionWin32();
449                     }
450                 }
451                 else if (wParam == DBT_DEVICEREMOVECOMPLETE)
452                 {
453                     DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
454                     if (dbh)
455                     {
456                         if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
457                             _glfwDetectJoystickDisconnectionWin32();
458                     }
459                 }
460 
461                 break;
462             }
463         }
464 
465         return DefWindowProcW(hWnd, uMsg, wParam, lParam);
466     }
467 
468     switch (uMsg)
469     {
470         case WM_SETFOCUS:
471         {
472             _glfwInputWindowFocus(window, GLFW_TRUE);
473 
474             if (window->cursorMode == GLFW_CURSOR_DISABLED)
475                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
476 
477             return 0;
478         }
479 
480         case WM_KILLFOCUS:
481         {
482             if (window->cursorMode == GLFW_CURSOR_DISABLED)
483                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
484 
485             if (window->monitor && window->autoIconify)
486                 _glfwPlatformIconifyWindow(window);
487 
488             _glfwInputWindowFocus(window, GLFW_FALSE);
489             return 0;
490         }
491 
492         case WM_SYSCOMMAND:
493         {
494             switch (wParam & 0xfff0)
495             {
496                 case SC_SCREENSAVE:
497                 case SC_MONITORPOWER:
498                 {
499                     if (window->monitor)
500                     {
501                         // We are running in full screen mode, so disallow
502                         // screen saver and screen blanking
503                         return 0;
504                     }
505                     else
506                         break;
507                 }
508 
509                 // User trying to access application menu using ALT?
510                 case SC_KEYMENU:
511                     return 0;
512             }
513             break;
514         }
515 
516         case WM_CLOSE:
517         {
518             _glfwInputWindowCloseRequest(window);
519             return 0;
520         }
521 
522         case WM_CHAR:
523         case WM_SYSCHAR:
524         case WM_UNICHAR:
525         {
526             const GLFWbool plain = (uMsg != WM_SYSCHAR);
527 
528             if (uMsg == WM_UNICHAR && wParam == UNICODE_NOCHAR)
529             {
530                 // WM_UNICHAR is not sent by Windows, but is sent by some
531                 // third-party input method engine
532                 // Returning TRUE here announces support for this message
533                 return TRUE;
534             }
535 
536             _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), plain);
537             return 0;
538         }
539 
540         case WM_KEYDOWN:
541         case WM_SYSKEYDOWN:
542         case WM_KEYUP:
543         case WM_SYSKEYUP:
544         {
545             const int key = translateKey(wParam, lParam);
546             const int scancode = (lParam >> 16) & 0x1ff;
547             const int action = ((lParam >> 31) & 1) ? GLFW_RELEASE : GLFW_PRESS;
548             const int mods = getKeyMods();
549 
550             if (key == _GLFW_KEY_INVALID)
551                 break;
552 
553             if (action == GLFW_RELEASE && wParam == VK_SHIFT)
554             {
555                 // Release both Shift keys on Shift up event, as only one event
556                 // is sent even if both keys are released
557                 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods);
558                 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods);
559             }
560             else if (wParam == VK_SNAPSHOT)
561             {
562                 // Key down is not reported for the Print Screen key
563                 _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
564                 _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
565             }
566             else
567                 _glfwInputKey(window, key, scancode, action, mods);
568 
569             break;
570         }
571 
572         case WM_LBUTTONDOWN:
573         case WM_RBUTTONDOWN:
574         case WM_MBUTTONDOWN:
575         case WM_XBUTTONDOWN:
576         case WM_LBUTTONUP:
577         case WM_RBUTTONUP:
578         case WM_MBUTTONUP:
579         case WM_XBUTTONUP:
580         {
581             int button, action;
582 
583             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
584                 button = GLFW_MOUSE_BUTTON_LEFT;
585             else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP)
586                 button = GLFW_MOUSE_BUTTON_RIGHT;
587             else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
588                 button = GLFW_MOUSE_BUTTON_MIDDLE;
589             else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
590                 button = GLFW_MOUSE_BUTTON_4;
591             else
592                 button = GLFW_MOUSE_BUTTON_5;
593 
594             if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN ||
595                 uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN)
596             {
597                 action = GLFW_PRESS;
598                 SetCapture(hWnd);
599             }
600             else
601             {
602                 action = GLFW_RELEASE;
603                 ReleaseCapture();
604             }
605 
606             _glfwInputMouseClick(window, button, action, getKeyMods());
607 
608             if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
609                 return TRUE;
610 
611             return 0;
612         }
613 
614         case WM_MOUSEMOVE:
615         {
616             const int x = GET_X_LPARAM(lParam);
617             const int y = GET_Y_LPARAM(lParam);
618 
619             if (window->cursorMode == GLFW_CURSOR_DISABLED)
620             {
621                 const int dx = x - window->win32.lastCursorPosX;
622                 const int dy = y - window->win32.lastCursorPosY;
623 
624                 if (_glfw.win32.disabledCursorWindow != window)
625                     break;
626 
627                 _glfwInputCursorPos(window,
628                                     window->virtualCursorPosX + dx,
629                                     window->virtualCursorPosY + dy);
630             }
631             else
632                 _glfwInputCursorPos(window, x, y);
633 
634             window->win32.lastCursorPosX = x;
635             window->win32.lastCursorPosY = y;
636 
637             if (!window->win32.cursorTracked)
638             {
639                 TRACKMOUSEEVENT tme;
640                 ZeroMemory(&tme, sizeof(tme));
641                 tme.cbSize = sizeof(tme);
642                 tme.dwFlags = TME_LEAVE;
643                 tme.hwndTrack = window->win32.handle;
644                 TrackMouseEvent(&tme);
645 
646                 window->win32.cursorTracked = GLFW_TRUE;
647                 _glfwInputCursorEnter(window, GLFW_TRUE);
648             }
649 
650             return 0;
651         }
652 
653         case WM_MOUSELEAVE:
654         {
655             window->win32.cursorTracked = GLFW_FALSE;
656             _glfwInputCursorEnter(window, GLFW_FALSE);
657             return 0;
658         }
659 
660         case WM_MOUSEWHEEL:
661         {
662             _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
663             return 0;
664         }
665 
666         case WM_MOUSEHWHEEL:
667         {
668             // This message is only sent on Windows Vista and later
669             // NOTE: The X-axis is inverted for consistency with OS X and X11.
670             _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
671             return 0;
672         }
673 
674         case WM_ENTERSIZEMOVE:
675         case WM_ENTERMENULOOP:
676         {
677             if (window->cursorMode == GLFW_CURSOR_DISABLED)
678                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_NORMAL);
679 
680             break;
681         }
682 
683         case WM_EXITSIZEMOVE:
684         case WM_EXITMENULOOP:
685         {
686             if (window->cursorMode == GLFW_CURSOR_DISABLED)
687                 _glfwPlatformSetCursorMode(window, GLFW_CURSOR_DISABLED);
688 
689             break;
690         }
691 
692         case WM_SIZE:
693         {
694             const GLFWbool iconified =
695                 !window->win32.iconified && wParam == SIZE_MINIMIZED;
696             const GLFWbool restored =
697                 window->win32.iconified &&
698                 (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED);
699 
700             if (_glfw.win32.disabledCursorWindow == window)
701                 updateClipRect(window);
702 
703             if (iconified)
704                 _glfwInputWindowIconify(window, GLFW_TRUE);
705             else if (restored)
706                 _glfwInputWindowIconify(window, GLFW_FALSE);
707 
708             _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));
709             _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));
710 
711             if (iconified)
712             {
713                 window->win32.iconified = GLFW_TRUE;
714                 if (window->monitor)
715                     releaseMonitor(window);
716             }
717             else if (restored)
718             {
719                 window->win32.iconified = GLFW_FALSE;
720                 if (window->monitor)
721                     acquireMonitor(window);
722             }
723 
724             return 0;
725         }
726 
727         case WM_MOVE:
728         {
729             if (_glfw.win32.disabledCursorWindow == window)
730                 updateClipRect(window);
731 
732             // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
733             // those macros do not handle negative window positions correctly
734             _glfwInputWindowPos(window,
735                                 GET_X_LPARAM(lParam),
736                                 GET_Y_LPARAM(lParam));
737             return 0;
738         }
739 
740         case WM_SIZING:
741         {
742             if (window->numer == GLFW_DONT_CARE ||
743                 window->denom == GLFW_DONT_CARE)
744             {
745                 break;
746             }
747 
748             applyAspectRatio(window, (int) wParam, (RECT*) lParam);
749             return TRUE;
750         }
751 
752         case WM_GETMINMAXINFO:
753         {
754             int xoff, yoff;
755             MINMAXINFO* mmi = (MINMAXINFO*) lParam;
756 
757             if (window->monitor)
758                 break;
759 
760             getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
761                               0, 0, &xoff, &yoff);
762 
763             if (window->minwidth != GLFW_DONT_CARE &&
764                 window->minheight != GLFW_DONT_CARE)
765             {
766                 mmi->ptMinTrackSize.x = window->minwidth + xoff;
767                 mmi->ptMinTrackSize.y = window->minheight + yoff;
768             }
769 
770             if (window->maxwidth != GLFW_DONT_CARE &&
771                 window->maxheight != GLFW_DONT_CARE)
772             {
773                 mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
774                 mmi->ptMaxTrackSize.y = window->maxheight + yoff;
775             }
776 
777             return 0;
778         }
779 
780         case WM_PAINT:
781         {
782             _glfwInputWindowDamage(window);
783             break;
784         }
785 
786         case WM_ERASEBKGND:
787         {
788             return TRUE;
789         }
790 
791         case WM_SETCURSOR:
792         {
793             if (LOWORD(lParam) == HTCLIENT)
794             {
795                 updateCursorImage(window);
796                 return TRUE;
797             }
798 
799             break;
800         }
801 
802         case WM_DPICHANGED:
803         {
804             RECT* rect = (RECT*) lParam;
805             SetWindowPos(window->win32.handle,
806                          HWND_TOP,
807                          rect->left,
808                          rect->top,
809                          rect->right - rect->left,
810                          rect->bottom - rect->top,
811                          SWP_NOACTIVATE | SWP_NOZORDER);
812             break;
813         }
814 
815         case WM_DROPFILES:
816         {
817             HDROP drop = (HDROP) wParam;
818             POINT pt;
819             int i;
820 
821             const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
822             char** paths = calloc(count, sizeof(char*));
823 
824             // Move the mouse to the position of the drop
825             DragQueryPoint(drop, &pt);
826             _glfwInputCursorPos(window, pt.x, pt.y);
827 
828             for (i = 0;  i < count;  i++)
829             {
830                 const UINT length = DragQueryFileW(drop, i, NULL, 0);
831                 WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
832 
833                 DragQueryFileW(drop, i, buffer, length + 1);
834                 paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
835 
836                 free(buffer);
837             }
838 
839             _glfwInputDrop(window, count, (const char**) paths);
840 
841             for (i = 0;  i < count;  i++)
842                 free(paths[i]);
843             free(paths);
844 
845             DragFinish(drop);
846             return 0;
847         }
848     }
849 
850     return DefWindowProcW(hWnd, uMsg, wParam, lParam);
851 }
852 
853 // Creates the GLFW window
854 //
createNativeWindow(_GLFWwindow * window,const _GLFWwndconfig * wndconfig)855 static int createNativeWindow(_GLFWwindow* window,
856                               const _GLFWwndconfig* wndconfig)
857 {
858     int xpos, ypos, fullWidth, fullHeight;
859     WCHAR* wideTitle;
860     DWORD style = getWindowStyle(window);
861     DWORD exStyle = getWindowExStyle(window);
862 
863     if (window->monitor)
864     {
865         GLFWvidmode mode;
866 
867         // NOTE: This window placement is temporary and approximate, as the
868         //       correct position and size cannot be known until the monitor
869         //       video mode has been set
870         _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
871         _glfwPlatformGetVideoMode(window->monitor, &mode);
872         fullWidth  = mode.width;
873         fullHeight = mode.height;
874     }
875     else
876     {
877         xpos = CW_USEDEFAULT;
878         ypos = CW_USEDEFAULT;
879 
880         if (wndconfig->maximized)
881             style |= WS_MAXIMIZE;
882 
883         getFullWindowSize(style, exStyle,
884                           wndconfig->width, wndconfig->height,
885                           &fullWidth, &fullHeight);
886     }
887 
888     wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
889     if (!wideTitle)
890     {
891         _glfwInputError(GLFW_PLATFORM_ERROR,
892                         "Win32: Failed to convert window title to UTF-16");
893         return GLFW_FALSE;
894     }
895 
896     window->win32.handle = CreateWindowExW(exStyle,
897                                            _GLFW_WNDCLASSNAME,
898                                            wideTitle,
899                                            style,
900                                            xpos, ypos,
901                                            fullWidth, fullHeight,
902                                            NULL, // No parent window
903                                            NULL, // No window menu
904                                            GetModuleHandleW(NULL),
905                                            NULL);
906 
907     free(wideTitle);
908 
909     if (!window->win32.handle)
910     {
911         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window");
912         return GLFW_FALSE;
913     }
914 
915     SetPropW(window->win32.handle, L"GLFW", window);
916 
917     if (_glfw_ChangeWindowMessageFilterEx)
918     {
919         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
920                                           WM_DROPFILES, MSGFLT_ALLOW, NULL);
921         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
922                                           WM_COPYDATA, MSGFLT_ALLOW, NULL);
923         _glfw_ChangeWindowMessageFilterEx(window->win32.handle,
924                                           WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
925     }
926 
927     DragAcceptFiles(window->win32.handle, TRUE);
928 
929     return GLFW_TRUE;
930 }
931 
932 
933 //////////////////////////////////////////////////////////////////////////
934 //////                       GLFW internal API                      //////
935 //////////////////////////////////////////////////////////////////////////
936 
937 // Registers the GLFW window class
938 //
_glfwRegisterWindowClassWin32(void)939 GLFWbool _glfwRegisterWindowClassWin32(void)
940 {
941     WNDCLASSEXW wc;
942 
943     ZeroMemory(&wc, sizeof(wc));
944     wc.cbSize        = sizeof(wc);
945     wc.style         = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
946     wc.lpfnWndProc   = (WNDPROC) windowProc;
947     wc.hInstance     = GetModuleHandleW(NULL);
948     wc.hCursor       = LoadCursorW(NULL, IDC_ARROW);
949     wc.lpszClassName = _GLFW_WNDCLASSNAME;
950 
951     // Load user-provided icon if available
952     wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
953                           L"GLFW_ICON", IMAGE_ICON,
954                           0, 0, LR_DEFAULTSIZE | LR_SHARED);
955     if (!wc.hIcon)
956     {
957         // No user-provided icon found, load default icon
958         wc.hIcon = LoadImageW(NULL,
959                               IDI_APPLICATION, IMAGE_ICON,
960                               0, 0, LR_DEFAULTSIZE | LR_SHARED);
961     }
962 
963     if (!RegisterClassExW(&wc))
964     {
965         _glfwInputError(GLFW_PLATFORM_ERROR,
966                         "Win32: Failed to register window class");
967         return GLFW_FALSE;
968     }
969 
970     return GLFW_TRUE;
971 }
972 
973 // Unregisters the GLFW window class
974 //
_glfwUnregisterWindowClassWin32(void)975 void _glfwUnregisterWindowClassWin32(void)
976 {
977     UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
978 }
979 
980 
981 //////////////////////////////////////////////////////////////////////////
982 //////                       GLFW platform API                      //////
983 //////////////////////////////////////////////////////////////////////////
984 
_glfwPlatformCreateWindow(_GLFWwindow * window,const _GLFWwndconfig * wndconfig,const _GLFWctxconfig * ctxconfig,const _GLFWfbconfig * fbconfig)985 int _glfwPlatformCreateWindow(_GLFWwindow* window,
986                               const _GLFWwndconfig* wndconfig,
987                               const _GLFWctxconfig* ctxconfig,
988                               const _GLFWfbconfig* fbconfig)
989 {
990     if (!createNativeWindow(window, wndconfig))
991         return GLFW_FALSE;
992 
993     if (ctxconfig->client != GLFW_NO_API)
994     {
995         if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
996         {
997             if (!_glfwInitWGL())
998                 return GLFW_FALSE;
999             if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
1000                 return GLFW_FALSE;
1001         }
1002         else
1003         {
1004             if (!_glfwInitEGL())
1005                 return GLFW_FALSE;
1006             if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
1007                 return GLFW_FALSE;
1008         }
1009     }
1010 
1011     if (window->monitor)
1012     {
1013         _glfwPlatformShowWindow(window);
1014         _glfwPlatformFocusWindow(window);
1015         if (!acquireMonitor(window))
1016             return GLFW_FALSE;
1017 
1018         centerCursor(window);
1019     }
1020 
1021     return GLFW_TRUE;
1022 }
1023 
_glfwPlatformDestroyWindow(_GLFWwindow * window)1024 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
1025 {
1026     if (window->monitor)
1027         releaseMonitor(window);
1028 
1029     if (window->context.destroy)
1030         window->context.destroy(window);
1031 
1032     if (_glfw.win32.disabledCursorWindow == window)
1033         _glfw.win32.disabledCursorWindow = NULL;
1034 
1035     if (window->win32.handle)
1036     {
1037         RemovePropW(window->win32.handle, L"GLFW");
1038         DestroyWindow(window->win32.handle);
1039         window->win32.handle = NULL;
1040     }
1041 
1042     if (window->win32.bigIcon)
1043         DestroyIcon(window->win32.bigIcon);
1044 
1045     if (window->win32.smallIcon)
1046         DestroyIcon(window->win32.smallIcon);
1047 }
1048 
_glfwPlatformSetWindowTitle(_GLFWwindow * window,const char * title)1049 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
1050 {
1051     WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title);
1052     if (!wideTitle)
1053     {
1054         _glfwInputError(GLFW_PLATFORM_ERROR,
1055                         "Win32: Failed to convert window title to UTF-16");
1056         return;
1057     }
1058 
1059     SetWindowTextW(window->win32.handle, wideTitle);
1060     free(wideTitle);
1061 }
1062 
_glfwPlatformSetWindowIcon(_GLFWwindow * window,int count,const GLFWimage * images)1063 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
1064                                 int count, const GLFWimage* images)
1065 {
1066     HICON bigIcon = NULL, smallIcon = NULL;
1067 
1068     if (count)
1069     {
1070         const GLFWimage* bigImage = chooseImage(count, images,
1071                                                 GetSystemMetrics(SM_CXICON),
1072                                                 GetSystemMetrics(SM_CYICON));
1073         const GLFWimage* smallImage = chooseImage(count, images,
1074                                                   GetSystemMetrics(SM_CXSMICON),
1075                                                   GetSystemMetrics(SM_CYSMICON));
1076 
1077         bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
1078         smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
1079     }
1080     else
1081     {
1082         bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON);
1083         smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
1084     }
1085 
1086     SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
1087     SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
1088 
1089     if (window->win32.bigIcon)
1090         DestroyIcon(window->win32.bigIcon);
1091 
1092     if (window->win32.smallIcon)
1093         DestroyIcon(window->win32.smallIcon);
1094 
1095     if (count)
1096     {
1097         window->win32.bigIcon = bigIcon;
1098         window->win32.smallIcon = smallIcon;
1099     }
1100 }
1101 
_glfwPlatformGetWindowPos(_GLFWwindow * window,int * xpos,int * ypos)1102 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
1103 {
1104     POINT pos = { 0, 0 };
1105     ClientToScreen(window->win32.handle, &pos);
1106 
1107     if (xpos)
1108         *xpos = pos.x;
1109     if (ypos)
1110         *ypos = pos.y;
1111 }
1112 
_glfwPlatformSetWindowPos(_GLFWwindow * window,int xpos,int ypos)1113 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
1114 {
1115     RECT rect = { xpos, ypos, xpos, ypos };
1116     AdjustWindowRectEx(&rect, getWindowStyle(window),
1117                        FALSE, getWindowExStyle(window));
1118     SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
1119                  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
1120 }
1121 
_glfwPlatformGetWindowSize(_GLFWwindow * window,int * width,int * height)1122 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
1123 {
1124     RECT area;
1125     GetClientRect(window->win32.handle, &area);
1126 
1127     if (width)
1128         *width = area.right;
1129     if (height)
1130         *height = area.bottom;
1131 }
1132 
_glfwPlatformSetWindowSize(_GLFWwindow * window,int width,int height)1133 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
1134 {
1135     if (window->monitor)
1136     {
1137         if (window->monitor->window == window)
1138             acquireMonitor(window);
1139     }
1140     else
1141     {
1142         RECT rect = { 0, 0, width, height };
1143         AdjustWindowRectEx(&rect, getWindowStyle(window),
1144                            FALSE, getWindowExStyle(window));
1145         SetWindowPos(window->win32.handle, HWND_TOP,
1146                      0, 0, rect.right - rect.left, rect.bottom - rect.top,
1147                      SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
1148     }
1149 }
1150 
_glfwPlatformSetWindowSizeLimits(_GLFWwindow * window,int minwidth,int minheight,int maxwidth,int maxheight)1151 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
1152                                       int minwidth, int minheight,
1153                                       int maxwidth, int maxheight)
1154 {
1155     RECT area;
1156 
1157     if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
1158         (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE))
1159     {
1160         return;
1161     }
1162 
1163     GetWindowRect(window->win32.handle, &area);
1164     MoveWindow(window->win32.handle,
1165                area.left, area.top,
1166                area.right - area.left,
1167                area.bottom - area.top, TRUE);
1168 }
1169 
_glfwPlatformSetWindowAspectRatio(_GLFWwindow * window,int numer,int denom)1170 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
1171 {
1172     RECT area;
1173 
1174     if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
1175         return;
1176 
1177     GetWindowRect(window->win32.handle, &area);
1178     applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area);
1179     MoveWindow(window->win32.handle,
1180                area.left, area.top,
1181                area.right - area.left,
1182                area.bottom - area.top, TRUE);
1183 }
1184 
_glfwPlatformGetFramebufferSize(_GLFWwindow * window,int * width,int * height)1185 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
1186 {
1187     _glfwPlatformGetWindowSize(window, width, height);
1188 }
1189 
_glfwPlatformGetWindowFrameSize(_GLFWwindow * window,int * left,int * top,int * right,int * bottom)1190 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
1191                                      int* left, int* top,
1192                                      int* right, int* bottom)
1193 {
1194     RECT rect;
1195     int width, height;
1196 
1197     _glfwPlatformGetWindowSize(window, &width, &height);
1198     SetRect(&rect, 0, 0, width, height);
1199     AdjustWindowRectEx(&rect, getWindowStyle(window),
1200                        FALSE, getWindowExStyle(window));
1201 
1202     if (left)
1203         *left = -rect.left;
1204     if (top)
1205         *top = -rect.top;
1206     if (right)
1207         *right = rect.right - width;
1208     if (bottom)
1209         *bottom = rect.bottom - height;
1210 }
1211 
_glfwPlatformIconifyWindow(_GLFWwindow * window)1212 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
1213 {
1214     ShowWindow(window->win32.handle, SW_MINIMIZE);
1215 }
1216 
_glfwPlatformRestoreWindow(_GLFWwindow * window)1217 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
1218 {
1219     ShowWindow(window->win32.handle, SW_RESTORE);
1220 }
1221 
_glfwPlatformMaximizeWindow(_GLFWwindow * window)1222 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
1223 {
1224     ShowWindow(window->win32.handle, SW_MAXIMIZE);
1225 }
1226 
_glfwPlatformShowWindow(_GLFWwindow * window)1227 void _glfwPlatformShowWindow(_GLFWwindow* window)
1228 {
1229     ShowWindow(window->win32.handle, SW_SHOW);
1230 }
1231 
_glfwPlatformHideWindow(_GLFWwindow * window)1232 void _glfwPlatformHideWindow(_GLFWwindow* window)
1233 {
1234     ShowWindow(window->win32.handle, SW_HIDE);
1235 }
1236 
_glfwPlatformFocusWindow(_GLFWwindow * window)1237 void _glfwPlatformFocusWindow(_GLFWwindow* window)
1238 {
1239     BringWindowToTop(window->win32.handle);
1240     SetForegroundWindow(window->win32.handle);
1241     SetFocus(window->win32.handle);
1242 }
1243 
_glfwPlatformSetWindowMonitor(_GLFWwindow * window,_GLFWmonitor * monitor,int xpos,int ypos,int width,int height,int refreshRate)1244 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
1245                                    _GLFWmonitor* monitor,
1246                                    int xpos, int ypos,
1247                                    int width, int height,
1248                                    int refreshRate)
1249 {
1250     if (window->monitor == monitor)
1251     {
1252         if (monitor)
1253         {
1254             if (monitor->window == window)
1255                 acquireMonitor(window);
1256         }
1257         else
1258         {
1259             RECT rect = { xpos, ypos, xpos + width, ypos + height };
1260             AdjustWindowRectEx(&rect, getWindowStyle(window),
1261                                FALSE, getWindowExStyle(window));
1262             SetWindowPos(window->win32.handle, HWND_TOP,
1263                          rect.left, rect.top,
1264                          rect.right - rect.left, rect.bottom - rect.top,
1265                          SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
1266         }
1267 
1268         return;
1269     }
1270 
1271     if (window->monitor)
1272         releaseMonitor(window);
1273 
1274     _glfwInputWindowMonitorChange(window, monitor);
1275 
1276     if (monitor)
1277     {
1278         GLFWvidmode mode;
1279         DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
1280         UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
1281 
1282         if (window->decorated)
1283         {
1284             style &= ~WS_OVERLAPPEDWINDOW;
1285             style |= getWindowStyle(window);
1286             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
1287 
1288             flags |= SWP_FRAMECHANGED;
1289         }
1290 
1291         _glfwPlatformGetVideoMode(monitor, &mode);
1292         _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos);
1293 
1294         SetWindowPos(window->win32.handle, HWND_TOPMOST,
1295                      xpos, ypos, mode.width, mode.height,
1296                      flags);
1297 
1298         acquireMonitor(window);
1299     }
1300     else
1301     {
1302         HWND after;
1303         RECT rect = { xpos, ypos, xpos + width, ypos + height };
1304         DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
1305         UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
1306 
1307         if (window->decorated)
1308         {
1309             style &= ~WS_POPUP;
1310             style |= getWindowStyle(window);
1311             SetWindowLongW(window->win32.handle, GWL_STYLE, style);
1312 
1313             flags |= SWP_FRAMECHANGED;
1314         }
1315 
1316         if (window->floating)
1317             after = HWND_TOPMOST;
1318         else
1319             after = HWND_NOTOPMOST;
1320 
1321         AdjustWindowRectEx(&rect, getWindowStyle(window),
1322                            FALSE, getWindowExStyle(window));
1323         SetWindowPos(window->win32.handle, after,
1324                      rect.left, rect.top,
1325                      rect.right - rect.left, rect.bottom - rect.top,
1326                      flags);
1327     }
1328 }
1329 
_glfwPlatformWindowFocused(_GLFWwindow * window)1330 int _glfwPlatformWindowFocused(_GLFWwindow* window)
1331 {
1332     return window->win32.handle == GetActiveWindow();
1333 }
1334 
_glfwPlatformWindowIconified(_GLFWwindow * window)1335 int _glfwPlatformWindowIconified(_GLFWwindow* window)
1336 {
1337     return IsIconic(window->win32.handle);
1338 }
1339 
_glfwPlatformWindowVisible(_GLFWwindow * window)1340 int _glfwPlatformWindowVisible(_GLFWwindow* window)
1341 {
1342     return IsWindowVisible(window->win32.handle);
1343 }
1344 
_glfwPlatformWindowMaximized(_GLFWwindow * window)1345 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
1346 {
1347     return IsZoomed(window->win32.handle);
1348 }
1349 
_glfwPlatformPollEvents(void)1350 void _glfwPlatformPollEvents(void)
1351 {
1352     MSG msg;
1353     HWND handle;
1354     _GLFWwindow* window;
1355 
1356     while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
1357     {
1358         if (msg.message == WM_QUIT)
1359         {
1360             // Treat WM_QUIT as a close on all windows
1361             // While GLFW does not itself post WM_QUIT, other processes may post
1362             // it to this one, for example Task Manager
1363 
1364             window = _glfw.windowListHead;
1365             while (window)
1366             {
1367                 _glfwInputWindowCloseRequest(window);
1368                 window = window->next;
1369             }
1370         }
1371         else
1372         {
1373             TranslateMessage(&msg);
1374             DispatchMessageW(&msg);
1375         }
1376     }
1377 
1378     handle = GetActiveWindow();
1379     if (handle)
1380     {
1381         // LSHIFT/RSHIFT fixup (keys tend to "stick" without this fix)
1382         // This is the only async event handling in GLFW, but it solves some
1383         // nasty problems
1384         window = GetPropW(handle, L"GLFW");
1385         if (window)
1386         {
1387             const int mods = getAsyncKeyMods();
1388 
1389             // Get current state of left and right shift keys
1390             const int lshiftDown = (GetAsyncKeyState(VK_LSHIFT) >> 15) & 1;
1391             const int rshiftDown = (GetAsyncKeyState(VK_RSHIFT) >> 15) & 1;
1392 
1393             // See if this differs from our belief of what has happened
1394             // (we only have to check for lost key up events)
1395             if (!lshiftDown && window->keys[GLFW_KEY_LEFT_SHIFT] == 1)
1396                 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, 0, GLFW_RELEASE, mods);
1397 
1398             if (!rshiftDown && window->keys[GLFW_KEY_RIGHT_SHIFT] == 1)
1399                 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, 0, GLFW_RELEASE, mods);
1400         }
1401     }
1402 
1403     window = _glfw.win32.disabledCursorWindow;
1404     if (window)
1405     {
1406         int width, height;
1407         _glfwPlatformGetWindowSize(window, &width, &height);
1408 
1409         // NOTE: Re-center the cursor only if it has moved since the last call,
1410         //       to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
1411         if (window->win32.lastCursorPosX != width / 2 ||
1412             window->win32.lastCursorPosY != height / 2)
1413         {
1414             _glfwPlatformSetCursorPos(window, width / 2, height / 2);
1415         }
1416     }
1417 }
1418 
_glfwPlatformWaitEvents(void)1419 void _glfwPlatformWaitEvents(void)
1420 {
1421     WaitMessage();
1422 
1423     _glfwPlatformPollEvents();
1424 }
1425 
_glfwPlatformWaitEventsTimeout(double timeout)1426 void _glfwPlatformWaitEventsTimeout(double timeout)
1427 {
1428     MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS);
1429 
1430     _glfwPlatformPollEvents();
1431 }
1432 
_glfwPlatformPostEmptyEvent(void)1433 void _glfwPlatformPostEmptyEvent(void)
1434 {
1435     _GLFWwindow* window = _glfw.windowListHead;
1436     PostMessage(window->win32.handle, WM_NULL, 0, 0);
1437 }
1438 
_glfwPlatformGetCursorPos(_GLFWwindow * window,double * xpos,double * ypos)1439 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
1440 {
1441     POINT pos;
1442 
1443     if (GetCursorPos(&pos))
1444     {
1445         ScreenToClient(window->win32.handle, &pos);
1446 
1447         if (xpos)
1448             *xpos = pos.x;
1449         if (ypos)
1450             *ypos = pos.y;
1451     }
1452 }
1453 
_glfwPlatformSetCursorPos(_GLFWwindow * window,double xpos,double ypos)1454 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
1455 {
1456     POINT pos = { (int) xpos, (int) ypos };
1457 
1458     // Store the new position so it can be recognized later
1459     window->win32.lastCursorPosX = pos.x;
1460     window->win32.lastCursorPosY = pos.y;
1461 
1462     ClientToScreen(window->win32.handle, &pos);
1463     SetCursorPos(pos.x, pos.y);
1464 }
1465 
_glfwPlatformSetCursorMode(_GLFWwindow * window,int mode)1466 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
1467 {
1468     if (mode == GLFW_CURSOR_DISABLED)
1469     {
1470         _glfw.win32.disabledCursorWindow = window;
1471         _glfwPlatformGetCursorPos(window,
1472                                   &_glfw.win32.restoreCursorPosX,
1473                                   &_glfw.win32.restoreCursorPosY);
1474         centerCursor(window);
1475         updateClipRect(window);
1476     }
1477     else if (_glfw.win32.disabledCursorWindow == window)
1478     {
1479         _glfw.win32.disabledCursorWindow = NULL;
1480         updateClipRect(NULL);
1481         _glfwPlatformSetCursorPos(window,
1482                                   _glfw.win32.restoreCursorPosX,
1483                                   _glfw.win32.restoreCursorPosY);
1484     }
1485 
1486     if (cursorInClientArea(window))
1487         updateCursorImage(window);
1488 }
1489 
_glfwPlatformGetKeyName(int key,int scancode)1490 const char* _glfwPlatformGetKeyName(int key, int scancode)
1491 {
1492     WCHAR name[16];
1493 
1494     if (key != GLFW_KEY_UNKNOWN)
1495         scancode = _glfw.win32.nativeKeys[key];
1496 
1497     if (!_glfwIsPrintable(_glfw.win32.publicKeys[scancode]))
1498         return NULL;
1499 
1500     if (!GetKeyNameTextW(scancode << 16, name, sizeof(name) / sizeof(WCHAR)))
1501         return NULL;
1502 
1503     if (!WideCharToMultiByte(CP_UTF8, 0, name, -1,
1504                              _glfw.win32.keyName,
1505                              sizeof(_glfw.win32.keyName),
1506                              NULL, NULL))
1507     {
1508         return NULL;
1509     }
1510 
1511     return _glfw.win32.keyName;
1512 }
1513 
_glfwPlatformCreateCursor(_GLFWcursor * cursor,const GLFWimage * image,int xhot,int yhot)1514 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
1515                               const GLFWimage* image,
1516                               int xhot, int yhot)
1517 {
1518     cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
1519     if (!cursor->win32.handle)
1520         return GLFW_FALSE;
1521 
1522     return GLFW_TRUE;
1523 }
1524 
_glfwPlatformCreateStandardCursor(_GLFWcursor * cursor,int shape)1525 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
1526 {
1527     cursor->win32.handle =
1528         CopyCursor(LoadCursorW(NULL, translateCursorShape(shape)));
1529     if (!cursor->win32.handle)
1530     {
1531         _glfwInputError(GLFW_PLATFORM_ERROR,
1532                         "Win32: Failed to create standard cursor");
1533         return GLFW_FALSE;
1534     }
1535 
1536     return GLFW_TRUE;
1537 }
1538 
_glfwPlatformDestroyCursor(_GLFWcursor * cursor)1539 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
1540 {
1541     if (cursor->win32.handle)
1542         DestroyIcon((HICON) cursor->win32.handle);
1543 }
1544 
_glfwPlatformSetCursor(_GLFWwindow * window,_GLFWcursor * cursor)1545 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
1546 {
1547     if (cursorInClientArea(window))
1548         updateCursorImage(window);
1549 }
1550 
_glfwPlatformSetClipboardString(_GLFWwindow * window,const char * string)1551 void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
1552 {
1553     int characterCount;
1554     HANDLE object;
1555     WCHAR* buffer;
1556 
1557     characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
1558     if (!characterCount)
1559     {
1560         _glfwInputError(GLFW_PLATFORM_ERROR,
1561                         "Win32: Failed to convert clipboard string to UTF-16");
1562         return;
1563     }
1564 
1565     object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
1566     if (!object)
1567     {
1568         _glfwInputError(GLFW_PLATFORM_ERROR,
1569                         "Win32: Failed to allocate global handle for clipboard");
1570         return;
1571     }
1572 
1573     buffer = GlobalLock(object);
1574     if (!buffer)
1575     {
1576         GlobalFree(object);
1577 
1578         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
1579         return;
1580     }
1581 
1582     MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
1583     GlobalUnlock(object);
1584 
1585     if (!OpenClipboard(_glfw.win32.helperWindowHandle))
1586     {
1587         GlobalFree(object);
1588 
1589         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
1590         return;
1591     }
1592 
1593     EmptyClipboard();
1594     SetClipboardData(CF_UNICODETEXT, object);
1595     CloseClipboard();
1596 }
1597 
_glfwPlatformGetClipboardString(_GLFWwindow * window)1598 const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
1599 {
1600     HANDLE object;
1601     WCHAR* buffer;
1602 
1603     if (!OpenClipboard(_glfw.win32.helperWindowHandle))
1604     {
1605         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
1606         return NULL;
1607     }
1608 
1609     object = GetClipboardData(CF_UNICODETEXT);
1610     if (!object)
1611     {
1612         CloseClipboard();
1613 
1614         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
1615                         "Win32: Failed to convert clipboard to string");
1616         return NULL;
1617     }
1618 
1619     buffer = GlobalLock(object);
1620     if (!buffer)
1621     {
1622         CloseClipboard();
1623 
1624         _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
1625         return NULL;
1626     }
1627 
1628     free(_glfw.win32.clipboardString);
1629     _glfw.win32.clipboardString =
1630         _glfwCreateUTF8FromWideStringWin32(buffer);
1631 
1632     GlobalUnlock(object);
1633     CloseClipboard();
1634 
1635     if (!_glfw.win32.clipboardString)
1636     {
1637         _glfwInputError(GLFW_PLATFORM_ERROR,
1638                         "Win32: Failed to convert wide string to UTF-8");
1639         return NULL;
1640     }
1641 
1642     return _glfw.win32.clipboardString;
1643 }
1644 
_glfwPlatformGetRequiredInstanceExtensions(uint32_t * count)1645 char** _glfwPlatformGetRequiredInstanceExtensions(uint32_t* count)
1646 {
1647     char** extensions;
1648 
1649     *count = 0;
1650 
1651     if (!_glfw.vk.KHR_win32_surface)
1652         return NULL;
1653 
1654     extensions = calloc(2, sizeof(char*));
1655     extensions[0] = strdup("VK_KHR_surface");
1656     extensions[1] = strdup("VK_KHR_win32_surface");
1657 
1658     *count = 2;
1659     return extensions;
1660 }
1661 
_glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,VkPhysicalDevice device,uint32_t queuefamily)1662 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
1663                                                       VkPhysicalDevice device,
1664                                                       uint32_t queuefamily)
1665 {
1666     PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR vkGetPhysicalDeviceWin32PresentationSupportKHR =
1667         (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
1668         vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
1669     if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
1670     {
1671         _glfwInputError(GLFW_API_UNAVAILABLE,
1672                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
1673         return GLFW_FALSE;
1674     }
1675 
1676     return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
1677 }
1678 
_glfwPlatformCreateWindowSurface(VkInstance instance,_GLFWwindow * window,const VkAllocationCallbacks * allocator,VkSurfaceKHR * surface)1679 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
1680                                           _GLFWwindow* window,
1681                                           const VkAllocationCallbacks* allocator,
1682                                           VkSurfaceKHR* surface)
1683 {
1684     VkResult err;
1685     VkWin32SurfaceCreateInfoKHR sci;
1686     PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
1687 
1688     vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
1689         vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
1690     if (!vkCreateWin32SurfaceKHR)
1691     {
1692         _glfwInputError(GLFW_API_UNAVAILABLE,
1693                         "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
1694         return VK_ERROR_EXTENSION_NOT_PRESENT;
1695     }
1696 
1697     memset(&sci, 0, sizeof(sci));
1698     sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1699     sci.hinstance = GetModuleHandle(NULL);
1700     sci.hwnd = window->win32.handle;
1701 
1702     err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
1703     if (err)
1704     {
1705         _glfwInputError(GLFW_PLATFORM_ERROR,
1706                         "Win32: Failed to create Vulkan surface: %s",
1707                         _glfwGetVulkanResultString(err));
1708     }
1709 
1710     return err;
1711 }
1712 
1713 
1714 //////////////////////////////////////////////////////////////////////////
1715 //////                        GLFW native API                       //////
1716 //////////////////////////////////////////////////////////////////////////
1717 
glfwGetWin32Window(GLFWwindow * handle)1718 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
1719 {
1720     _GLFWwindow* window = (_GLFWwindow*) handle;
1721     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1722     return window->win32.handle;
1723 }
1724 
1725