ScrapExplorer - win32_window.c

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