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,2072 @@
1
+ //========================================================================
2
+ // GLFW 3.4 macOS - www.glfw.org
3
+ //------------------------------------------------------------------------
4
+ // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
5
+ //
6
+ // This software is provided 'as-is', without any express or implied
7
+ // warranty. In no event will the authors be held liable for any damages
8
+ // arising from the use of this software.
9
+ //
10
+ // Permission is granted to anyone to use this software for any purpose,
11
+ // including commercial applications, and to alter it and redistribute it
12
+ // freely, subject to the following restrictions:
13
+ //
14
+ // 1. The origin of this software must not be misrepresented; you must not
15
+ // claim that you wrote the original software. If you use this software
16
+ // in a product, an acknowledgment in the product documentation would
17
+ // be appreciated but is not required.
18
+ //
19
+ // 2. Altered source versions must be plainly marked as such, and must not
20
+ // be misrepresented as being the original software.
21
+ //
22
+ // 3. This notice may not be removed or altered from any source
23
+ // distribution.
24
+ //
25
+ //========================================================================
26
+
27
+ #include "internal.h"
28
+
29
+ #if defined(_GLFW_COCOA)
30
+
31
+ #include <float.h>
32
+ #include <string.h>
33
+
34
+ // HACK: This enum value is missing from framework headers on OS X 10.11 despite
35
+ // having been (according to documentation) added in Mac OS X 10.7
36
+ #define NSWindowCollectionBehaviorFullScreenNone (1 << 9)
37
+
38
+ // Returns whether the cursor is in the content area of the specified window
39
+ //
40
+ static GLFWbool cursorInContentArea(_GLFWwindow* window)
41
+ {
42
+ const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
43
+ return [window->ns.view mouse:pos inRect:[window->ns.view frame]];
44
+ }
45
+
46
+ // Hides the cursor if not already hidden
47
+ //
48
+ static void hideCursor(_GLFWwindow* window)
49
+ {
50
+ if (!_glfw.ns.cursorHidden)
51
+ {
52
+ [NSCursor hide];
53
+ _glfw.ns.cursorHidden = GLFW_TRUE;
54
+ }
55
+ }
56
+
57
+ // Shows the cursor if not already shown
58
+ //
59
+ static void showCursor(_GLFWwindow* window)
60
+ {
61
+ if (_glfw.ns.cursorHidden)
62
+ {
63
+ [NSCursor unhide];
64
+ _glfw.ns.cursorHidden = GLFW_FALSE;
65
+ }
66
+ }
67
+
68
+ // Updates the cursor image according to its cursor mode
69
+ //
70
+ static void updateCursorImage(_GLFWwindow* window)
71
+ {
72
+ if (window->cursorMode == GLFW_CURSOR_NORMAL)
73
+ {
74
+ showCursor(window);
75
+
76
+ if (window->cursor)
77
+ [(NSCursor*) window->cursor->ns.object set];
78
+ else
79
+ [[NSCursor arrowCursor] set];
80
+ }
81
+ else
82
+ hideCursor(window);
83
+ }
84
+
85
+ // Apply chosen cursor mode to a focused window
86
+ //
87
+ static void updateCursorMode(_GLFWwindow* window)
88
+ {
89
+ if (window->cursorMode == GLFW_CURSOR_DISABLED)
90
+ {
91
+ _glfw.ns.disabledCursorWindow = window;
92
+ _glfwGetCursorPosCocoa(window,
93
+ &_glfw.ns.restoreCursorPosX,
94
+ &_glfw.ns.restoreCursorPosY);
95
+ _glfwCenterCursorInContentArea(window);
96
+ CGAssociateMouseAndMouseCursorPosition(false);
97
+ }
98
+ else if (_glfw.ns.disabledCursorWindow == window)
99
+ {
100
+ _glfw.ns.disabledCursorWindow = NULL;
101
+ _glfwSetCursorPosCocoa(window,
102
+ _glfw.ns.restoreCursorPosX,
103
+ _glfw.ns.restoreCursorPosY);
104
+ // NOTE: The matching CGAssociateMouseAndMouseCursorPosition call is
105
+ // made in _glfwSetCursorPosCocoa as part of a workaround
106
+ }
107
+
108
+ if (cursorInContentArea(window))
109
+ updateCursorImage(window);
110
+ }
111
+
112
+ // Make the specified window and its video mode active on its monitor
113
+ //
114
+ static void acquireMonitor(_GLFWwindow* window)
115
+ {
116
+ _glfwSetVideoModeCocoa(window->monitor, &window->videoMode);
117
+ const CGRect bounds = CGDisplayBounds(window->monitor->ns.displayID);
118
+ const NSRect frame = NSMakeRect(bounds.origin.x,
119
+ _glfwTransformYCocoa(bounds.origin.y + bounds.size.height - 1),
120
+ bounds.size.width,
121
+ bounds.size.height);
122
+
123
+ [window->ns.object setFrame:frame display:YES];
124
+
125
+ _glfwInputMonitorWindow(window->monitor, window);
126
+ }
127
+
128
+ // Remove the window and restore the original video mode
129
+ //
130
+ static void releaseMonitor(_GLFWwindow* window)
131
+ {
132
+ if (window->monitor->window != window)
133
+ return;
134
+
135
+ _glfwInputMonitorWindow(window->monitor, NULL);
136
+ _glfwRestoreVideoModeCocoa(window->monitor);
137
+ }
138
+
139
+ // Translates macOS key modifiers into GLFW ones
140
+ //
141
+ static int translateFlags(NSUInteger flags)
142
+ {
143
+ int mods = 0;
144
+
145
+ if (flags & NSEventModifierFlagShift)
146
+ mods |= GLFW_MOD_SHIFT;
147
+ if (flags & NSEventModifierFlagControl)
148
+ mods |= GLFW_MOD_CONTROL;
149
+ if (flags & NSEventModifierFlagOption)
150
+ mods |= GLFW_MOD_ALT;
151
+ if (flags & NSEventModifierFlagCommand)
152
+ mods |= GLFW_MOD_SUPER;
153
+ if (flags & NSEventModifierFlagCapsLock)
154
+ mods |= GLFW_MOD_CAPS_LOCK;
155
+
156
+ return mods;
157
+ }
158
+
159
+ // Translates a macOS keycode to a GLFW keycode
160
+ //
161
+ static int translateKey(unsigned int key)
162
+ {
163
+ if (key >= sizeof(_glfw.ns.keycodes) / sizeof(_glfw.ns.keycodes[0]))
164
+ return GLFW_KEY_UNKNOWN;
165
+
166
+ return _glfw.ns.keycodes[key];
167
+ }
168
+
169
+ // Translate a GLFW keycode to a Cocoa modifier flag
170
+ //
171
+ static NSUInteger translateKeyToModifierFlag(int key)
172
+ {
173
+ switch (key)
174
+ {
175
+ case GLFW_KEY_LEFT_SHIFT:
176
+ case GLFW_KEY_RIGHT_SHIFT:
177
+ return NSEventModifierFlagShift;
178
+ case GLFW_KEY_LEFT_CONTROL:
179
+ case GLFW_KEY_RIGHT_CONTROL:
180
+ return NSEventModifierFlagControl;
181
+ case GLFW_KEY_LEFT_ALT:
182
+ case GLFW_KEY_RIGHT_ALT:
183
+ return NSEventModifierFlagOption;
184
+ case GLFW_KEY_LEFT_SUPER:
185
+ case GLFW_KEY_RIGHT_SUPER:
186
+ return NSEventModifierFlagCommand;
187
+ case GLFW_KEY_CAPS_LOCK:
188
+ return NSEventModifierFlagCapsLock;
189
+ }
190
+
191
+ return 0;
192
+ }
193
+
194
+ // Defines a constant for empty ranges in NSTextInputClient
195
+ //
196
+ static const NSRange kEmptyRange = { NSNotFound, 0 };
197
+
198
+
199
+ //------------------------------------------------------------------------
200
+ // Delegate for window related notifications
201
+ //------------------------------------------------------------------------
202
+
203
+ @interface GLFWWindowDelegate : NSObject
204
+ {
205
+ _GLFWwindow* window;
206
+ }
207
+
208
+ - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
209
+
210
+ @end
211
+
212
+ @implementation GLFWWindowDelegate
213
+
214
+ - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow
215
+ {
216
+ self = [super init];
217
+ if (self != nil)
218
+ window = initWindow;
219
+
220
+ return self;
221
+ }
222
+
223
+ - (BOOL)windowShouldClose:(id)sender
224
+ {
225
+ _glfwInputWindowCloseRequest(window);
226
+ return NO;
227
+ }
228
+
229
+ - (void)windowDidResize:(NSNotification *)notification
230
+ {
231
+ if (window->context.source == GLFW_NATIVE_CONTEXT_API)
232
+ [window->context.nsgl.object update];
233
+
234
+ if (_glfw.ns.disabledCursorWindow == window)
235
+ _glfwCenterCursorInContentArea(window);
236
+
237
+ const int maximized = [window->ns.object isZoomed];
238
+ if (window->ns.maximized != maximized)
239
+ {
240
+ window->ns.maximized = maximized;
241
+ _glfwInputWindowMaximize(window, maximized);
242
+ }
243
+
244
+ const NSRect contentRect = [window->ns.view frame];
245
+ const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
246
+
247
+ if (fbRect.size.width != window->ns.fbWidth ||
248
+ fbRect.size.height != window->ns.fbHeight)
249
+ {
250
+ window->ns.fbWidth = fbRect.size.width;
251
+ window->ns.fbHeight = fbRect.size.height;
252
+ _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
253
+ }
254
+
255
+ if (contentRect.size.width != window->ns.width ||
256
+ contentRect.size.height != window->ns.height)
257
+ {
258
+ window->ns.width = contentRect.size.width;
259
+ window->ns.height = contentRect.size.height;
260
+ _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height);
261
+ }
262
+ }
263
+
264
+ - (void)windowDidMove:(NSNotification *)notification
265
+ {
266
+ if (window->context.source == GLFW_NATIVE_CONTEXT_API)
267
+ [window->context.nsgl.object update];
268
+
269
+ if (_glfw.ns.disabledCursorWindow == window)
270
+ _glfwCenterCursorInContentArea(window);
271
+
272
+ int x, y;
273
+ _glfwGetWindowPosCocoa(window, &x, &y);
274
+ _glfwInputWindowPos(window, x, y);
275
+ }
276
+
277
+ - (void)windowDidMiniaturize:(NSNotification *)notification
278
+ {
279
+ if (window->monitor)
280
+ releaseMonitor(window);
281
+
282
+ _glfwInputWindowIconify(window, GLFW_TRUE);
283
+ }
284
+
285
+ - (void)windowDidDeminiaturize:(NSNotification *)notification
286
+ {
287
+ if (window->monitor)
288
+ acquireMonitor(window);
289
+
290
+ _glfwInputWindowIconify(window, GLFW_FALSE);
291
+ }
292
+
293
+ - (void)windowDidBecomeKey:(NSNotification *)notification
294
+ {
295
+ if (_glfw.ns.disabledCursorWindow == window)
296
+ _glfwCenterCursorInContentArea(window);
297
+
298
+ _glfwInputWindowFocus(window, GLFW_TRUE);
299
+ updateCursorMode(window);
300
+ }
301
+
302
+ - (void)windowDidResignKey:(NSNotification *)notification
303
+ {
304
+ if (window->monitor && window->autoIconify)
305
+ _glfwIconifyWindowCocoa(window);
306
+
307
+ _glfwInputWindowFocus(window, GLFW_FALSE);
308
+ }
309
+
310
+ - (void)windowDidChangeOcclusionState:(NSNotification* )notification
311
+ {
312
+ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
313
+ if ([window->ns.object respondsToSelector:@selector(occlusionState)])
314
+ {
315
+ if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
316
+ window->ns.occluded = GLFW_FALSE;
317
+ else
318
+ window->ns.occluded = GLFW_TRUE;
319
+ }
320
+ #endif
321
+ }
322
+
323
+ @end
324
+
325
+
326
+ //------------------------------------------------------------------------
327
+ // Content view class for the GLFW window
328
+ //------------------------------------------------------------------------
329
+
330
+ @interface GLFWContentView : NSView <NSTextInputClient>
331
+ {
332
+ _GLFWwindow* window;
333
+ NSTrackingArea* trackingArea;
334
+ NSMutableAttributedString* markedText;
335
+ }
336
+
337
+ - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow;
338
+
339
+ @end
340
+
341
+ @implementation GLFWContentView
342
+
343
+ - (instancetype)initWithGlfwWindow:(_GLFWwindow *)initWindow
344
+ {
345
+ self = [super init];
346
+ if (self != nil)
347
+ {
348
+ window = initWindow;
349
+ trackingArea = nil;
350
+ markedText = [[NSMutableAttributedString alloc] init];
351
+
352
+ [self updateTrackingAreas];
353
+ [self registerForDraggedTypes:@[NSPasteboardTypeURL]];
354
+ }
355
+
356
+ return self;
357
+ }
358
+
359
+ - (void)dealloc
360
+ {
361
+ [trackingArea release];
362
+ [markedText release];
363
+ [super dealloc];
364
+ }
365
+
366
+ - (BOOL)isOpaque
367
+ {
368
+ return [window->ns.object isOpaque];
369
+ }
370
+
371
+ - (BOOL)canBecomeKeyView
372
+ {
373
+ return YES;
374
+ }
375
+
376
+ - (BOOL)acceptsFirstResponder
377
+ {
378
+ return YES;
379
+ }
380
+
381
+ - (BOOL)wantsUpdateLayer
382
+ {
383
+ return YES;
384
+ }
385
+
386
+ - (void)updateLayer
387
+ {
388
+ if (window->context.source == GLFW_NATIVE_CONTEXT_API)
389
+ [window->context.nsgl.object update];
390
+
391
+ _glfwInputWindowDamage(window);
392
+ }
393
+
394
+ - (void)cursorUpdate:(NSEvent *)event
395
+ {
396
+ updateCursorImage(window);
397
+ }
398
+
399
+ - (BOOL)acceptsFirstMouse:(NSEvent *)event
400
+ {
401
+ return YES;
402
+ }
403
+
404
+ - (void)mouseDown:(NSEvent *)event
405
+ {
406
+ _glfwInputMouseClick(window,
407
+ GLFW_MOUSE_BUTTON_LEFT,
408
+ GLFW_PRESS,
409
+ translateFlags([event modifierFlags]));
410
+ }
411
+
412
+ - (void)mouseDragged:(NSEvent *)event
413
+ {
414
+ [self mouseMoved:event];
415
+ }
416
+
417
+ - (void)mouseUp:(NSEvent *)event
418
+ {
419
+ _glfwInputMouseClick(window,
420
+ GLFW_MOUSE_BUTTON_LEFT,
421
+ GLFW_RELEASE,
422
+ translateFlags([event modifierFlags]));
423
+ }
424
+
425
+ - (void)mouseMoved:(NSEvent *)event
426
+ {
427
+ if (window->cursorMode == GLFW_CURSOR_DISABLED)
428
+ {
429
+ const double dx = [event deltaX] - window->ns.cursorWarpDeltaX;
430
+ const double dy = [event deltaY] - window->ns.cursorWarpDeltaY;
431
+
432
+ _glfwInputCursorPos(window,
433
+ window->virtualCursorPosX + dx,
434
+ window->virtualCursorPosY + dy);
435
+ }
436
+ else
437
+ {
438
+ const NSRect contentRect = [window->ns.view frame];
439
+ // NOTE: The returned location uses base 0,1 not 0,0
440
+ const NSPoint pos = [event locationInWindow];
441
+
442
+ _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
443
+ }
444
+
445
+ window->ns.cursorWarpDeltaX = 0;
446
+ window->ns.cursorWarpDeltaY = 0;
447
+ }
448
+
449
+ - (void)rightMouseDown:(NSEvent *)event
450
+ {
451
+ _glfwInputMouseClick(window,
452
+ GLFW_MOUSE_BUTTON_RIGHT,
453
+ GLFW_PRESS,
454
+ translateFlags([event modifierFlags]));
455
+ }
456
+
457
+ - (void)rightMouseDragged:(NSEvent *)event
458
+ {
459
+ [self mouseMoved:event];
460
+ }
461
+
462
+ - (void)rightMouseUp:(NSEvent *)event
463
+ {
464
+ _glfwInputMouseClick(window,
465
+ GLFW_MOUSE_BUTTON_RIGHT,
466
+ GLFW_RELEASE,
467
+ translateFlags([event modifierFlags]));
468
+ }
469
+
470
+ - (void)otherMouseDown:(NSEvent *)event
471
+ {
472
+ _glfwInputMouseClick(window,
473
+ (int) [event buttonNumber],
474
+ GLFW_PRESS,
475
+ translateFlags([event modifierFlags]));
476
+ }
477
+
478
+ - (void)otherMouseDragged:(NSEvent *)event
479
+ {
480
+ [self mouseMoved:event];
481
+ }
482
+
483
+ - (void)otherMouseUp:(NSEvent *)event
484
+ {
485
+ _glfwInputMouseClick(window,
486
+ (int) [event buttonNumber],
487
+ GLFW_RELEASE,
488
+ translateFlags([event modifierFlags]));
489
+ }
490
+
491
+ - (void)mouseExited:(NSEvent *)event
492
+ {
493
+ if (window->cursorMode == GLFW_CURSOR_HIDDEN)
494
+ showCursor(window);
495
+
496
+ _glfwInputCursorEnter(window, GLFW_FALSE);
497
+ }
498
+
499
+ - (void)mouseEntered:(NSEvent *)event
500
+ {
501
+ if (window->cursorMode == GLFW_CURSOR_HIDDEN)
502
+ hideCursor(window);
503
+
504
+ _glfwInputCursorEnter(window, GLFW_TRUE);
505
+ }
506
+
507
+ - (void)viewDidChangeBackingProperties
508
+ {
509
+ const NSRect contentRect = [window->ns.view frame];
510
+ const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
511
+ const float xscale = fbRect.size.width / contentRect.size.width;
512
+ const float yscale = fbRect.size.height / contentRect.size.height;
513
+
514
+ if (xscale != window->ns.xscale || yscale != window->ns.yscale)
515
+ {
516
+ if (window->ns.scaleFramebuffer && window->ns.layer)
517
+ [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
518
+
519
+ window->ns.xscale = xscale;
520
+ window->ns.yscale = yscale;
521
+ _glfwInputWindowContentScale(window, xscale, yscale);
522
+ }
523
+
524
+ if (fbRect.size.width != window->ns.fbWidth ||
525
+ fbRect.size.height != window->ns.fbHeight)
526
+ {
527
+ window->ns.fbWidth = fbRect.size.width;
528
+ window->ns.fbHeight = fbRect.size.height;
529
+ _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height);
530
+ }
531
+ }
532
+
533
+ - (void)drawRect:(NSRect)rect
534
+ {
535
+ _glfwInputWindowDamage(window);
536
+ }
537
+
538
+ - (void)updateTrackingAreas
539
+ {
540
+ if (trackingArea != nil)
541
+ {
542
+ [self removeTrackingArea:trackingArea];
543
+ [trackingArea release];
544
+ }
545
+
546
+ const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
547
+ NSTrackingActiveInKeyWindow |
548
+ NSTrackingEnabledDuringMouseDrag |
549
+ NSTrackingCursorUpdate |
550
+ NSTrackingInVisibleRect |
551
+ NSTrackingAssumeInside;
552
+
553
+ trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds]
554
+ options:options
555
+ owner:self
556
+ userInfo:nil];
557
+
558
+ [self addTrackingArea:trackingArea];
559
+ [super updateTrackingAreas];
560
+ }
561
+
562
+ - (void)keyDown:(NSEvent *)event
563
+ {
564
+ const int key = translateKey([event keyCode]);
565
+ const int mods = translateFlags([event modifierFlags]);
566
+
567
+ _glfwInputKey(window, key, [event keyCode], GLFW_PRESS, mods);
568
+
569
+ [self interpretKeyEvents:@[event]];
570
+ }
571
+
572
+ - (void)flagsChanged:(NSEvent *)event
573
+ {
574
+ int action;
575
+ const unsigned int modifierFlags =
576
+ [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
577
+ const int key = translateKey([event keyCode]);
578
+ const int mods = translateFlags(modifierFlags);
579
+ const NSUInteger keyFlag = translateKeyToModifierFlag(key);
580
+
581
+ if (keyFlag & modifierFlags)
582
+ {
583
+ if (window->keys[key] == GLFW_PRESS)
584
+ action = GLFW_RELEASE;
585
+ else
586
+ action = GLFW_PRESS;
587
+ }
588
+ else
589
+ action = GLFW_RELEASE;
590
+
591
+ _glfwInputKey(window, key, [event keyCode], action, mods);
592
+ }
593
+
594
+ - (void)keyUp:(NSEvent *)event
595
+ {
596
+ const int key = translateKey([event keyCode]);
597
+ const int mods = translateFlags([event modifierFlags]);
598
+ _glfwInputKey(window, key, [event keyCode], GLFW_RELEASE, mods);
599
+ }
600
+
601
+ - (void)scrollWheel:(NSEvent *)event
602
+ {
603
+ double deltaX = [event scrollingDeltaX];
604
+ double deltaY = [event scrollingDeltaY];
605
+
606
+ if ([event hasPreciseScrollingDeltas])
607
+ {
608
+ deltaX *= 0.1;
609
+ deltaY *= 0.1;
610
+ }
611
+
612
+ if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
613
+ _glfwInputScroll(window, deltaX, deltaY);
614
+ }
615
+
616
+ - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
617
+ {
618
+ // HACK: We don't know what to say here because we don't know what the
619
+ // application wants to do with the paths
620
+ return NSDragOperationGeneric;
621
+ }
622
+
623
+ - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
624
+ {
625
+ const NSRect contentRect = [window->ns.view frame];
626
+ // NOTE: The returned location uses base 0,1 not 0,0
627
+ const NSPoint pos = [sender draggingLocation];
628
+ _glfwInputCursorPos(window, pos.x, contentRect.size.height - pos.y);
629
+
630
+ NSPasteboard* pasteboard = [sender draggingPasteboard];
631
+ NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
632
+ NSArray* urls = [pasteboard readObjectsForClasses:@[[NSURL class]]
633
+ options:options];
634
+ const NSUInteger count = [urls count];
635
+ if (count)
636
+ {
637
+ char** paths = _glfw_calloc(count, sizeof(char*));
638
+
639
+ for (NSUInteger i = 0; i < count; i++)
640
+ paths[i] = _glfw_strdup([urls[i] fileSystemRepresentation]);
641
+
642
+ _glfwInputDrop(window, (int) count, (const char**) paths);
643
+
644
+ for (NSUInteger i = 0; i < count; i++)
645
+ _glfw_free(paths[i]);
646
+ _glfw_free(paths);
647
+ }
648
+
649
+ return YES;
650
+ }
651
+
652
+ - (BOOL)hasMarkedText
653
+ {
654
+ return [markedText length] > 0;
655
+ }
656
+
657
+ - (NSRange)markedRange
658
+ {
659
+ if ([markedText length] > 0)
660
+ return NSMakeRange(0, [markedText length] - 1);
661
+ else
662
+ return kEmptyRange;
663
+ }
664
+
665
+ - (NSRange)selectedRange
666
+ {
667
+ return kEmptyRange;
668
+ }
669
+
670
+ - (void)setMarkedText:(id)string
671
+ selectedRange:(NSRange)selectedRange
672
+ replacementRange:(NSRange)replacementRange
673
+ {
674
+ [markedText release];
675
+ if ([string isKindOfClass:[NSAttributedString class]])
676
+ markedText = [[NSMutableAttributedString alloc] initWithAttributedString:string];
677
+ else
678
+ markedText = [[NSMutableAttributedString alloc] initWithString:string];
679
+ }
680
+
681
+ - (void)unmarkText
682
+ {
683
+ [[markedText mutableString] setString:@""];
684
+ }
685
+
686
+ - (NSArray*)validAttributesForMarkedText
687
+ {
688
+ return [NSArray array];
689
+ }
690
+
691
+ - (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range
692
+ actualRange:(NSRangePointer)actualRange
693
+ {
694
+ return nil;
695
+ }
696
+
697
+ - (NSUInteger)characterIndexForPoint:(NSPoint)point
698
+ {
699
+ return 0;
700
+ }
701
+
702
+ - (NSRect)firstRectForCharacterRange:(NSRange)range
703
+ actualRange:(NSRangePointer)actualRange
704
+ {
705
+ const NSRect frame = [window->ns.view frame];
706
+ return NSMakeRect(frame.origin.x, frame.origin.y, 0.0, 0.0);
707
+ }
708
+
709
+ - (void)insertText:(id)string replacementRange:(NSRange)replacementRange
710
+ {
711
+ NSString* characters;
712
+ NSEvent* event = [NSApp currentEvent];
713
+ const int mods = translateFlags([event modifierFlags]);
714
+ const int plain = !(mods & GLFW_MOD_SUPER);
715
+
716
+ if ([string isKindOfClass:[NSAttributedString class]])
717
+ characters = [string string];
718
+ else
719
+ characters = (NSString*) string;
720
+
721
+ NSRange range = NSMakeRange(0, [characters length]);
722
+ while (range.length)
723
+ {
724
+ uint32_t codepoint = 0;
725
+
726
+ if ([characters getBytes:&codepoint
727
+ maxLength:sizeof(codepoint)
728
+ usedLength:NULL
729
+ encoding:NSUTF32StringEncoding
730
+ options:0
731
+ range:range
732
+ remainingRange:&range])
733
+ {
734
+ if (codepoint >= 0xf700 && codepoint <= 0xf7ff)
735
+ continue;
736
+
737
+ _glfwInputChar(window, codepoint, mods, plain);
738
+ }
739
+ }
740
+ }
741
+
742
+ - (void)doCommandBySelector:(SEL)selector
743
+ {
744
+ }
745
+
746
+ @end
747
+
748
+
749
+ //------------------------------------------------------------------------
750
+ // GLFW window class
751
+ //------------------------------------------------------------------------
752
+
753
+ @interface GLFWWindow : NSWindow {}
754
+ @end
755
+
756
+ @implementation GLFWWindow
757
+
758
+ - (BOOL)canBecomeKeyWindow
759
+ {
760
+ // Required for NSWindowStyleMaskBorderless windows
761
+ return YES;
762
+ }
763
+
764
+ - (BOOL)canBecomeMainWindow
765
+ {
766
+ return YES;
767
+ }
768
+
769
+ @end
770
+
771
+
772
+ // Create the Cocoa window
773
+ //
774
+ static GLFWbool createNativeWindow(_GLFWwindow* window,
775
+ const _GLFWwndconfig* wndconfig,
776
+ const _GLFWfbconfig* fbconfig)
777
+ {
778
+ window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window];
779
+ if (window->ns.delegate == nil)
780
+ {
781
+ _glfwInputError(GLFW_PLATFORM_ERROR,
782
+ "Cocoa: Failed to create window delegate");
783
+ return GLFW_FALSE;
784
+ }
785
+
786
+ NSRect contentRect;
787
+
788
+ if (window->monitor)
789
+ {
790
+ GLFWvidmode mode;
791
+ int xpos, ypos;
792
+
793
+ _glfwGetVideoModeCocoa(window->monitor, &mode);
794
+ _glfwGetMonitorPosCocoa(window->monitor, &xpos, &ypos);
795
+
796
+ contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height);
797
+ }
798
+ else
799
+ {
800
+ if (wndconfig->xpos == GLFW_ANY_POSITION ||
801
+ wndconfig->ypos == GLFW_ANY_POSITION)
802
+ {
803
+ contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
804
+ }
805
+ else
806
+ {
807
+ const int xpos = wndconfig->xpos;
808
+ const int ypos = _glfwTransformYCocoa(wndconfig->ypos + wndconfig->height - 1);
809
+ contentRect = NSMakeRect(xpos, ypos, wndconfig->width, wndconfig->height);
810
+ }
811
+ }
812
+
813
+ NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
814
+
815
+ if (window->monitor || !window->decorated)
816
+ styleMask |= NSWindowStyleMaskBorderless;
817
+ else
818
+ {
819
+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
820
+
821
+ if (window->resizable)
822
+ styleMask |= NSWindowStyleMaskResizable;
823
+ }
824
+
825
+ window->ns.object = [[GLFWWindow alloc]
826
+ initWithContentRect:contentRect
827
+ styleMask:styleMask
828
+ backing:NSBackingStoreBuffered
829
+ defer:NO];
830
+
831
+ if (window->ns.object == nil)
832
+ {
833
+ _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to create window");
834
+ return GLFW_FALSE;
835
+ }
836
+
837
+ if (window->monitor)
838
+ [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
839
+ else
840
+ {
841
+ if (wndconfig->xpos == GLFW_ANY_POSITION ||
842
+ wndconfig->ypos == GLFW_ANY_POSITION)
843
+ {
844
+ [(NSWindow*) window->ns.object center];
845
+ _glfw.ns.cascadePoint =
846
+ NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
847
+ NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
848
+ }
849
+
850
+ if (wndconfig->resizable)
851
+ {
852
+ const NSWindowCollectionBehavior behavior =
853
+ NSWindowCollectionBehaviorFullScreenPrimary |
854
+ NSWindowCollectionBehaviorManaged;
855
+ [window->ns.object setCollectionBehavior:behavior];
856
+ }
857
+ else
858
+ {
859
+ const NSWindowCollectionBehavior behavior =
860
+ NSWindowCollectionBehaviorFullScreenNone;
861
+ [window->ns.object setCollectionBehavior:behavior];
862
+ }
863
+
864
+ if (wndconfig->floating)
865
+ [window->ns.object setLevel:NSFloatingWindowLevel];
866
+
867
+ if (wndconfig->maximized)
868
+ [window->ns.object zoom:nil];
869
+ }
870
+
871
+ if (strlen(wndconfig->ns.frameName))
872
+ [window->ns.object setFrameAutosaveName:@(wndconfig->ns.frameName)];
873
+
874
+ window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window];
875
+ window->ns.scaleFramebuffer = wndconfig->scaleFramebuffer;
876
+
877
+ if (fbconfig->transparent)
878
+ {
879
+ [window->ns.object setOpaque:NO];
880
+ [window->ns.object setHasShadow:NO];
881
+ [window->ns.object setBackgroundColor:[NSColor clearColor]];
882
+ }
883
+
884
+ [window->ns.object setContentView:window->ns.view];
885
+ [window->ns.object makeFirstResponder:window->ns.view];
886
+ [window->ns.object setTitle:@(wndconfig->title)];
887
+ [window->ns.object setDelegate:window->ns.delegate];
888
+ [window->ns.object setAcceptsMouseMovedEvents:YES];
889
+ [window->ns.object setRestorable:NO];
890
+
891
+ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
892
+ if ([window->ns.object respondsToSelector:@selector(setTabbingMode:)])
893
+ [window->ns.object setTabbingMode:NSWindowTabbingModeDisallowed];
894
+ #endif
895
+
896
+ _glfwGetWindowSizeCocoa(window, &window->ns.width, &window->ns.height);
897
+ _glfwGetFramebufferSizeCocoa(window, &window->ns.fbWidth, &window->ns.fbHeight);
898
+
899
+ return GLFW_TRUE;
900
+ }
901
+
902
+
903
+ //////////////////////////////////////////////////////////////////////////
904
+ ////// GLFW internal API //////
905
+ //////////////////////////////////////////////////////////////////////////
906
+
907
+ // Transforms a y-coordinate between the CG display and NS screen spaces
908
+ //
909
+ float _glfwTransformYCocoa(float y)
910
+ {
911
+ return CGDisplayBounds(CGMainDisplayID()).size.height - y - 1;
912
+ }
913
+
914
+
915
+ //////////////////////////////////////////////////////////////////////////
916
+ ////// GLFW platform API //////
917
+ //////////////////////////////////////////////////////////////////////////
918
+
919
+ GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window,
920
+ const _GLFWwndconfig* wndconfig,
921
+ const _GLFWctxconfig* ctxconfig,
922
+ const _GLFWfbconfig* fbconfig)
923
+ {
924
+ @autoreleasepool {
925
+
926
+ if (!createNativeWindow(window, wndconfig, fbconfig))
927
+ return GLFW_FALSE;
928
+
929
+ if (ctxconfig->client != GLFW_NO_API)
930
+ {
931
+ if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
932
+ {
933
+ if (!_glfwInitNSGL())
934
+ return GLFW_FALSE;
935
+ if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig))
936
+ return GLFW_FALSE;
937
+ }
938
+ else if (ctxconfig->source == GLFW_EGL_CONTEXT_API)
939
+ {
940
+ // EGL implementation on macOS use CALayer* EGLNativeWindowType so we
941
+ // need to get the layer for EGL window surface creation.
942
+ [window->ns.view setWantsLayer:YES];
943
+ window->ns.layer = [window->ns.view layer];
944
+
945
+ if (!_glfwInitEGL())
946
+ return GLFW_FALSE;
947
+ if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
948
+ return GLFW_FALSE;
949
+ }
950
+ else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
951
+ {
952
+ if (!_glfwInitOSMesa())
953
+ return GLFW_FALSE;
954
+ if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
955
+ return GLFW_FALSE;
956
+ }
957
+
958
+ if (!_glfwRefreshContextAttribs(window, ctxconfig))
959
+ return GLFW_FALSE;
960
+ }
961
+
962
+ if (wndconfig->mousePassthrough)
963
+ _glfwSetWindowMousePassthroughCocoa(window, GLFW_TRUE);
964
+
965
+ if (window->monitor)
966
+ {
967
+ _glfwShowWindowCocoa(window);
968
+ _glfwFocusWindowCocoa(window);
969
+ acquireMonitor(window);
970
+
971
+ if (wndconfig->centerCursor)
972
+ _glfwCenterCursorInContentArea(window);
973
+ }
974
+ else
975
+ {
976
+ if (wndconfig->visible)
977
+ {
978
+ _glfwShowWindowCocoa(window);
979
+ if (wndconfig->focused)
980
+ _glfwFocusWindowCocoa(window);
981
+ }
982
+ }
983
+
984
+ return GLFW_TRUE;
985
+
986
+ } // autoreleasepool
987
+ }
988
+
989
+ void _glfwDestroyWindowCocoa(_GLFWwindow* window)
990
+ {
991
+ @autoreleasepool {
992
+
993
+ if (_glfw.ns.disabledCursorWindow == window)
994
+ _glfw.ns.disabledCursorWindow = NULL;
995
+
996
+ [window->ns.object orderOut:nil];
997
+
998
+ if (window->monitor)
999
+ releaseMonitor(window);
1000
+
1001
+ if (window->context.destroy)
1002
+ window->context.destroy(window);
1003
+
1004
+ [window->ns.object setDelegate:nil];
1005
+ [window->ns.delegate release];
1006
+ window->ns.delegate = nil;
1007
+
1008
+ [window->ns.view release];
1009
+ window->ns.view = nil;
1010
+
1011
+ [window->ns.object close];
1012
+ window->ns.object = nil;
1013
+
1014
+ // HACK: Allow Cocoa to catch up before returning
1015
+ _glfwPollEventsCocoa();
1016
+
1017
+ } // autoreleasepool
1018
+ }
1019
+
1020
+ void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title)
1021
+ {
1022
+ @autoreleasepool {
1023
+ NSString* string = @(title);
1024
+ [window->ns.object setTitle:string];
1025
+ // HACK: Set the miniwindow title explicitly as setTitle: doesn't update it
1026
+ // if the window lacks NSWindowStyleMaskTitled
1027
+ [window->ns.object setMiniwindowTitle:string];
1028
+ } // autoreleasepool
1029
+ }
1030
+
1031
+ void _glfwSetWindowIconCocoa(_GLFWwindow* window,
1032
+ int count, const GLFWimage* images)
1033
+ {
1034
+ _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
1035
+ "Cocoa: Regular windows do not have icons on macOS");
1036
+ }
1037
+
1038
+ void _glfwGetWindowPosCocoa(_GLFWwindow* window, int* xpos, int* ypos)
1039
+ {
1040
+ @autoreleasepool {
1041
+
1042
+ const NSRect contentRect =
1043
+ [window->ns.object contentRectForFrameRect:[window->ns.object frame]];
1044
+
1045
+ if (xpos)
1046
+ *xpos = contentRect.origin.x;
1047
+ if (ypos)
1048
+ *ypos = _glfwTransformYCocoa(contentRect.origin.y + contentRect.size.height - 1);
1049
+
1050
+ } // autoreleasepool
1051
+ }
1052
+
1053
+ void _glfwSetWindowPosCocoa(_GLFWwindow* window, int x, int y)
1054
+ {
1055
+ @autoreleasepool {
1056
+
1057
+ const NSRect contentRect = [window->ns.view frame];
1058
+ const NSRect dummyRect = NSMakeRect(x, _glfwTransformYCocoa(y + contentRect.size.height - 1), 0, 0);
1059
+ const NSRect frameRect = [window->ns.object frameRectForContentRect:dummyRect];
1060
+ [window->ns.object setFrameOrigin:frameRect.origin];
1061
+
1062
+ } // autoreleasepool
1063
+ }
1064
+
1065
+ void _glfwGetWindowSizeCocoa(_GLFWwindow* window, int* width, int* height)
1066
+ {
1067
+ @autoreleasepool {
1068
+
1069
+ const NSRect contentRect = [window->ns.view frame];
1070
+
1071
+ if (width)
1072
+ *width = contentRect.size.width;
1073
+ if (height)
1074
+ *height = contentRect.size.height;
1075
+
1076
+ } // autoreleasepool
1077
+ }
1078
+
1079
+ void _glfwSetWindowSizeCocoa(_GLFWwindow* window, int width, int height)
1080
+ {
1081
+ @autoreleasepool {
1082
+
1083
+ if (window->monitor)
1084
+ {
1085
+ if (window->monitor->window == window)
1086
+ acquireMonitor(window);
1087
+ }
1088
+ else
1089
+ {
1090
+ NSRect contentRect =
1091
+ [window->ns.object contentRectForFrameRect:[window->ns.object frame]];
1092
+ contentRect.origin.y += contentRect.size.height - height;
1093
+ contentRect.size = NSMakeSize(width, height);
1094
+ [window->ns.object setFrame:[window->ns.object frameRectForContentRect:contentRect]
1095
+ display:YES];
1096
+ }
1097
+
1098
+ } // autoreleasepool
1099
+ }
1100
+
1101
+ void _glfwSetWindowSizeLimitsCocoa(_GLFWwindow* window,
1102
+ int minwidth, int minheight,
1103
+ int maxwidth, int maxheight)
1104
+ {
1105
+ @autoreleasepool {
1106
+
1107
+ if (minwidth == GLFW_DONT_CARE || minheight == GLFW_DONT_CARE)
1108
+ [window->ns.object setContentMinSize:NSMakeSize(0, 0)];
1109
+ else
1110
+ [window->ns.object setContentMinSize:NSMakeSize(minwidth, minheight)];
1111
+
1112
+ if (maxwidth == GLFW_DONT_CARE || maxheight == GLFW_DONT_CARE)
1113
+ [window->ns.object setContentMaxSize:NSMakeSize(DBL_MAX, DBL_MAX)];
1114
+ else
1115
+ [window->ns.object setContentMaxSize:NSMakeSize(maxwidth, maxheight)];
1116
+
1117
+ } // autoreleasepool
1118
+ }
1119
+
1120
+ void _glfwSetWindowAspectRatioCocoa(_GLFWwindow* window, int numer, int denom)
1121
+ {
1122
+ @autoreleasepool {
1123
+ if (numer == GLFW_DONT_CARE || denom == GLFW_DONT_CARE)
1124
+ [window->ns.object setResizeIncrements:NSMakeSize(1.0, 1.0)];
1125
+ else
1126
+ [window->ns.object setContentAspectRatio:NSMakeSize(numer, denom)];
1127
+ } // autoreleasepool
1128
+ }
1129
+
1130
+ void _glfwGetFramebufferSizeCocoa(_GLFWwindow* window, int* width, int* height)
1131
+ {
1132
+ @autoreleasepool {
1133
+
1134
+ const NSRect contentRect = [window->ns.view frame];
1135
+ const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect];
1136
+
1137
+ if (width)
1138
+ *width = (int) fbRect.size.width;
1139
+ if (height)
1140
+ *height = (int) fbRect.size.height;
1141
+
1142
+ } // autoreleasepool
1143
+ }
1144
+
1145
+ void _glfwGetWindowFrameSizeCocoa(_GLFWwindow* window,
1146
+ int* left, int* top,
1147
+ int* right, int* bottom)
1148
+ {
1149
+ @autoreleasepool {
1150
+
1151
+ const NSRect contentRect = [window->ns.view frame];
1152
+ const NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect];
1153
+
1154
+ if (left)
1155
+ *left = contentRect.origin.x - frameRect.origin.x;
1156
+ if (top)
1157
+ *top = frameRect.origin.y + frameRect.size.height -
1158
+ contentRect.origin.y - contentRect.size.height;
1159
+ if (right)
1160
+ *right = frameRect.origin.x + frameRect.size.width -
1161
+ contentRect.origin.x - contentRect.size.width;
1162
+ if (bottom)
1163
+ *bottom = contentRect.origin.y - frameRect.origin.y;
1164
+
1165
+ } // autoreleasepool
1166
+ }
1167
+
1168
+ void _glfwGetWindowContentScaleCocoa(_GLFWwindow* window,
1169
+ float* xscale, float* yscale)
1170
+ {
1171
+ @autoreleasepool {
1172
+
1173
+ const NSRect points = [window->ns.view frame];
1174
+ const NSRect pixels = [window->ns.view convertRectToBacking:points];
1175
+
1176
+ if (xscale)
1177
+ *xscale = (float) (pixels.size.width / points.size.width);
1178
+ if (yscale)
1179
+ *yscale = (float) (pixels.size.height / points.size.height);
1180
+
1181
+ } // autoreleasepool
1182
+ }
1183
+
1184
+ void _glfwIconifyWindowCocoa(_GLFWwindow* window)
1185
+ {
1186
+ @autoreleasepool {
1187
+ [window->ns.object miniaturize:nil];
1188
+ } // autoreleasepool
1189
+ }
1190
+
1191
+ void _glfwRestoreWindowCocoa(_GLFWwindow* window)
1192
+ {
1193
+ @autoreleasepool {
1194
+ if ([window->ns.object isMiniaturized])
1195
+ [window->ns.object deminiaturize:nil];
1196
+ else if ([window->ns.object isZoomed])
1197
+ [window->ns.object zoom:nil];
1198
+ } // autoreleasepool
1199
+ }
1200
+
1201
+ void _glfwMaximizeWindowCocoa(_GLFWwindow* window)
1202
+ {
1203
+ @autoreleasepool {
1204
+ if (![window->ns.object isZoomed])
1205
+ [window->ns.object zoom:nil];
1206
+ } // autoreleasepool
1207
+ }
1208
+
1209
+ void _glfwShowWindowCocoa(_GLFWwindow* window)
1210
+ {
1211
+ @autoreleasepool {
1212
+ [window->ns.object orderFront:nil];
1213
+ } // autoreleasepool
1214
+ }
1215
+
1216
+ void _glfwHideWindowCocoa(_GLFWwindow* window)
1217
+ {
1218
+ @autoreleasepool {
1219
+ [window->ns.object orderOut:nil];
1220
+ } // autoreleasepool
1221
+ }
1222
+
1223
+ void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window)
1224
+ {
1225
+ @autoreleasepool {
1226
+ [NSApp requestUserAttention:NSInformationalRequest];
1227
+ } // autoreleasepool
1228
+ }
1229
+
1230
+ void _glfwFocusWindowCocoa(_GLFWwindow* window)
1231
+ {
1232
+ @autoreleasepool {
1233
+ // Make us the active application
1234
+ // HACK: This is here to prevent applications using only hidden windows from
1235
+ // being activated, but should probably not be done every time any
1236
+ // window is shown
1237
+ [NSApp activateIgnoringOtherApps:YES];
1238
+ [window->ns.object makeKeyAndOrderFront:nil];
1239
+ } // autoreleasepool
1240
+ }
1241
+
1242
+ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window,
1243
+ _GLFWmonitor* monitor,
1244
+ int xpos, int ypos,
1245
+ int width, int height,
1246
+ int refreshRate)
1247
+ {
1248
+ @autoreleasepool {
1249
+
1250
+ if (window->monitor == monitor)
1251
+ {
1252
+ if (monitor)
1253
+ {
1254
+ if (monitor->window == window)
1255
+ acquireMonitor(window);
1256
+ }
1257
+ else
1258
+ {
1259
+ const NSRect contentRect =
1260
+ NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), width, height);
1261
+ const NSUInteger styleMask = [window->ns.object styleMask];
1262
+ const NSRect frameRect =
1263
+ [window->ns.object frameRectForContentRect:contentRect
1264
+ styleMask:styleMask];
1265
+
1266
+ [window->ns.object setFrame:frameRect display:YES];
1267
+ }
1268
+
1269
+ return;
1270
+ }
1271
+
1272
+ if (window->monitor)
1273
+ releaseMonitor(window);
1274
+
1275
+ _glfwInputWindowMonitor(window, monitor);
1276
+
1277
+ // HACK: Allow the state cached in Cocoa to catch up to reality
1278
+ // TODO: Solve this in a less terrible way
1279
+ _glfwPollEventsCocoa();
1280
+
1281
+ NSUInteger styleMask = [window->ns.object styleMask];
1282
+
1283
+ if (window->monitor)
1284
+ {
1285
+ styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable);
1286
+ styleMask |= NSWindowStyleMaskBorderless;
1287
+ }
1288
+ else
1289
+ {
1290
+ if (window->decorated)
1291
+ {
1292
+ styleMask &= ~NSWindowStyleMaskBorderless;
1293
+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
1294
+ }
1295
+
1296
+ if (window->resizable)
1297
+ styleMask |= NSWindowStyleMaskResizable;
1298
+ else
1299
+ styleMask &= ~NSWindowStyleMaskResizable;
1300
+ }
1301
+
1302
+ [window->ns.object setStyleMask:styleMask];
1303
+ // HACK: Changing the style mask can cause the first responder to be cleared
1304
+ [window->ns.object makeFirstResponder:window->ns.view];
1305
+
1306
+ if (window->monitor)
1307
+ {
1308
+ [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
1309
+ [window->ns.object setHasShadow:NO];
1310
+
1311
+ acquireMonitor(window);
1312
+ }
1313
+ else
1314
+ {
1315
+ NSRect contentRect = NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1),
1316
+ width, height);
1317
+ NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect
1318
+ styleMask:styleMask];
1319
+ [window->ns.object setFrame:frameRect display:YES];
1320
+
1321
+ if (window->numer != GLFW_DONT_CARE &&
1322
+ window->denom != GLFW_DONT_CARE)
1323
+ {
1324
+ [window->ns.object setContentAspectRatio:NSMakeSize(window->numer,
1325
+ window->denom)];
1326
+ }
1327
+
1328
+ if (window->minwidth != GLFW_DONT_CARE &&
1329
+ window->minheight != GLFW_DONT_CARE)
1330
+ {
1331
+ [window->ns.object setContentMinSize:NSMakeSize(window->minwidth,
1332
+ window->minheight)];
1333
+ }
1334
+
1335
+ if (window->maxwidth != GLFW_DONT_CARE &&
1336
+ window->maxheight != GLFW_DONT_CARE)
1337
+ {
1338
+ [window->ns.object setContentMaxSize:NSMakeSize(window->maxwidth,
1339
+ window->maxheight)];
1340
+ }
1341
+
1342
+ if (window->floating)
1343
+ [window->ns.object setLevel:NSFloatingWindowLevel];
1344
+ else
1345
+ [window->ns.object setLevel:NSNormalWindowLevel];
1346
+
1347
+ if (window->resizable)
1348
+ {
1349
+ const NSWindowCollectionBehavior behavior =
1350
+ NSWindowCollectionBehaviorFullScreenPrimary |
1351
+ NSWindowCollectionBehaviorManaged;
1352
+ [window->ns.object setCollectionBehavior:behavior];
1353
+ }
1354
+ else
1355
+ {
1356
+ const NSWindowCollectionBehavior behavior =
1357
+ NSWindowCollectionBehaviorFullScreenNone;
1358
+ [window->ns.object setCollectionBehavior:behavior];
1359
+ }
1360
+
1361
+ [window->ns.object setHasShadow:YES];
1362
+ // HACK: Clearing NSWindowStyleMaskTitled resets and disables the window
1363
+ // title property but the miniwindow title property is unaffected
1364
+ [window->ns.object setTitle:[window->ns.object miniwindowTitle]];
1365
+ }
1366
+
1367
+ } // autoreleasepool
1368
+ }
1369
+
1370
+ GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window)
1371
+ {
1372
+ @autoreleasepool {
1373
+ return [window->ns.object isKeyWindow];
1374
+ } // autoreleasepool
1375
+ }
1376
+
1377
+ GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window)
1378
+ {
1379
+ @autoreleasepool {
1380
+ return [window->ns.object isMiniaturized];
1381
+ } // autoreleasepool
1382
+ }
1383
+
1384
+ GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window)
1385
+ {
1386
+ @autoreleasepool {
1387
+ return [window->ns.object isVisible];
1388
+ } // autoreleasepool
1389
+ }
1390
+
1391
+ GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window)
1392
+ {
1393
+ @autoreleasepool {
1394
+
1395
+ if (window->resizable)
1396
+ return [window->ns.object isZoomed];
1397
+ else
1398
+ return GLFW_FALSE;
1399
+
1400
+ } // autoreleasepool
1401
+ }
1402
+
1403
+ GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window)
1404
+ {
1405
+ @autoreleasepool {
1406
+
1407
+ const NSPoint point = [NSEvent mouseLocation];
1408
+
1409
+ if ([NSWindow windowNumberAtPoint:point belowWindowWithWindowNumber:0] !=
1410
+ [window->ns.object windowNumber])
1411
+ {
1412
+ return GLFW_FALSE;
1413
+ }
1414
+
1415
+ return NSMouseInRect(point,
1416
+ [window->ns.object convertRectToScreen:[window->ns.view frame]], NO);
1417
+
1418
+ } // autoreleasepool
1419
+ }
1420
+
1421
+ GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window)
1422
+ {
1423
+ @autoreleasepool {
1424
+ return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
1425
+ } // autoreleasepool
1426
+ }
1427
+
1428
+ void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled)
1429
+ {
1430
+ @autoreleasepool {
1431
+
1432
+ const NSUInteger styleMask = [window->ns.object styleMask];
1433
+ if (enabled)
1434
+ {
1435
+ [window->ns.object setStyleMask:(styleMask | NSWindowStyleMaskResizable)];
1436
+ const NSWindowCollectionBehavior behavior =
1437
+ NSWindowCollectionBehaviorFullScreenPrimary |
1438
+ NSWindowCollectionBehaviorManaged;
1439
+ [window->ns.object setCollectionBehavior:behavior];
1440
+ }
1441
+ else
1442
+ {
1443
+ [window->ns.object setStyleMask:(styleMask & ~NSWindowStyleMaskResizable)];
1444
+ const NSWindowCollectionBehavior behavior =
1445
+ NSWindowCollectionBehaviorFullScreenNone;
1446
+ [window->ns.object setCollectionBehavior:behavior];
1447
+ }
1448
+
1449
+ } // autoreleasepool
1450
+ }
1451
+
1452
+ void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled)
1453
+ {
1454
+ @autoreleasepool {
1455
+
1456
+ NSUInteger styleMask = [window->ns.object styleMask];
1457
+ if (enabled)
1458
+ {
1459
+ styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
1460
+ styleMask &= ~NSWindowStyleMaskBorderless;
1461
+ }
1462
+ else
1463
+ {
1464
+ styleMask |= NSWindowStyleMaskBorderless;
1465
+ styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
1466
+ }
1467
+
1468
+ [window->ns.object setStyleMask:styleMask];
1469
+ [window->ns.object makeFirstResponder:window->ns.view];
1470
+
1471
+ } // autoreleasepool
1472
+ }
1473
+
1474
+ void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled)
1475
+ {
1476
+ @autoreleasepool {
1477
+ if (enabled)
1478
+ [window->ns.object setLevel:NSFloatingWindowLevel];
1479
+ else
1480
+ [window->ns.object setLevel:NSNormalWindowLevel];
1481
+ } // autoreleasepool
1482
+ }
1483
+
1484
+ void _glfwSetWindowMousePassthroughCocoa(_GLFWwindow* window, GLFWbool enabled)
1485
+ {
1486
+ @autoreleasepool {
1487
+ [window->ns.object setIgnoresMouseEvents:enabled];
1488
+ }
1489
+ }
1490
+
1491
+ float _glfwGetWindowOpacityCocoa(_GLFWwindow* window)
1492
+ {
1493
+ @autoreleasepool {
1494
+ return (float) [window->ns.object alphaValue];
1495
+ } // autoreleasepool
1496
+ }
1497
+
1498
+ void _glfwSetWindowOpacityCocoa(_GLFWwindow* window, float opacity)
1499
+ {
1500
+ @autoreleasepool {
1501
+ [window->ns.object setAlphaValue:opacity];
1502
+ } // autoreleasepool
1503
+ }
1504
+
1505
+ void _glfwSetRawMouseMotionCocoa(_GLFWwindow *window, GLFWbool enabled)
1506
+ {
1507
+ _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
1508
+ "Cocoa: Raw mouse motion not yet implemented");
1509
+ }
1510
+
1511
+ GLFWbool _glfwRawMouseMotionSupportedCocoa(void)
1512
+ {
1513
+ return GLFW_FALSE;
1514
+ }
1515
+
1516
+ void _glfwPollEventsCocoa(void)
1517
+ {
1518
+ @autoreleasepool {
1519
+
1520
+ for (;;)
1521
+ {
1522
+ NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
1523
+ untilDate:[NSDate distantPast]
1524
+ inMode:NSDefaultRunLoopMode
1525
+ dequeue:YES];
1526
+ if (event == nil)
1527
+ break;
1528
+
1529
+ [NSApp sendEvent:event];
1530
+ }
1531
+
1532
+ } // autoreleasepool
1533
+ }
1534
+
1535
+ void _glfwWaitEventsCocoa(void)
1536
+ {
1537
+ @autoreleasepool {
1538
+
1539
+ // I wanted to pass NO to dequeue:, and rely on PollEvents to
1540
+ // dequeue and send. For reasons not at all clear to me, passing
1541
+ // NO to dequeue: causes this method never to return.
1542
+ NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny
1543
+ untilDate:[NSDate distantFuture]
1544
+ inMode:NSDefaultRunLoopMode
1545
+ dequeue:YES];
1546
+ [NSApp sendEvent:event];
1547
+
1548
+ _glfwPollEventsCocoa();
1549
+
1550
+ } // autoreleasepool
1551
+ }
1552
+
1553
+ void _glfwWaitEventsTimeoutCocoa(double timeout)
1554
+ {
1555
+ @autoreleasepool {
1556
+
1557
+ NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
1558
+ NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
1559
+ untilDate:date
1560
+ inMode:NSDefaultRunLoopMode
1561
+ dequeue:YES];
1562
+ if (event)
1563
+ [NSApp sendEvent:event];
1564
+
1565
+ _glfwPollEventsCocoa();
1566
+
1567
+ } // autoreleasepool
1568
+ }
1569
+
1570
+ void _glfwPostEmptyEventCocoa(void)
1571
+ {
1572
+ @autoreleasepool {
1573
+
1574
+ NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
1575
+ location:NSMakePoint(0, 0)
1576
+ modifierFlags:0
1577
+ timestamp:0
1578
+ windowNumber:0
1579
+ context:nil
1580
+ subtype:0
1581
+ data1:0
1582
+ data2:0];
1583
+ [NSApp postEvent:event atStart:YES];
1584
+
1585
+ } // autoreleasepool
1586
+ }
1587
+
1588
+ void _glfwGetCursorPosCocoa(_GLFWwindow* window, double* xpos, double* ypos)
1589
+ {
1590
+ @autoreleasepool {
1591
+
1592
+ const NSRect contentRect = [window->ns.view frame];
1593
+ // NOTE: The returned location uses base 0,1 not 0,0
1594
+ const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
1595
+
1596
+ if (xpos)
1597
+ *xpos = pos.x;
1598
+ if (ypos)
1599
+ *ypos = contentRect.size.height - pos.y;
1600
+
1601
+ } // autoreleasepool
1602
+ }
1603
+
1604
+ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y)
1605
+ {
1606
+ @autoreleasepool {
1607
+
1608
+ updateCursorImage(window);
1609
+
1610
+ const NSRect contentRect = [window->ns.view frame];
1611
+ // NOTE: The returned location uses base 0,1 not 0,0
1612
+ const NSPoint pos = [window->ns.object mouseLocationOutsideOfEventStream];
1613
+
1614
+ window->ns.cursorWarpDeltaX += x - pos.x;
1615
+ window->ns.cursorWarpDeltaY += y - contentRect.size.height + pos.y;
1616
+
1617
+ if (window->monitor)
1618
+ {
1619
+ CGDisplayMoveCursorToPoint(window->monitor->ns.displayID,
1620
+ CGPointMake(x, y));
1621
+ }
1622
+ else
1623
+ {
1624
+ const NSRect localRect = NSMakeRect(x, contentRect.size.height - y - 1, 0, 0);
1625
+ const NSRect globalRect = [window->ns.object convertRectToScreen:localRect];
1626
+ const NSPoint globalPoint = globalRect.origin;
1627
+
1628
+ CGWarpMouseCursorPosition(CGPointMake(globalPoint.x,
1629
+ _glfwTransformYCocoa(globalPoint.y)));
1630
+ }
1631
+
1632
+ // HACK: Calling this right after setting the cursor position prevents macOS
1633
+ // from freezing the cursor for a fraction of a second afterwards
1634
+ if (window->cursorMode != GLFW_CURSOR_DISABLED)
1635
+ CGAssociateMouseAndMouseCursorPosition(true);
1636
+
1637
+ } // autoreleasepool
1638
+ }
1639
+
1640
+ void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode)
1641
+ {
1642
+ @autoreleasepool {
1643
+
1644
+ if (mode == GLFW_CURSOR_CAPTURED)
1645
+ {
1646
+ _glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
1647
+ "Cocoa: Captured cursor mode not yet implemented");
1648
+ }
1649
+
1650
+ if (_glfwWindowFocusedCocoa(window))
1651
+ updateCursorMode(window);
1652
+
1653
+ } // autoreleasepool
1654
+ }
1655
+
1656
+ const char* _glfwGetScancodeNameCocoa(int scancode)
1657
+ {
1658
+ @autoreleasepool {
1659
+
1660
+ if (scancode < 0 || scancode > 0xff)
1661
+ {
1662
+ _glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
1663
+ return NULL;
1664
+ }
1665
+
1666
+ const int key = _glfw.ns.keycodes[scancode];
1667
+ if (key == GLFW_KEY_UNKNOWN)
1668
+ return NULL;
1669
+
1670
+ UInt32 deadKeyState = 0;
1671
+ UniChar characters[4];
1672
+ UniCharCount characterCount = 0;
1673
+
1674
+ if (UCKeyTranslate([(NSData*) _glfw.ns.unicodeData bytes],
1675
+ scancode,
1676
+ kUCKeyActionDisplay,
1677
+ 0,
1678
+ LMGetKbdType(),
1679
+ kUCKeyTranslateNoDeadKeysBit,
1680
+ &deadKeyState,
1681
+ sizeof(characters) / sizeof(characters[0]),
1682
+ &characterCount,
1683
+ characters) != noErr)
1684
+ {
1685
+ return NULL;
1686
+ }
1687
+
1688
+ if (!characterCount)
1689
+ return NULL;
1690
+
1691
+ CFStringRef string = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault,
1692
+ characters,
1693
+ characterCount,
1694
+ kCFAllocatorNull);
1695
+ CFStringGetCString(string,
1696
+ _glfw.ns.keynames[key],
1697
+ sizeof(_glfw.ns.keynames[key]),
1698
+ kCFStringEncodingUTF8);
1699
+ CFRelease(string);
1700
+
1701
+ return _glfw.ns.keynames[key];
1702
+
1703
+ } // autoreleasepool
1704
+ }
1705
+
1706
+ int _glfwGetKeyScancodeCocoa(int key)
1707
+ {
1708
+ return _glfw.ns.scancodes[key];
1709
+ }
1710
+
1711
+ GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor,
1712
+ const GLFWimage* image,
1713
+ int xhot, int yhot)
1714
+ {
1715
+ @autoreleasepool {
1716
+
1717
+ NSImage* native;
1718
+ NSBitmapImageRep* rep;
1719
+
1720
+ rep = [[NSBitmapImageRep alloc]
1721
+ initWithBitmapDataPlanes:NULL
1722
+ pixelsWide:image->width
1723
+ pixelsHigh:image->height
1724
+ bitsPerSample:8
1725
+ samplesPerPixel:4
1726
+ hasAlpha:YES
1727
+ isPlanar:NO
1728
+ colorSpaceName:NSCalibratedRGBColorSpace
1729
+ bitmapFormat:NSBitmapFormatAlphaNonpremultiplied
1730
+ bytesPerRow:image->width * 4
1731
+ bitsPerPixel:32];
1732
+
1733
+ if (rep == nil)
1734
+ return GLFW_FALSE;
1735
+
1736
+ memcpy([rep bitmapData], image->pixels, image->width * image->height * 4);
1737
+
1738
+ native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)];
1739
+ [native addRepresentation:rep];
1740
+
1741
+ cursor->ns.object = [[NSCursor alloc] initWithImage:native
1742
+ hotSpot:NSMakePoint(xhot, yhot)];
1743
+
1744
+ [native release];
1745
+ [rep release];
1746
+
1747
+ if (cursor->ns.object == nil)
1748
+ return GLFW_FALSE;
1749
+
1750
+ return GLFW_TRUE;
1751
+
1752
+ } // autoreleasepool
1753
+ }
1754
+
1755
+ GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape)
1756
+ {
1757
+ @autoreleasepool {
1758
+
1759
+ SEL cursorSelector = NULL;
1760
+
1761
+ // HACK: Try to use a private message
1762
+ switch (shape)
1763
+ {
1764
+ case GLFW_RESIZE_EW_CURSOR:
1765
+ cursorSelector = NSSelectorFromString(@"_windowResizeEastWestCursor");
1766
+ break;
1767
+ case GLFW_RESIZE_NS_CURSOR:
1768
+ cursorSelector = NSSelectorFromString(@"_windowResizeNorthSouthCursor");
1769
+ break;
1770
+ case GLFW_RESIZE_NWSE_CURSOR:
1771
+ cursorSelector = NSSelectorFromString(@"_windowResizeNorthWestSouthEastCursor");
1772
+ break;
1773
+ case GLFW_RESIZE_NESW_CURSOR:
1774
+ cursorSelector = NSSelectorFromString(@"_windowResizeNorthEastSouthWestCursor");
1775
+ break;
1776
+ }
1777
+
1778
+ if (cursorSelector && [NSCursor respondsToSelector:cursorSelector])
1779
+ {
1780
+ id object = [NSCursor performSelector:cursorSelector];
1781
+ if ([object isKindOfClass:[NSCursor class]])
1782
+ cursor->ns.object = object;
1783
+ }
1784
+
1785
+ if (!cursor->ns.object)
1786
+ {
1787
+ switch (shape)
1788
+ {
1789
+ case GLFW_ARROW_CURSOR:
1790
+ cursor->ns.object = [NSCursor arrowCursor];
1791
+ break;
1792
+ case GLFW_IBEAM_CURSOR:
1793
+ cursor->ns.object = [NSCursor IBeamCursor];
1794
+ break;
1795
+ case GLFW_CROSSHAIR_CURSOR:
1796
+ cursor->ns.object = [NSCursor crosshairCursor];
1797
+ break;
1798
+ case GLFW_POINTING_HAND_CURSOR:
1799
+ cursor->ns.object = [NSCursor pointingHandCursor];
1800
+ break;
1801
+ case GLFW_RESIZE_EW_CURSOR:
1802
+ cursor->ns.object = [NSCursor resizeLeftRightCursor];
1803
+ break;
1804
+ case GLFW_RESIZE_NS_CURSOR:
1805
+ cursor->ns.object = [NSCursor resizeUpDownCursor];
1806
+ break;
1807
+ case GLFW_RESIZE_ALL_CURSOR:
1808
+ cursor->ns.object = [NSCursor closedHandCursor];
1809
+ break;
1810
+ case GLFW_NOT_ALLOWED_CURSOR:
1811
+ cursor->ns.object = [NSCursor operationNotAllowedCursor];
1812
+ break;
1813
+ }
1814
+ }
1815
+
1816
+ if (!cursor->ns.object)
1817
+ {
1818
+ _glfwInputError(GLFW_CURSOR_UNAVAILABLE,
1819
+ "Cocoa: Standard cursor shape unavailable");
1820
+ return GLFW_FALSE;
1821
+ }
1822
+
1823
+ [cursor->ns.object retain];
1824
+ return GLFW_TRUE;
1825
+
1826
+ } // autoreleasepool
1827
+ }
1828
+
1829
+ void _glfwDestroyCursorCocoa(_GLFWcursor* cursor)
1830
+ {
1831
+ @autoreleasepool {
1832
+ if (cursor->ns.object)
1833
+ [(NSCursor*) cursor->ns.object release];
1834
+ } // autoreleasepool
1835
+ }
1836
+
1837
+ void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor)
1838
+ {
1839
+ @autoreleasepool {
1840
+ if (cursorInContentArea(window))
1841
+ updateCursorImage(window);
1842
+ } // autoreleasepool
1843
+ }
1844
+
1845
+ void _glfwSetClipboardStringCocoa(const char* string)
1846
+ {
1847
+ @autoreleasepool {
1848
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
1849
+ [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
1850
+ [pasteboard setString:@(string) forType:NSPasteboardTypeString];
1851
+ } // autoreleasepool
1852
+ }
1853
+
1854
+ const char* _glfwGetClipboardStringCocoa(void)
1855
+ {
1856
+ @autoreleasepool {
1857
+
1858
+ NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
1859
+
1860
+ if (![[pasteboard types] containsObject:NSPasteboardTypeString])
1861
+ {
1862
+ _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
1863
+ "Cocoa: Failed to retrieve string from pasteboard");
1864
+ return NULL;
1865
+ }
1866
+
1867
+ NSString* object = [pasteboard stringForType:NSPasteboardTypeString];
1868
+ if (!object)
1869
+ {
1870
+ _glfwInputError(GLFW_PLATFORM_ERROR,
1871
+ "Cocoa: Failed to retrieve object from pasteboard");
1872
+ return NULL;
1873
+ }
1874
+
1875
+ _glfw_free(_glfw.ns.clipboardString);
1876
+ _glfw.ns.clipboardString = _glfw_strdup([object UTF8String]);
1877
+
1878
+ return _glfw.ns.clipboardString;
1879
+
1880
+ } // autoreleasepool
1881
+ }
1882
+
1883
+ EGLenum _glfwGetEGLPlatformCocoa(EGLint** attribs)
1884
+ {
1885
+ if (_glfw.egl.ANGLE_platform_angle)
1886
+ {
1887
+ int type = 0;
1888
+
1889
+ if (_glfw.egl.ANGLE_platform_angle_opengl)
1890
+ {
1891
+ if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
1892
+ type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
1893
+ }
1894
+
1895
+ if (_glfw.egl.ANGLE_platform_angle_metal)
1896
+ {
1897
+ if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_METAL)
1898
+ type = EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE;
1899
+ }
1900
+
1901
+ if (type)
1902
+ {
1903
+ *attribs = _glfw_calloc(3, sizeof(EGLint));
1904
+ (*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
1905
+ (*attribs)[1] = type;
1906
+ (*attribs)[2] = EGL_NONE;
1907
+ return EGL_PLATFORM_ANGLE_ANGLE;
1908
+ }
1909
+ }
1910
+
1911
+ return 0;
1912
+ }
1913
+
1914
+ EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void)
1915
+ {
1916
+ return EGL_DEFAULT_DISPLAY;
1917
+ }
1918
+
1919
+ EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window)
1920
+ {
1921
+ return window->ns.layer;
1922
+ }
1923
+
1924
+ void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions)
1925
+ {
1926
+ if (_glfw.vk.KHR_surface && _glfw.vk.EXT_metal_surface)
1927
+ {
1928
+ extensions[0] = "VK_KHR_surface";
1929
+ extensions[1] = "VK_EXT_metal_surface";
1930
+ }
1931
+ else if (_glfw.vk.KHR_surface && _glfw.vk.MVK_macos_surface)
1932
+ {
1933
+ extensions[0] = "VK_KHR_surface";
1934
+ extensions[1] = "VK_MVK_macos_surface";
1935
+ }
1936
+ }
1937
+
1938
+ GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance,
1939
+ VkPhysicalDevice device,
1940
+ uint32_t queuefamily)
1941
+ {
1942
+ return GLFW_TRUE;
1943
+ }
1944
+
1945
+ VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance,
1946
+ _GLFWwindow* window,
1947
+ const VkAllocationCallbacks* allocator,
1948
+ VkSurfaceKHR* surface)
1949
+ {
1950
+ @autoreleasepool {
1951
+
1952
+ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101100
1953
+ // HACK: Dynamically load Core Animation to avoid adding an extra
1954
+ // dependency for the majority who don't use MoltenVK
1955
+ NSBundle* bundle = [NSBundle bundleWithPath:@"/System/Library/Frameworks/QuartzCore.framework"];
1956
+ if (!bundle)
1957
+ {
1958
+ _glfwInputError(GLFW_PLATFORM_ERROR,
1959
+ "Cocoa: Failed to find QuartzCore.framework");
1960
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
1961
+ }
1962
+
1963
+ // NOTE: Create the layer here as makeBackingLayer should not return nil
1964
+ window->ns.layer = [[bundle classNamed:@"CAMetalLayer"] layer];
1965
+ if (!window->ns.layer)
1966
+ {
1967
+ _glfwInputError(GLFW_PLATFORM_ERROR,
1968
+ "Cocoa: Failed to create layer for view");
1969
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
1970
+ }
1971
+
1972
+ if (window->ns.scaleFramebuffer)
1973
+ [window->ns.layer setContentsScale:[window->ns.object backingScaleFactor]];
1974
+
1975
+ [window->ns.view setLayer:window->ns.layer];
1976
+ [window->ns.view setWantsLayer:YES];
1977
+
1978
+ VkResult err;
1979
+
1980
+ if (_glfw.vk.EXT_metal_surface)
1981
+ {
1982
+ VkMetalSurfaceCreateInfoEXT sci;
1983
+
1984
+ PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT;
1985
+ vkCreateMetalSurfaceEXT = (PFN_vkCreateMetalSurfaceEXT)
1986
+ vkGetInstanceProcAddr(instance, "vkCreateMetalSurfaceEXT");
1987
+ if (!vkCreateMetalSurfaceEXT)
1988
+ {
1989
+ _glfwInputError(GLFW_API_UNAVAILABLE,
1990
+ "Cocoa: Vulkan instance missing VK_EXT_metal_surface extension");
1991
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
1992
+ }
1993
+
1994
+ memset(&sci, 0, sizeof(sci));
1995
+ sci.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
1996
+ sci.pLayer = window->ns.layer;
1997
+
1998
+ err = vkCreateMetalSurfaceEXT(instance, &sci, allocator, surface);
1999
+ }
2000
+ else
2001
+ {
2002
+ VkMacOSSurfaceCreateInfoMVK sci;
2003
+
2004
+ PFN_vkCreateMacOSSurfaceMVK vkCreateMacOSSurfaceMVK;
2005
+ vkCreateMacOSSurfaceMVK = (PFN_vkCreateMacOSSurfaceMVK)
2006
+ vkGetInstanceProcAddr(instance, "vkCreateMacOSSurfaceMVK");
2007
+ if (!vkCreateMacOSSurfaceMVK)
2008
+ {
2009
+ _glfwInputError(GLFW_API_UNAVAILABLE,
2010
+ "Cocoa: Vulkan instance missing VK_MVK_macos_surface extension");
2011
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
2012
+ }
2013
+
2014
+ memset(&sci, 0, sizeof(sci));
2015
+ sci.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
2016
+ sci.pView = window->ns.view;
2017
+
2018
+ err = vkCreateMacOSSurfaceMVK(instance, &sci, allocator, surface);
2019
+ }
2020
+
2021
+ if (err)
2022
+ {
2023
+ _glfwInputError(GLFW_PLATFORM_ERROR,
2024
+ "Cocoa: Failed to create Vulkan surface: %s",
2025
+ _glfwGetVulkanResultString(err));
2026
+ }
2027
+
2028
+ return err;
2029
+ #else
2030
+ return VK_ERROR_EXTENSION_NOT_PRESENT;
2031
+ #endif
2032
+
2033
+ } // autoreleasepool
2034
+ }
2035
+
2036
+
2037
+ //////////////////////////////////////////////////////////////////////////
2038
+ ////// GLFW native API //////
2039
+ //////////////////////////////////////////////////////////////////////////
2040
+
2041
+ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle)
2042
+ {
2043
+ _GLFWwindow* window = (_GLFWwindow*) handle;
2044
+ _GLFW_REQUIRE_INIT_OR_RETURN(nil);
2045
+
2046
+ if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
2047
+ {
2048
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
2049
+ "Cocoa: Platform not initialized");
2050
+ return nil;
2051
+ }
2052
+
2053
+ return window->ns.object;
2054
+ }
2055
+
2056
+ GLFWAPI id glfwGetCocoaView(GLFWwindow* handle)
2057
+ {
2058
+ _GLFWwindow* window = (_GLFWwindow*) handle;
2059
+ _GLFW_REQUIRE_INIT_OR_RETURN(nil);
2060
+
2061
+ if (_glfw.platform.platformID != GLFW_PLATFORM_COCOA)
2062
+ {
2063
+ _glfwInputError(GLFW_PLATFORM_UNAVAILABLE,
2064
+ "Cocoa: Platform not initialized");
2065
+ return nil;
2066
+ }
2067
+
2068
+ return window->ns.view;
2069
+ }
2070
+
2071
+ #endif // _GLFW_COCOA
2072
+