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