glfw3.c 3.4.0

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