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