1 //========================================================================
2 // GLFW 3.4 Win32 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org>
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.
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:
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.
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
26 //========================================================================
27 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
39 // Returns the window style for the specified window
41 static DWORD getWindowStyle(const _GLFWwindow* window)
43 DWORD style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
49 style |= WS_SYSMENU | WS_MINIMIZEBOX;
51 if (window->decorated)
55 if (window->resizable)
56 style |= WS_MAXIMIZEBOX | WS_THICKFRAME;
65 // Returns the extended window style for the specified window
67 static DWORD getWindowExStyle(const _GLFWwindow* window)
69 DWORD style = WS_EX_APPWINDOW;
71 if (window->monitor || window->floating)
72 style |= WS_EX_TOPMOST;
77 // Returns the image whose area most closely matches the desired one
79 static const GLFWimage* chooseImage(int count, const GLFWimage* images,
80 int width, int height)
82 int i, leastDiff = INT_MAX;
83 const GLFWimage* closest = NULL;
85 for (i = 0; i < count; i++)
87 const int currDiff = abs(images[i].width * images[i].height -
89 if (currDiff < leastDiff)
99 // Creates an RGBA icon or cursor
101 static HICON createIcon(const GLFWimage* image,
102 int xhot, int yhot, GLFWbool icon)
110 unsigned char* target = NULL;
111 unsigned char* source = image->pixels;
113 ZeroMemory(&bi, sizeof(bi));
114 bi.bV5Size = sizeof(bi);
115 bi.bV5Width = image->width;
116 bi.bV5Height = -image->height;
119 bi.bV5Compression = BI_BITFIELDS;
120 bi.bV5RedMask = 0x00ff0000;
121 bi.bV5GreenMask = 0x0000ff00;
122 bi.bV5BlueMask = 0x000000ff;
123 bi.bV5AlphaMask = 0xff000000;
126 color = CreateDIBSection(dc,
136 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
137 "Win32: Failed to create RGBA bitmap");
141 mask = CreateBitmap(image->width, image->height, 1, 1, NULL);
144 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
145 "Win32: Failed to create mask bitmap");
150 for (i = 0; i < image->width * image->height; i++)
152 target[0] = source[2];
153 target[1] = source[1];
154 target[2] = source[0];
155 target[3] = source[3];
160 ZeroMemory(&ii, sizeof(ii));
167 handle = CreateIconIndirect(&ii);
176 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
177 "Win32: Failed to create icon");
181 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
182 "Win32: Failed to create cursor");
189 // Translate content area size to full window size according to styles and DPI
191 static void getFullWindowSize(DWORD style, DWORD exStyle,
192 int contentWidth, int contentHeight,
193 int* fullWidth, int* fullHeight,
196 RECT rect = { 0, 0, contentWidth, contentHeight };
198 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
199 AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
201 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
203 *fullWidth = rect.right - rect.left;
204 *fullHeight = rect.bottom - rect.top;
207 // Enforce the content area aspect ratio based on which edge is being dragged
209 static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
212 UINT dpi = USER_DEFAULT_SCREEN_DPI;
213 const float ratio = (float) window->numer / (float) window->denom;
215 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
216 dpi = GetDpiForWindow(window->win32.handle);
218 getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
219 0, 0, &xoff, &yoff, dpi);
221 if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT ||
222 edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
224 area->bottom = area->top + yoff +
225 (int) ((area->right - area->left - xoff) / ratio);
227 else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
229 area->top = area->bottom - yoff -
230 (int) ((area->right - area->left - xoff) / ratio);
232 else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
234 area->right = area->left + xoff +
235 (int) ((area->bottom - area->top - yoff) * ratio);
239 // Updates the cursor image according to its cursor mode
241 static void updateCursorImage(_GLFWwindow* window)
243 if (window->cursorMode == GLFW_CURSOR_NORMAL)
246 SetCursor(window->cursor->win32.handle);
248 SetCursor(LoadCursorW(NULL, IDC_ARROW));
254 // Updates the cursor clip rect
256 static void updateClipRect(_GLFWwindow* window)
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);
270 // Enables WM_INPUT messages for the mouse for the specified window
272 static void enableRawMouseMotion(_GLFWwindow* window)
274 const RAWINPUTDEVICE rid = { 0x01, 0x02, 0, window->win32.handle };
276 if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
278 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
279 "Win32: Failed to register raw input device");
283 // Disables WM_INPUT messages for the mouse
285 static void disableRawMouseMotion(_GLFWwindow* window)
287 const RAWINPUTDEVICE rid = { 0x01, 0x02, RIDEV_REMOVE, NULL };
289 if (!RegisterRawInputDevices(&rid, 1, sizeof(rid)))
291 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
292 "Win32: Failed to remove raw input device");
296 // Apply disabled cursor mode to a focused window
298 static void disableCursor(_GLFWwindow* window)
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);
308 if (window->rawMouseMotion)
309 enableRawMouseMotion(window);
312 // Exit disabled cursor mode for the specified window
314 static void enableCursor(_GLFWwindow* window)
316 if (window->rawMouseMotion)
317 disableRawMouseMotion(window);
319 _glfw.win32.disabledCursorWindow = NULL;
320 updateClipRect(NULL);
321 _glfwPlatformSetCursorPos(window,
322 _glfw.win32.restoreCursorPosX,
323 _glfw.win32.restoreCursorPosY);
324 updateCursorImage(window);
327 // Returns whether the cursor is in the content area of the specified window
329 static GLFWbool cursorInContentArea(_GLFWwindow* window)
334 if (!GetCursorPos(&pos))
337 if (WindowFromPoint(pos) != window->win32.handle)
340 GetClientRect(window->win32.handle, &area);
341 ClientToScreen(window->win32.handle, (POINT*) &area.left);
342 ClientToScreen(window->win32.handle, (POINT*) &area.right);
344 return PtInRect(&area, pos);
347 // Update native window styles to match attributes
349 static void updateWindowStyles(const _GLFWwindow* window)
352 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
353 style &= ~(WS_OVERLAPPEDWINDOW | WS_POPUP);
354 style |= getWindowStyle(window);
356 GetClientRect(window->win32.handle, &rect);
358 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
360 AdjustWindowRectExForDpi(&rect, style, FALSE,
361 getWindowExStyle(window),
362 GetDpiForWindow(window->win32.handle));
365 AdjustWindowRectEx(&rect, style, FALSE, getWindowExStyle(window));
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,
372 rect.right - rect.left, rect.bottom - rect.top,
373 SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
376 // Update window framebuffer transparency
378 static void updateFramebufferTransparency(const _GLFWwindow* window)
380 BOOL composition, opaque;
383 if (!IsWindowsVistaOrGreater())
386 if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
389 if (IsWindows8OrGreater() ||
390 (SUCCEEDED(DwmGetColorizationColor(&color, &opaque)) && !opaque))
392 HRGN region = CreateRectRgn(0, 0, -1, -1);
393 DWM_BLURBEHIND bb = {0};
394 bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
395 bb.hRgnBlur = region;
398 DwmEnableBlurBehindWindow(window->win32.handle, &bb);
399 DeleteObject(region);
403 // HACK: Disable framebuffer transparency on Windows 7 when the
404 // colorization color is opaque, because otherwise the window
405 // contents is blended additively with the previous frame instead
407 DWM_BLURBEHIND bb = {0};
408 bb.dwFlags = DWM_BB_ENABLE;
409 DwmEnableBlurBehindWindow(window->win32.handle, &bb);
413 // Retrieves and translates modifier keys
415 static int getKeyMods(void)
419 if (GetKeyState(VK_SHIFT) & 0x8000)
420 mods |= GLFW_MOD_SHIFT;
421 if (GetKeyState(VK_CONTROL) & 0x8000)
422 mods |= GLFW_MOD_CONTROL;
423 if (GetKeyState(VK_MENU) & 0x8000)
424 mods |= GLFW_MOD_ALT;
425 if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000)
426 mods |= GLFW_MOD_SUPER;
427 if (GetKeyState(VK_CAPITAL) & 1)
428 mods |= GLFW_MOD_CAPS_LOCK;
429 if (GetKeyState(VK_NUMLOCK) & 1)
430 mods |= GLFW_MOD_NUM_LOCK;
435 static void fitToMonitor(_GLFWwindow* window)
437 MONITORINFO mi = { sizeof(mi) };
438 GetMonitorInfo(window->monitor->win32.handle, &mi);
439 SetWindowPos(window->win32.handle, HWND_TOPMOST,
442 mi.rcMonitor.right - mi.rcMonitor.left,
443 mi.rcMonitor.bottom - mi.rcMonitor.top,
444 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
447 // Make the specified window and its video mode active on its monitor
449 static void acquireMonitor(_GLFWwindow* window)
451 if (!_glfw.win32.acquiredMonitorCount)
453 SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
455 // HACK: When mouse trails are enabled the cursor becomes invisible when
456 // the OpenGL ICD switches to page flipping
457 SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
458 SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
461 if (!window->monitor->window)
462 _glfw.win32.acquiredMonitorCount++;
464 _glfwSetVideoModeWin32(window->monitor, &window->videoMode);
465 _glfwInputMonitorWindow(window->monitor, window);
468 // Remove the window and restore the original video mode
470 static void releaseMonitor(_GLFWwindow* window)
472 if (window->monitor->window != window)
475 _glfw.win32.acquiredMonitorCount--;
476 if (!_glfw.win32.acquiredMonitorCount)
478 SetThreadExecutionState(ES_CONTINUOUS);
480 // HACK: Restore mouse trail length saved in acquireMonitor
481 SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
484 _glfwInputMonitorWindow(window->monitor, NULL);
485 _glfwRestoreVideoModeWin32(window->monitor);
488 // Window callback function (handles window messages)
490 static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
491 WPARAM wParam, LPARAM lParam)
493 _GLFWwindow* window = GetPropW(hWnd, L"GLFW");
496 // This is the message handling for the hidden helper window
497 // and for a regular window during its initial creation
503 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
504 EnableNonClientDpiScaling(hWnd);
509 case WM_DISPLAYCHANGE:
510 _glfwPollMonitorsWin32();
513 case WM_DEVICECHANGE:
515 if (!_glfw.joysticksInitialized)
518 if (wParam == DBT_DEVICEARRIVAL)
520 DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
521 if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
522 _glfwDetectJoystickConnectionWin32();
524 else if (wParam == DBT_DEVICEREMOVECOMPLETE)
526 DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
527 if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
528 _glfwDetectJoystickDisconnectionWin32();
535 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
540 case WM_MOUSEACTIVATE:
542 // HACK: Postpone cursor disabling when the window was activated by
543 // clicking a caption button
544 if (HIWORD(lParam) == WM_LBUTTONDOWN)
546 if (LOWORD(lParam) != HTCLIENT)
547 window->win32.frameAction = GLFW_TRUE;
553 case WM_CAPTURECHANGED:
555 // HACK: Disable the cursor once the caption button action has been
556 // completed or cancelled
557 if (lParam == 0 && window->win32.frameAction)
559 if (window->cursorMode == GLFW_CURSOR_DISABLED)
560 disableCursor(window);
562 window->win32.frameAction = GLFW_FALSE;
570 _glfwInputWindowFocus(window, GLFW_TRUE);
572 // HACK: Do not disable cursor while the user is interacting with
574 if (window->win32.frameAction)
577 if (window->cursorMode == GLFW_CURSOR_DISABLED)
578 disableCursor(window);
585 if (window->cursorMode == GLFW_CURSOR_DISABLED)
586 enableCursor(window);
588 if (window->monitor && window->autoIconify)
589 _glfwPlatformIconifyWindow(window);
591 _glfwInputWindowFocus(window, GLFW_FALSE);
597 switch (wParam & 0xfff0)
600 case SC_MONITORPOWER:
604 // We are running in full screen mode, so disallow
605 // screen saver and screen blanking
612 // User trying to access application menu using ALT?
615 if (!window->win32.keymenu)
626 _glfwInputWindowCloseRequest(window);
630 case WM_INPUTLANGCHANGE:
632 _glfwUpdateKeyNamesWin32();
639 if (wParam >= 0xd800 && wParam <= 0xdbff)
640 window->win32.highSurrogate = (WCHAR) wParam;
643 unsigned int codepoint = 0;
645 if (wParam >= 0xdc00 && wParam <= 0xdfff)
647 if (window->win32.highSurrogate)
649 codepoint += (window->win32.highSurrogate - 0xd800) << 10;
650 codepoint += (WCHAR) wParam - 0xdc00;
651 codepoint += 0x10000;
655 codepoint = (WCHAR) wParam;
657 window->win32.highSurrogate = 0;
658 _glfwInputChar(window, codepoint, getKeyMods(), uMsg != WM_SYSCHAR);
661 if (uMsg == WM_SYSCHAR && window->win32.keymenu)
669 if (wParam == UNICODE_NOCHAR)
671 // WM_UNICHAR is not sent by Windows, but is sent by some
672 // third-party input method engine
673 // Returning TRUE here announces support for this message
677 _glfwInputChar(window, (unsigned int) wParam, getKeyMods(), GLFW_TRUE);
687 const int action = (HIWORD(lParam) & KF_UP) ? GLFW_RELEASE : GLFW_PRESS;
688 const int mods = getKeyMods();
690 scancode = (HIWORD(lParam) & (KF_EXTENDED | 0xff));
693 // NOTE: Some synthetic key messages have a scancode of zero
694 // HACK: Map the virtual key back to a usable scancode
695 scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
698 key = _glfw.win32.keycodes[scancode];
700 // The Ctrl keys require special handling
701 if (wParam == VK_CONTROL)
703 if (HIWORD(lParam) & KF_EXTENDED)
705 // Right side keys have the extended key bit set
706 key = GLFW_KEY_RIGHT_CONTROL;
710 // NOTE: Alt Gr sends Left Ctrl followed by Right Alt
711 // HACK: We only want one event for Alt Gr, so if we detect
712 // this sequence we discard this Left Ctrl message now
713 // and later report Right Alt normally
715 const DWORD time = GetMessageTime();
717 if (PeekMessageW(&next, NULL, 0, 0, PM_NOREMOVE))
719 if (next.message == WM_KEYDOWN ||
720 next.message == WM_SYSKEYDOWN ||
721 next.message == WM_KEYUP ||
722 next.message == WM_SYSKEYUP)
724 if (next.wParam == VK_MENU &&
725 (HIWORD(next.lParam) & KF_EXTENDED) &&
728 // Next message is Right Alt down so discard this
734 // This is a regular Left Ctrl message
735 key = GLFW_KEY_LEFT_CONTROL;
738 else if (wParam == VK_PROCESSKEY)
740 // IME notifies that keys have been filtered by setting the
741 // virtual key-code to VK_PROCESSKEY
745 if (action == GLFW_RELEASE && wParam == VK_SHIFT)
747 // HACK: Release both Shift keys on Shift up event, as when both
748 // are pressed the first release does not emit any event
749 // NOTE: The other half of this is in _glfwPlatformPollEvents
750 _glfwInputKey(window, GLFW_KEY_LEFT_SHIFT, scancode, action, mods);
751 _glfwInputKey(window, GLFW_KEY_RIGHT_SHIFT, scancode, action, mods);
753 else if (wParam == VK_SNAPSHOT)
755 // HACK: Key down is not reported for the Print Screen key
756 _glfwInputKey(window, key, scancode, GLFW_PRESS, mods);
757 _glfwInputKey(window, key, scancode, GLFW_RELEASE, mods);
760 _glfwInputKey(window, key, scancode, action, mods);
774 int i, button, action;
776 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP)
777 button = GLFW_MOUSE_BUTTON_LEFT;
778 else if (uMsg == WM_RBUTTONDOWN || uMsg == WM_RBUTTONUP)
779 button = GLFW_MOUSE_BUTTON_RIGHT;
780 else if (uMsg == WM_MBUTTONDOWN || uMsg == WM_MBUTTONUP)
781 button = GLFW_MOUSE_BUTTON_MIDDLE;
782 else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
783 button = GLFW_MOUSE_BUTTON_4;
785 button = GLFW_MOUSE_BUTTON_5;
787 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_RBUTTONDOWN ||
788 uMsg == WM_MBUTTONDOWN || uMsg == WM_XBUTTONDOWN)
793 action = GLFW_RELEASE;
795 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
797 if (window->mouseButtons[i] == GLFW_PRESS)
801 if (i > GLFW_MOUSE_BUTTON_LAST)
804 _glfwInputMouseClick(window, button, action, getKeyMods());
806 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
808 if (window->mouseButtons[i] == GLFW_PRESS)
812 if (i > GLFW_MOUSE_BUTTON_LAST)
815 if (uMsg == WM_XBUTTONDOWN || uMsg == WM_XBUTTONUP)
823 const int x = GET_X_LPARAM(lParam);
824 const int y = GET_Y_LPARAM(lParam);
826 if (!window->win32.cursorTracked)
829 ZeroMemory(&tme, sizeof(tme));
830 tme.cbSize = sizeof(tme);
831 tme.dwFlags = TME_LEAVE;
832 tme.hwndTrack = window->win32.handle;
833 TrackMouseEvent(&tme);
835 window->win32.cursorTracked = GLFW_TRUE;
836 _glfwInputCursorEnter(window, GLFW_TRUE);
839 if (window->cursorMode == GLFW_CURSOR_DISABLED)
841 const int dx = x - window->win32.lastCursorPosX;
842 const int dy = y - window->win32.lastCursorPosY;
844 if (_glfw.win32.disabledCursorWindow != window)
846 if (window->rawMouseMotion)
849 _glfwInputCursorPos(window,
850 window->virtualCursorPosX + dx,
851 window->virtualCursorPosY + dy);
854 _glfwInputCursorPos(window, x, y);
856 window->win32.lastCursorPosX = x;
857 window->win32.lastCursorPosY = y;
865 HRAWINPUT ri = (HRAWINPUT) lParam;
866 RAWINPUT* data = NULL;
869 if (_glfw.win32.disabledCursorWindow != window)
871 if (!window->rawMouseMotion)
874 GetRawInputData(ri, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
875 if (size > (UINT) _glfw.win32.rawInputSize)
877 free(_glfw.win32.rawInput);
878 _glfw.win32.rawInput = calloc(size, 1);
879 _glfw.win32.rawInputSize = size;
882 size = _glfw.win32.rawInputSize;
883 if (GetRawInputData(ri, RID_INPUT,
884 _glfw.win32.rawInput, &size,
885 sizeof(RAWINPUTHEADER)) == (UINT) -1)
887 _glfwInputError(GLFW_PLATFORM_ERROR,
888 "Win32: Failed to retrieve raw input data");
892 data = _glfw.win32.rawInput;
893 if (data->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
895 dx = data->data.mouse.lLastX - window->win32.lastCursorPosX;
896 dy = data->data.mouse.lLastY - window->win32.lastCursorPosY;
900 dx = data->data.mouse.lLastX;
901 dy = data->data.mouse.lLastY;
904 _glfwInputCursorPos(window,
905 window->virtualCursorPosX + dx,
906 window->virtualCursorPosY + dy);
908 window->win32.lastCursorPosX += dx;
909 window->win32.lastCursorPosY += dy;
915 window->win32.cursorTracked = GLFW_FALSE;
916 _glfwInputCursorEnter(window, GLFW_FALSE);
922 _glfwInputScroll(window, 0.0, (SHORT) HIWORD(wParam) / (double) WHEEL_DELTA);
928 // This message is only sent on Windows Vista and later
929 // NOTE: The X-axis is inverted for consistency with macOS and X11
930 _glfwInputScroll(window, -((SHORT) HIWORD(wParam) / (double) WHEEL_DELTA), 0.0);
934 case WM_ENTERSIZEMOVE:
935 case WM_ENTERMENULOOP:
937 if (window->win32.frameAction)
940 // HACK: Enable the cursor while the user is moving or
941 // resizing the window or using the window menu
942 if (window->cursorMode == GLFW_CURSOR_DISABLED)
943 enableCursor(window);
948 case WM_EXITSIZEMOVE:
949 case WM_EXITMENULOOP:
951 if (window->win32.frameAction)
954 // HACK: Disable the cursor once the user is done moving or
955 // resizing the window or using the menu
956 if (window->cursorMode == GLFW_CURSOR_DISABLED)
957 disableCursor(window);
964 const GLFWbool iconified = wParam == SIZE_MINIMIZED;
965 const GLFWbool maximized = wParam == SIZE_MAXIMIZED ||
966 (window->win32.maximized &&
967 wParam != SIZE_RESTORED);
969 if (_glfw.win32.disabledCursorWindow == window)
970 updateClipRect(window);
972 if (window->win32.iconified != iconified)
973 _glfwInputWindowIconify(window, iconified);
975 if (window->win32.maximized != maximized)
976 _glfwInputWindowMaximize(window, maximized);
978 _glfwInputFramebufferSize(window, LOWORD(lParam), HIWORD(lParam));
979 _glfwInputWindowSize(window, LOWORD(lParam), HIWORD(lParam));
981 if (window->monitor && window->win32.iconified != iconified)
984 releaseMonitor(window);
987 acquireMonitor(window);
988 fitToMonitor(window);
992 window->win32.iconified = iconified;
993 window->win32.maximized = maximized;
999 if (_glfw.win32.disabledCursorWindow == window)
1000 updateClipRect(window);
1002 // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
1003 // those macros do not handle negative window positions correctly
1004 _glfwInputWindowPos(window,
1005 GET_X_LPARAM(lParam),
1006 GET_Y_LPARAM(lParam));
1012 if (window->numer == GLFW_DONT_CARE ||
1013 window->denom == GLFW_DONT_CARE)
1018 applyAspectRatio(window, (int) wParam, (RECT*) lParam);
1022 case WM_GETMINMAXINFO:
1025 UINT dpi = USER_DEFAULT_SCREEN_DPI;
1026 MINMAXINFO* mmi = (MINMAXINFO*) lParam;
1028 if (window->monitor)
1031 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1032 dpi = GetDpiForWindow(window->win32.handle);
1034 getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
1035 0, 0, &xoff, &yoff, dpi);
1037 if (window->minwidth != GLFW_DONT_CARE &&
1038 window->minheight != GLFW_DONT_CARE)
1040 mmi->ptMinTrackSize.x = window->minwidth + xoff;
1041 mmi->ptMinTrackSize.y = window->minheight + yoff;
1044 if (window->maxwidth != GLFW_DONT_CARE &&
1045 window->maxheight != GLFW_DONT_CARE)
1047 mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
1048 mmi->ptMaxTrackSize.y = window->maxheight + yoff;
1051 if (!window->decorated)
1054 const HMONITOR mh = MonitorFromWindow(window->win32.handle,
1055 MONITOR_DEFAULTTONEAREST);
1057 ZeroMemory(&mi, sizeof(mi));
1058 mi.cbSize = sizeof(mi);
1059 GetMonitorInfo(mh, &mi);
1061 mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
1062 mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
1063 mmi->ptMaxSize.x = mi.rcWork.right - mi.rcWork.left;
1064 mmi->ptMaxSize.y = mi.rcWork.bottom - mi.rcWork.top;
1072 _glfwInputWindowDamage(window);
1084 // Prevent title bar from being drawn after restoring a minimized
1085 // undecorated window
1086 if (!window->decorated)
1092 case WM_DWMCOMPOSITIONCHANGED:
1093 case WM_DWMCOLORIZATIONCOLORCHANGED:
1095 if (window->win32.transparent)
1096 updateFramebufferTransparency(window);
1100 case WM_GETDPISCALEDSIZE:
1102 if (window->win32.scaleToMonitor)
1105 // Adjust the window size to keep the content area size constant
1106 if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
1108 RECT source = {0}, target = {0};
1109 SIZE* size = (SIZE*) lParam;
1111 AdjustWindowRectExForDpi(&source, getWindowStyle(window),
1112 FALSE, getWindowExStyle(window),
1113 GetDpiForWindow(window->win32.handle));
1114 AdjustWindowRectExForDpi(&target, getWindowStyle(window),
1115 FALSE, getWindowExStyle(window),
1118 size->cx += (target.right - target.left) -
1119 (source.right - source.left);
1120 size->cy += (target.bottom - target.top) -
1121 (source.bottom - source.top);
1130 const float xscale = HIWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
1131 const float yscale = LOWORD(wParam) / (float) USER_DEFAULT_SCREEN_DPI;
1133 // Only apply the suggested size if the OS is new enough to have
1134 // sent a WM_GETDPISCALEDSIZE before this
1135 if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
1137 RECT* suggested = (RECT*) lParam;
1138 SetWindowPos(window->win32.handle, HWND_TOP,
1141 suggested->right - suggested->left,
1142 suggested->bottom - suggested->top,
1143 SWP_NOACTIVATE | SWP_NOZORDER);
1146 _glfwInputWindowContentScale(window, xscale, yscale);
1152 if (LOWORD(lParam) == HTCLIENT)
1154 updateCursorImage(window);
1163 HDROP drop = (HDROP) wParam;
1167 const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
1168 char** paths = calloc(count, sizeof(char*));
1170 // Move the mouse to the position of the drop
1171 DragQueryPoint(drop, &pt);
1172 _glfwInputCursorPos(window, pt.x, pt.y);
1174 for (i = 0; i < count; i++)
1176 const UINT length = DragQueryFileW(drop, i, NULL, 0);
1177 WCHAR* buffer = calloc((size_t) length + 1, sizeof(WCHAR));
1179 DragQueryFileW(drop, i, buffer, length + 1);
1180 paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
1185 _glfwInputDrop(window, count, (const char**) paths);
1187 for (i = 0; i < count; i++)
1196 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
1199 // Creates the GLFW window
1201 static int createNativeWindow(_GLFWwindow* window,
1202 const _GLFWwndconfig* wndconfig,
1203 const _GLFWfbconfig* fbconfig)
1205 int xpos, ypos, fullWidth, fullHeight;
1207 DWORD style = getWindowStyle(window);
1208 DWORD exStyle = getWindowExStyle(window);
1210 if (window->monitor)
1214 // NOTE: This window placement is temporary and approximate, as the
1215 // correct position and size cannot be known until the monitor
1216 // video mode has been picked in _glfwSetVideoModeWin32
1217 _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos);
1218 _glfwPlatformGetVideoMode(window->monitor, &mode);
1219 fullWidth = mode.width;
1220 fullHeight = mode.height;
1224 xpos = CW_USEDEFAULT;
1225 ypos = CW_USEDEFAULT;
1227 window->win32.maximized = wndconfig->maximized;
1228 if (wndconfig->maximized)
1229 style |= WS_MAXIMIZE;
1231 getFullWindowSize(style, exStyle,
1232 wndconfig->width, wndconfig->height,
1233 &fullWidth, &fullHeight,
1234 USER_DEFAULT_SCREEN_DPI);
1237 wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
1241 window->win32.handle = CreateWindowExW(exStyle,
1246 fullWidth, fullHeight,
1247 NULL, // No parent window
1248 NULL, // No window menu
1249 GetModuleHandleW(NULL),
1254 if (!window->win32.handle)
1256 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
1257 "Win32: Failed to create window");
1261 SetPropW(window->win32.handle, L"GLFW", window);
1263 if (IsWindows7OrGreater())
1265 ChangeWindowMessageFilterEx(window->win32.handle,
1266 WM_DROPFILES, MSGFLT_ALLOW, NULL);
1267 ChangeWindowMessageFilterEx(window->win32.handle,
1268 WM_COPYDATA, MSGFLT_ALLOW, NULL);
1269 ChangeWindowMessageFilterEx(window->win32.handle,
1270 WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL);
1273 window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
1274 window->win32.keymenu = wndconfig->win32.keymenu;
1276 // Adjust window rect to account for DPI scaling of the window frame and
1277 // (if enabled) DPI scaling of the content area
1278 // This cannot be done until we know what monitor the window was placed on
1279 if (!window->monitor)
1281 RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
1282 WINDOWPLACEMENT wp = { sizeof(wp) };
1284 if (wndconfig->scaleToMonitor)
1286 float xscale, yscale;
1287 _glfwPlatformGetWindowContentScale(window, &xscale, &yscale);
1288 rect.right = (int) (rect.right * xscale);
1289 rect.bottom = (int) (rect.bottom * yscale);
1292 ClientToScreen(window->win32.handle, (POINT*) &rect.left);
1293 ClientToScreen(window->win32.handle, (POINT*) &rect.right);
1295 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1297 AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
1298 GetDpiForWindow(window->win32.handle));
1301 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1303 // Only update the restored window rect as the window may be maximized
1304 GetWindowPlacement(window->win32.handle, &wp);
1305 wp.rcNormalPosition = rect;
1306 wp.showCmd = SW_HIDE;
1307 SetWindowPlacement(window->win32.handle, &wp);
1310 DragAcceptFiles(window->win32.handle, TRUE);
1312 if (fbconfig->transparent)
1314 updateFramebufferTransparency(window);
1315 window->win32.transparent = GLFW_TRUE;
1322 //////////////////////////////////////////////////////////////////////////
1323 ////// GLFW internal API //////
1324 //////////////////////////////////////////////////////////////////////////
1326 // Registers the GLFW window class
1328 GLFWbool _glfwRegisterWindowClassWin32(void)
1332 ZeroMemory(&wc, sizeof(wc));
1333 wc.cbSize = sizeof(wc);
1334 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
1335 wc.lpfnWndProc = (WNDPROC) windowProc;
1336 wc.hInstance = GetModuleHandleW(NULL);
1337 wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
1338 wc.lpszClassName = _GLFW_WNDCLASSNAME;
1340 // Load user-provided icon if available
1341 wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
1342 L"GLFW_ICON", IMAGE_ICON,
1343 0, 0, LR_DEFAULTSIZE | LR_SHARED);
1346 // No user-provided icon found, load default icon
1347 wc.hIcon = LoadImageW(NULL,
1348 IDI_APPLICATION, IMAGE_ICON,
1349 0, 0, LR_DEFAULTSIZE | LR_SHARED);
1352 if (!RegisterClassExW(&wc))
1354 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
1355 "Win32: Failed to register window class");
1362 // Unregisters the GLFW window class
1364 void _glfwUnregisterWindowClassWin32(void)
1366 UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
1370 //////////////////////////////////////////////////////////////////////////
1371 ////// GLFW platform API //////
1372 //////////////////////////////////////////////////////////////////////////
1374 int _glfwPlatformCreateWindow(_GLFWwindow* window,
1375 const _GLFWwndconfig* wndconfig,
1376 const _GLFWctxconfig* ctxconfig,
1377 const _GLFWfbconfig* fbconfig)
1379 if (!createNativeWindow(window, wndconfig, fbconfig))
1382 if (ctxconfig->client != GLFW_NO_API)
1384 if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
1386 if (!_glfwInitWGL())
1388 if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
1391 else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
1393 if (!_glfwInitEGL())
1395 if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
1398 else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
1400 if (!_glfwInitOSMesa())
1402 if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
1407 if (window->monitor)
1409 _glfwPlatformShowWindow(window);
1410 _glfwPlatformFocusWindow(window);
1411 acquireMonitor(window);
1412 fitToMonitor(window);
1418 void _glfwPlatformDestroyWindow(_GLFWwindow* window)
1420 if (window->monitor)
1421 releaseMonitor(window);
1423 if (window->context.destroy)
1424 window->context.destroy(window);
1426 if (_glfw.win32.disabledCursorWindow == window)
1427 _glfw.win32.disabledCursorWindow = NULL;
1429 if (window->win32.handle)
1431 RemovePropW(window->win32.handle, L"GLFW");
1432 DestroyWindow(window->win32.handle);
1433 window->win32.handle = NULL;
1436 if (window->win32.bigIcon)
1437 DestroyIcon(window->win32.bigIcon);
1439 if (window->win32.smallIcon)
1440 DestroyIcon(window->win32.smallIcon);
1443 void _glfwPlatformSetWindowTitle(_GLFWwindow* window, const char* title)
1445 WCHAR* wideTitle = _glfwCreateWideStringFromUTF8Win32(title);
1449 SetWindowTextW(window->win32.handle, wideTitle);
1453 void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
1454 int count, const GLFWimage* images)
1456 HICON bigIcon = NULL, smallIcon = NULL;
1460 const GLFWimage* bigImage = chooseImage(count, images,
1461 GetSystemMetrics(SM_CXICON),
1462 GetSystemMetrics(SM_CYICON));
1463 const GLFWimage* smallImage = chooseImage(count, images,
1464 GetSystemMetrics(SM_CXSMICON),
1465 GetSystemMetrics(SM_CYSMICON));
1467 bigIcon = createIcon(bigImage, 0, 0, GLFW_TRUE);
1468 smallIcon = createIcon(smallImage, 0, 0, GLFW_TRUE);
1472 bigIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICON);
1473 smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
1476 SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
1477 SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
1479 if (window->win32.bigIcon)
1480 DestroyIcon(window->win32.bigIcon);
1482 if (window->win32.smallIcon)
1483 DestroyIcon(window->win32.smallIcon);
1487 window->win32.bigIcon = bigIcon;
1488 window->win32.smallIcon = smallIcon;
1492 void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
1494 POINT pos = { 0, 0 };
1495 ClientToScreen(window->win32.handle, &pos);
1503 void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)
1505 RECT rect = { xpos, ypos, xpos, ypos };
1507 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1509 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
1510 FALSE, getWindowExStyle(window),
1511 GetDpiForWindow(window->win32.handle));
1515 AdjustWindowRectEx(&rect, getWindowStyle(window),
1516 FALSE, getWindowExStyle(window));
1519 SetWindowPos(window->win32.handle, NULL, rect.left, rect.top, 0, 0,
1520 SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
1523 void _glfwPlatformGetWindowSize(_GLFWwindow* window, int* width, int* height)
1526 GetClientRect(window->win32.handle, &area);
1529 *width = area.right;
1531 *height = area.bottom;
1534 void _glfwPlatformSetWindowSize(_GLFWwindow* window, int width, int height)
1536 if (window->monitor)
1538 if (window->monitor->window == window)
1540 acquireMonitor(window);
1541 fitToMonitor(window);
1546 RECT rect = { 0, 0, width, height };
1548 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1550 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
1551 FALSE, getWindowExStyle(window),
1552 GetDpiForWindow(window->win32.handle));
1556 AdjustWindowRectEx(&rect, getWindowStyle(window),
1557 FALSE, getWindowExStyle(window));
1560 SetWindowPos(window->win32.handle, HWND_TOP,
1561 0, 0, rect.right - rect.left, rect.bottom - rect.top,
1562 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOZORDER);
1566 void _glfwPlatformSetWindowSizeLimits(_GLFWwindow* window,
1567 int minwidth, int minheight,
1568 int maxwidth, int maxheight)
1572 if ((minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE) &&
1573 (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE))
1578 GetWindowRect(window->win32.handle, &area);
1579 MoveWindow(window->win32.handle,
1580 area.left, area.top,
1581 area.right - area.left,
1582 area.bottom - area.top, TRUE);
1585 void _glfwPlatformSetWindowAspectRatio(_GLFWwindow* window, int numer, int denom)
1589 if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
1592 GetWindowRect(window->win32.handle, &area);
1593 applyAspectRatio(window, WMSZ_BOTTOMRIGHT, &area);
1594 MoveWindow(window->win32.handle,
1595 area.left, area.top,
1596 area.right - area.left,
1597 area.bottom - area.top, TRUE);
1600 void _glfwPlatformGetFramebufferSize(_GLFWwindow* window, int* width, int* height)
1602 _glfwPlatformGetWindowSize(window, width, height);
1605 void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
1606 int* left, int* top,
1607 int* right, int* bottom)
1612 _glfwPlatformGetWindowSize(window, &width, &height);
1613 SetRect(&rect, 0, 0, width, height);
1615 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1617 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
1618 FALSE, getWindowExStyle(window),
1619 GetDpiForWindow(window->win32.handle));
1623 AdjustWindowRectEx(&rect, getWindowStyle(window),
1624 FALSE, getWindowExStyle(window));
1632 *right = rect.right - width;
1634 *bottom = rect.bottom - height;
1637 void _glfwPlatformGetWindowContentScale(_GLFWwindow* window,
1638 float* xscale, float* yscale)
1640 const HANDLE handle = MonitorFromWindow(window->win32.handle,
1641 MONITOR_DEFAULTTONEAREST);
1642 _glfwGetMonitorContentScaleWin32(handle, xscale, yscale);
1645 void _glfwPlatformIconifyWindow(_GLFWwindow* window)
1647 ShowWindow(window->win32.handle, SW_MINIMIZE);
1650 void _glfwPlatformRestoreWindow(_GLFWwindow* window)
1652 ShowWindow(window->win32.handle, SW_RESTORE);
1655 void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
1657 ShowWindow(window->win32.handle, SW_MAXIMIZE);
1660 void _glfwPlatformShowWindow(_GLFWwindow* window)
1662 ShowWindow(window->win32.handle, SW_SHOWNA);
1665 void _glfwPlatformHideWindow(_GLFWwindow* window)
1667 ShowWindow(window->win32.handle, SW_HIDE);
1670 void _glfwPlatformRequestWindowAttention(_GLFWwindow* window)
1672 FlashWindow(window->win32.handle, TRUE);
1675 void _glfwPlatformFocusWindow(_GLFWwindow* window)
1677 BringWindowToTop(window->win32.handle);
1678 SetForegroundWindow(window->win32.handle);
1679 SetFocus(window->win32.handle);
1682 void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
1683 _GLFWmonitor* monitor,
1685 int width, int height,
1688 if (window->monitor == monitor)
1692 if (monitor->window == window)
1694 acquireMonitor(window);
1695 fitToMonitor(window);
1700 RECT rect = { xpos, ypos, xpos + width, ypos + height };
1702 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1704 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
1705 FALSE, getWindowExStyle(window),
1706 GetDpiForWindow(window->win32.handle));
1710 AdjustWindowRectEx(&rect, getWindowStyle(window),
1711 FALSE, getWindowExStyle(window));
1714 SetWindowPos(window->win32.handle, HWND_TOP,
1715 rect.left, rect.top,
1716 rect.right - rect.left, rect.bottom - rect.top,
1717 SWP_NOCOPYBITS | SWP_NOACTIVATE | SWP_NOZORDER);
1723 if (window->monitor)
1724 releaseMonitor(window);
1726 _glfwInputWindowMonitor(window, monitor);
1728 if (window->monitor)
1730 MONITORINFO mi = { sizeof(mi) };
1731 UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS;
1733 if (window->decorated)
1735 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
1736 style &= ~WS_OVERLAPPEDWINDOW;
1737 style |= getWindowStyle(window);
1738 SetWindowLongW(window->win32.handle, GWL_STYLE, style);
1739 flags |= SWP_FRAMECHANGED;
1742 acquireMonitor(window);
1744 GetMonitorInfo(window->monitor->win32.handle, &mi);
1745 SetWindowPos(window->win32.handle, HWND_TOPMOST,
1748 mi.rcMonitor.right - mi.rcMonitor.left,
1749 mi.rcMonitor.bottom - mi.rcMonitor.top,
1755 RECT rect = { xpos, ypos, xpos + width, ypos + height };
1756 DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE);
1757 UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS;
1759 if (window->decorated)
1762 style |= getWindowStyle(window);
1763 SetWindowLongW(window->win32.handle, GWL_STYLE, style);
1765 flags |= SWP_FRAMECHANGED;
1768 if (window->floating)
1769 after = HWND_TOPMOST;
1771 after = HWND_NOTOPMOST;
1773 if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
1775 AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
1776 FALSE, getWindowExStyle(window),
1777 GetDpiForWindow(window->win32.handle));
1781 AdjustWindowRectEx(&rect, getWindowStyle(window),
1782 FALSE, getWindowExStyle(window));
1785 SetWindowPos(window->win32.handle, after,
1786 rect.left, rect.top,
1787 rect.right - rect.left, rect.bottom - rect.top,
1792 int _glfwPlatformWindowFocused(_GLFWwindow* window)
1794 return window->win32.handle == GetActiveWindow();
1797 int _glfwPlatformWindowIconified(_GLFWwindow* window)
1799 return IsIconic(window->win32.handle);
1802 int _glfwPlatformWindowVisible(_GLFWwindow* window)
1804 return IsWindowVisible(window->win32.handle);
1807 int _glfwPlatformWindowMaximized(_GLFWwindow* window)
1809 return IsZoomed(window->win32.handle);
1812 int _glfwPlatformWindowHovered(_GLFWwindow* window)
1814 return cursorInContentArea(window);
1817 int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
1819 BOOL composition, opaque;
1822 if (!window->win32.transparent)
1825 if (!IsWindowsVistaOrGreater())
1828 if (FAILED(DwmIsCompositionEnabled(&composition)) || !composition)
1831 if (!IsWindows8OrGreater())
1833 // HACK: Disable framebuffer transparency on Windows 7 when the
1834 // colorization color is opaque, because otherwise the window
1835 // contents is blended additively with the previous frame instead
1837 if (FAILED(DwmGetColorizationColor(&color, &opaque)) || opaque)
1844 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
1846 updateWindowStyles(window);
1849 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled)
1851 updateWindowStyles(window);
1854 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled)
1856 const HWND after = enabled ? HWND_TOPMOST : HWND_NOTOPMOST;
1857 SetWindowPos(window->win32.handle, after, 0, 0, 0, 0,
1858 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1861 void _glfwPlatformSetWindowMousePassthrough(_GLFWwindow* window, GLFWbool enabled)
1866 DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
1868 if (exStyle & WS_EX_LAYERED)
1869 GetLayeredWindowAttributes(window->win32.handle, &key, &alpha, &flags);
1872 exStyle |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
1875 exStyle &= ~WS_EX_TRANSPARENT;
1876 // NOTE: Window opacity also needs the layered window style so do not
1877 // remove it if the window is alpha blended
1878 if (exStyle & WS_EX_LAYERED)
1880 if (!(flags & LWA_ALPHA))
1881 exStyle &= ~WS_EX_LAYERED;
1885 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
1888 SetLayeredWindowAttributes(window->win32.handle, key, alpha, flags);
1891 float _glfwPlatformGetWindowOpacity(_GLFWwindow* window)
1896 if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) &&
1897 GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags))
1899 if (flags & LWA_ALPHA)
1900 return alpha / 255.f;
1906 void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity)
1908 LONG exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
1909 if (opacity < 1.f || (exStyle & WS_EX_TRANSPARENT))
1911 const BYTE alpha = (BYTE) (255 * opacity);
1912 exStyle |= WS_EX_LAYERED;
1913 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
1914 SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA);
1916 else if (exStyle & WS_EX_TRANSPARENT)
1918 SetLayeredWindowAttributes(window->win32.handle, 0, 0, 0);
1922 exStyle &= ~WS_EX_LAYERED;
1923 SetWindowLongW(window->win32.handle, GWL_EXSTYLE, exStyle);
1927 void _glfwPlatformSetRawMouseMotion(_GLFWwindow *window, GLFWbool enabled)
1929 if (_glfw.win32.disabledCursorWindow != window)
1933 enableRawMouseMotion(window);
1935 disableRawMouseMotion(window);
1938 GLFWbool _glfwPlatformRawMouseMotionSupported(void)
1943 void _glfwPlatformPollEvents(void)
1947 _GLFWwindow* window;
1949 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
1951 if (msg.message == WM_QUIT)
1953 // NOTE: While GLFW does not itself post WM_QUIT, other processes
1954 // may post it to this one, for example Task Manager
1955 // HACK: Treat WM_QUIT as a close on all windows
1957 window = _glfw.windowListHead;
1960 _glfwInputWindowCloseRequest(window);
1961 window = window->next;
1966 TranslateMessage(&msg);
1967 DispatchMessageW(&msg);
1971 // HACK: Release modifier keys that the system did not emit KEYUP for
1972 // NOTE: Shift keys on Windows tend to "stick" when both are pressed as
1973 // no key up message is generated by the first key release
1974 // NOTE: Windows key is not reported as released by the Win+V hotkey
1975 // Other Win hotkeys are handled implicitly by _glfwInputWindowFocus
1976 // because they change the input focus
1977 // NOTE: The other half of this is in the WM_*KEY* handler in windowProc
1978 handle = GetActiveWindow();
1981 window = GetPropW(handle, L"GLFW");
1985 const int keys[4][2] =
1987 { VK_LSHIFT, GLFW_KEY_LEFT_SHIFT },
1988 { VK_RSHIFT, GLFW_KEY_RIGHT_SHIFT },
1989 { VK_LWIN, GLFW_KEY_LEFT_SUPER },
1990 { VK_RWIN, GLFW_KEY_RIGHT_SUPER }
1993 for (i = 0; i < 4; i++)
1995 const int vk = keys[i][0];
1996 const int key = keys[i][1];
1997 const int scancode = _glfw.win32.scancodes[key];
1999 if ((GetKeyState(vk) & 0x8000))
2001 if (window->keys[key] != GLFW_PRESS)
2004 _glfwInputKey(window, key, scancode, GLFW_RELEASE, getKeyMods());
2009 window = _glfw.win32.disabledCursorWindow;
2013 _glfwPlatformGetWindowSize(window, &width, &height);
2015 // NOTE: Re-center the cursor only if it has moved since the last call,
2016 // to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
2017 if (window->win32.lastCursorPosX != width / 2 ||
2018 window->win32.lastCursorPosY != height / 2)
2020 _glfwPlatformSetCursorPos(window, width / 2, height / 2);
2025 void _glfwPlatformWaitEvents(void)
2029 _glfwPlatformPollEvents();
2032 void _glfwPlatformWaitEventsTimeout(double timeout)
2034 MsgWaitForMultipleObjects(0, NULL, FALSE, (DWORD) (timeout * 1e3), QS_ALLEVENTS);
2036 _glfwPlatformPollEvents();
2039 void _glfwPlatformPostEmptyEvent(void)
2041 PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
2044 void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
2048 if (GetCursorPos(&pos))
2050 ScreenToClient(window->win32.handle, &pos);
2059 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double xpos, double ypos)
2061 POINT pos = { (int) xpos, (int) ypos };
2063 // Store the new position so it can be recognized later
2064 window->win32.lastCursorPosX = pos.x;
2065 window->win32.lastCursorPosY = pos.y;
2067 ClientToScreen(window->win32.handle, &pos);
2068 SetCursorPos(pos.x, pos.y);
2071 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
2073 if (mode == GLFW_CURSOR_DISABLED)
2075 if (_glfwPlatformWindowFocused(window))
2076 disableCursor(window);
2078 else if (_glfw.win32.disabledCursorWindow == window)
2079 enableCursor(window);
2080 else if (cursorInContentArea(window))
2081 updateCursorImage(window);
2084 const char* _glfwPlatformGetScancodeName(int scancode)
2086 if (scancode < 0 || scancode > (KF_EXTENDED | 0xff) ||
2087 _glfw.win32.keycodes[scancode] == GLFW_KEY_UNKNOWN)
2089 _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode");
2093 return _glfw.win32.keynames[_glfw.win32.keycodes[scancode]];
2096 int _glfwPlatformGetKeyScancode(int key)
2098 return _glfw.win32.scancodes[key];
2101 int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
2102 const GLFWimage* image,
2105 cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
2106 if (!cursor->win32.handle)
2112 int _glfwPlatformCreateStandardCursor(_GLFWcursor* cursor, int shape)
2116 if (shape == GLFW_ARROW_CURSOR)
2118 else if (shape == GLFW_IBEAM_CURSOR)
2120 else if (shape == GLFW_CROSSHAIR_CURSOR)
2122 else if (shape == GLFW_POINTING_HAND_CURSOR)
2124 else if (shape == GLFW_RESIZE_EW_CURSOR)
2126 else if (shape == GLFW_RESIZE_NS_CURSOR)
2128 else if (shape == GLFW_RESIZE_NWSE_CURSOR)
2130 else if (shape == GLFW_RESIZE_NESW_CURSOR)
2132 else if (shape == GLFW_RESIZE_ALL_CURSOR)
2134 else if (shape == GLFW_NOT_ALLOWED_CURSOR)
2138 _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Unknown standard cursor");
2142 cursor->win32.handle = LoadImageW(NULL,
2143 MAKEINTRESOURCEW(id), IMAGE_CURSOR, 0, 0,
2144 LR_DEFAULTSIZE | LR_SHARED);
2145 if (!cursor->win32.handle)
2147 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2148 "Win32: Failed to create standard cursor");
2155 void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
2157 if (cursor->win32.handle)
2158 DestroyIcon((HICON) cursor->win32.handle);
2161 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
2163 if (cursorInContentArea(window))
2164 updateCursorImage(window);
2167 void _glfwPlatformSetClipboardString(const char* string)
2173 characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
2174 if (!characterCount)
2177 object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
2180 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2181 "Win32: Failed to allocate global handle for clipboard");
2185 buffer = GlobalLock(object);
2188 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2189 "Win32: Failed to lock global handle");
2194 MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
2195 GlobalUnlock(object);
2197 if (!OpenClipboard(_glfw.win32.helperWindowHandle))
2199 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2200 "Win32: Failed to open clipboard");
2206 SetClipboardData(CF_UNICODETEXT, object);
2210 const char* _glfwPlatformGetClipboardString(void)
2215 if (!OpenClipboard(_glfw.win32.helperWindowHandle))
2217 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2218 "Win32: Failed to open clipboard");
2222 object = GetClipboardData(CF_UNICODETEXT);
2225 _glfwInputErrorWin32(GLFW_FORMAT_UNAVAILABLE,
2226 "Win32: Failed to convert clipboard to string");
2231 buffer = GlobalLock(object);
2234 _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
2235 "Win32: Failed to lock global handle");
2240 free(_glfw.win32.clipboardString);
2241 _glfw.win32.clipboardString = _glfwCreateUTF8FromWideStringWin32(buffer);
2243 GlobalUnlock(object);
2246 return _glfw.win32.clipboardString;
2249 EGLenum _glfwPlatformGetEGLPlatform(EGLint** attribs)
2251 if (_glfw.egl.ANGLE_platform_angle)
2255 if (_glfw.egl.ANGLE_platform_angle_opengl)
2257 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
2258 type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
2259 else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES)
2260 type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
2263 if (_glfw.egl.ANGLE_platform_angle_d3d)
2265 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D9)
2266 type = EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE;
2267 else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_D3D11)
2268 type = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
2271 if (_glfw.egl.ANGLE_platform_angle_vulkan)
2273 if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN)
2274 type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
2279 *attribs = calloc(3, sizeof(EGLint));
2280 (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
2281 (*attribs)[1] = type;
2282 (*attribs)[2] = EGL_NONE;
2283 return EGL_PLATFORM_ANGLE_ANGLE;
2290 EGLNativeDisplayType _glfwPlatformGetEGLNativeDisplay(void)
2292 return GetDC(_glfw.win32.helperWindowHandle);
2295 EGLNativeWindowType _glfwPlatformGetEGLNativeWindow(_GLFWwindow* window)
2297 return window->win32.handle;
2300 void _glfwPlatformGetRequiredInstanceExtensions(char** extensions)
2302 if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_win32_surface)
2305 extensions[0] = "VK_KHR_surface";
2306 extensions[1] = "VK_KHR_win32_surface";
2309 int _glfwPlatformGetPhysicalDevicePresentationSupport(VkInstance instance,
2310 VkPhysicalDevice device,
2311 uint32_t queuefamily)
2313 PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR
2314 vkGetPhysicalDeviceWin32PresentationSupportKHR =
2315 (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)
2316 vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR");
2317 if (!vkGetPhysicalDeviceWin32PresentationSupportKHR)
2319 _glfwInputError(GLFW_API_UNAVAILABLE,
2320 "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
2324 return vkGetPhysicalDeviceWin32PresentationSupportKHR(device, queuefamily);
2327 VkResult _glfwPlatformCreateWindowSurface(VkInstance instance,
2328 _GLFWwindow* window,
2329 const VkAllocationCallbacks* allocator,
2330 VkSurfaceKHR* surface)
2333 VkWin32SurfaceCreateInfoKHR sci;
2334 PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR;
2336 vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)
2337 vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR");
2338 if (!vkCreateWin32SurfaceKHR)
2340 _glfwInputError(GLFW_API_UNAVAILABLE,
2341 "Win32: Vulkan instance missing VK_KHR_win32_surface extension");
2342 return VK_ERROR_EXTENSION_NOT_PRESENT;
2345 memset(&sci, 0, sizeof(sci));
2346 sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
2347 sci.hinstance = GetModuleHandle(NULL);
2348 sci.hwnd = window->win32.handle;
2350 err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
2353 _glfwInputError(GLFW_PLATFORM_ERROR,
2354 "Win32: Failed to create Vulkan surface: %s",
2355 _glfwGetVulkanResultString(err));
2362 //////////////////////////////////////////////////////////////////////////
2363 ////// GLFW native API //////
2364 //////////////////////////////////////////////////////////////////////////
2366 GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
2368 _GLFWwindow* window = (_GLFWwindow*) handle;
2369 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
2370 return window->win32.handle;