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