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