]> git.sesse.net Git - pistorm/blob - raylib_pi4_test/external/glfw/src/cocoa_init.m
Update raylib files and Makefile for Pi 4 testing
[pistorm] / raylib_pi4_test / external / glfw / src / cocoa_init.m
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 // It is fine to use C99 in this file because it will not be built with VS
27 //========================================================================
28
29 #include "internal.h"
30 #include <sys/param.h> // For MAXPATHLEN
31
32 // Needed for _NSGetProgname
33 #include <crt_externs.h>
34
35 // Change to our application bundle's resources directory, if present
36 //
37 static void changeToResourcesDirectory(void)
38 {
39     char resourcesPath[MAXPATHLEN];
40
41     CFBundleRef bundle = CFBundleGetMainBundle();
42     if (!bundle)
43         return;
44
45     CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
46
47     CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
48     if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
49     {
50         CFRelease(last);
51         CFRelease(resourcesURL);
52         return;
53     }
54
55     CFRelease(last);
56
57     if (!CFURLGetFileSystemRepresentation(resourcesURL,
58                                           true,
59                                           (UInt8*) resourcesPath,
60                                           MAXPATHLEN))
61     {
62         CFRelease(resourcesURL);
63         return;
64     }
65
66     CFRelease(resourcesURL);
67
68     chdir(resourcesPath);
69 }
70
71 // Set up the menu bar (manually)
72 // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
73 // could go away at any moment, lots of stuff that really should be
74 // localize(d|able), etc.  Add a nib to save us this horror.
75 //
76 static void createMenuBar(void)
77 {
78     size_t i;
79     NSString* appName = nil;
80     NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
81     NSString* nameKeys[] =
82     {
83         @"CFBundleDisplayName",
84         @"CFBundleName",
85         @"CFBundleExecutable",
86     };
87
88     // Try to figure out what the calling application is called
89
90     for (i = 0;  i < sizeof(nameKeys) / sizeof(nameKeys[0]);  i++)
91     {
92         id name = bundleInfo[nameKeys[i]];
93         if (name &&
94             [name isKindOfClass:[NSString class]] &&
95             ![name isEqualToString:@""])
96         {
97             appName = name;
98             break;
99         }
100     }
101
102     if (!appName)
103     {
104         char** progname = _NSGetProgname();
105         if (progname && *progname)
106             appName = @(*progname);
107         else
108             appName = @"GLFW Application";
109     }
110
111     NSMenu* bar = [[NSMenu alloc] init];
112     [NSApp setMainMenu:bar];
113
114     NSMenuItem* appMenuItem =
115         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
116     NSMenu* appMenu = [[NSMenu alloc] init];
117     [appMenuItem setSubmenu:appMenu];
118
119     [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
120                        action:@selector(orderFrontStandardAboutPanel:)
121                 keyEquivalent:@""];
122     [appMenu addItem:[NSMenuItem separatorItem]];
123     NSMenu* servicesMenu = [[NSMenu alloc] init];
124     [NSApp setServicesMenu:servicesMenu];
125     [[appMenu addItemWithTitle:@"Services"
126                        action:NULL
127                 keyEquivalent:@""] setSubmenu:servicesMenu];
128     [servicesMenu release];
129     [appMenu addItem:[NSMenuItem separatorItem]];
130     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
131                        action:@selector(hide:)
132                 keyEquivalent:@"h"];
133     [[appMenu addItemWithTitle:@"Hide Others"
134                        action:@selector(hideOtherApplications:)
135                 keyEquivalent:@"h"]
136         setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
137     [appMenu addItemWithTitle:@"Show All"
138                        action:@selector(unhideAllApplications:)
139                 keyEquivalent:@""];
140     [appMenu addItem:[NSMenuItem separatorItem]];
141     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
142                        action:@selector(terminate:)
143                 keyEquivalent:@"q"];
144
145     NSMenuItem* windowMenuItem =
146         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
147     [bar release];
148     NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
149     [NSApp setWindowsMenu:windowMenu];
150     [windowMenuItem setSubmenu:windowMenu];
151
152     [windowMenu addItemWithTitle:@"Minimize"
153                           action:@selector(performMiniaturize:)
154                    keyEquivalent:@"m"];
155     [windowMenu addItemWithTitle:@"Zoom"
156                           action:@selector(performZoom:)
157                    keyEquivalent:@""];
158     [windowMenu addItem:[NSMenuItem separatorItem]];
159     [windowMenu addItemWithTitle:@"Bring All to Front"
160                           action:@selector(arrangeInFront:)
161                    keyEquivalent:@""];
162
163     // TODO: Make this appear at the bottom of the menu (for consistency)
164     [windowMenu addItem:[NSMenuItem separatorItem]];
165     [[windowMenu addItemWithTitle:@"Enter Full Screen"
166                            action:@selector(toggleFullScreen:)
167                     keyEquivalent:@"f"]
168      setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
169
170     // Prior to Snow Leopard, we need to use this oddly-named semi-private API
171     // to get the application menu working properly.
172     SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
173     [NSApp performSelector:setAppleMenuSelector withObject:appMenu];
174 }
175
176 // Create key code translation tables
177 //
178 static void createKeyTables(void)
179 {
180     int scancode;
181
182     memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
183     memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
184
185     _glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
186     _glfw.ns.keycodes[0x12] = GLFW_KEY_1;
187     _glfw.ns.keycodes[0x13] = GLFW_KEY_2;
188     _glfw.ns.keycodes[0x14] = GLFW_KEY_3;
189     _glfw.ns.keycodes[0x15] = GLFW_KEY_4;
190     _glfw.ns.keycodes[0x17] = GLFW_KEY_5;
191     _glfw.ns.keycodes[0x16] = GLFW_KEY_6;
192     _glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
193     _glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
194     _glfw.ns.keycodes[0x19] = GLFW_KEY_9;
195     _glfw.ns.keycodes[0x00] = GLFW_KEY_A;
196     _glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
197     _glfw.ns.keycodes[0x08] = GLFW_KEY_C;
198     _glfw.ns.keycodes[0x02] = GLFW_KEY_D;
199     _glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
200     _glfw.ns.keycodes[0x03] = GLFW_KEY_F;
201     _glfw.ns.keycodes[0x05] = GLFW_KEY_G;
202     _glfw.ns.keycodes[0x04] = GLFW_KEY_H;
203     _glfw.ns.keycodes[0x22] = GLFW_KEY_I;
204     _glfw.ns.keycodes[0x26] = GLFW_KEY_J;
205     _glfw.ns.keycodes[0x28] = GLFW_KEY_K;
206     _glfw.ns.keycodes[0x25] = GLFW_KEY_L;
207     _glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
208     _glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
209     _glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
210     _glfw.ns.keycodes[0x23] = GLFW_KEY_P;
211     _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
212     _glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
213     _glfw.ns.keycodes[0x01] = GLFW_KEY_S;
214     _glfw.ns.keycodes[0x11] = GLFW_KEY_T;
215     _glfw.ns.keycodes[0x20] = GLFW_KEY_U;
216     _glfw.ns.keycodes[0x09] = GLFW_KEY_V;
217     _glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
218     _glfw.ns.keycodes[0x07] = GLFW_KEY_X;
219     _glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
220     _glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
221
222     _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
223     _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
224     _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
225     _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
226     _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
227     _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
228     _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
229     _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
230     _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
231     _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
232     _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
233     _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
234
235     _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
236     _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
237     _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
238     _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
239     _glfw.ns.keycodes[0x77] = GLFW_KEY_END;
240     _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
241     _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
242     _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
243     _glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
244     _glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
245     _glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
246     _glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
247     _glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
248     _glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
249     _glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
250     _glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
251     _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
252     _glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
253     _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
254     _glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
255     _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
256     _glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
257     _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
258     _glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
259     _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
260     _glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
261     _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
262     _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
263     _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
264     _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
265     _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
266     _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
267     _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
268     _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
269     _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
270     _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
271     _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
272     _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
273     _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
274     _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
275     _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
276     _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
277     _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
278     _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
279     _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
280     _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
281
282     _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
283     _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
284     _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
285     _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
286     _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
287     _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
288     _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
289     _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
290     _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
291     _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
292     _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
293     _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
294     _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
295     _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
296     _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
297     _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
298     _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
299
300     for (scancode = 0;  scancode < 256;  scancode++)
301     {
302         // Store the reverse translation for faster key name lookup
303         if (_glfw.ns.keycodes[scancode] >= 0)
304             _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
305     }
306 }
307
308 // Retrieve Unicode data for the current keyboard layout
309 //
310 static GLFWbool updateUnicodeDataNS(void)
311 {
312     if (_glfw.ns.inputSource)
313     {
314         CFRelease(_glfw.ns.inputSource);
315         _glfw.ns.inputSource = NULL;
316         _glfw.ns.unicodeData = nil;
317     }
318
319     _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
320     if (!_glfw.ns.inputSource)
321     {
322         _glfwInputError(GLFW_PLATFORM_ERROR,
323                         "Cocoa: Failed to retrieve keyboard layout input source");
324         return GLFW_FALSE;
325     }
326
327     _glfw.ns.unicodeData =
328         TISGetInputSourceProperty(_glfw.ns.inputSource,
329                                   kTISPropertyUnicodeKeyLayoutData);
330     if (!_glfw.ns.unicodeData)
331     {
332         _glfwInputError(GLFW_PLATFORM_ERROR,
333                         "Cocoa: Failed to retrieve keyboard layout Unicode data");
334         return GLFW_FALSE;
335     }
336
337     return GLFW_TRUE;
338 }
339
340 // Load HIToolbox.framework and the TIS symbols we need from it
341 //
342 static GLFWbool initializeTIS(void)
343 {
344     // This works only because Cocoa has already loaded it properly
345     _glfw.ns.tis.bundle =
346         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
347     if (!_glfw.ns.tis.bundle)
348     {
349         _glfwInputError(GLFW_PLATFORM_ERROR,
350                         "Cocoa: Failed to load HIToolbox.framework");
351         return GLFW_FALSE;
352     }
353
354     CFStringRef* kPropertyUnicodeKeyLayoutData =
355         CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
356                                       CFSTR("kTISPropertyUnicodeKeyLayoutData"));
357     _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
358         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
359                                           CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
360     _glfw.ns.tis.GetInputSourceProperty =
361         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
362                                           CFSTR("TISGetInputSourceProperty"));
363     _glfw.ns.tis.GetKbdType =
364         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
365                                           CFSTR("LMGetKbdType"));
366
367     if (!kPropertyUnicodeKeyLayoutData ||
368         !TISCopyCurrentKeyboardLayoutInputSource ||
369         !TISGetInputSourceProperty ||
370         !LMGetKbdType)
371     {
372         _glfwInputError(GLFW_PLATFORM_ERROR,
373                         "Cocoa: Failed to load TIS API symbols");
374         return GLFW_FALSE;
375     }
376
377     _glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
378         *kPropertyUnicodeKeyLayoutData;
379
380     return updateUnicodeDataNS();
381 }
382
383 @interface GLFWHelper : NSObject
384 @end
385
386 @implementation GLFWHelper
387
388 - (void)selectedKeyboardInputSourceChanged:(NSObject* )object
389 {
390     updateUnicodeDataNS();
391 }
392
393 - (void)doNothing:(id)object
394 {
395 }
396
397 @end // GLFWHelper
398
399 @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
400 @end
401
402 @implementation GLFWApplicationDelegate
403
404 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
405 {
406     _GLFWwindow* window;
407
408     for (window = _glfw.windowListHead;  window;  window = window->next)
409         _glfwInputWindowCloseRequest(window);
410
411     return NSTerminateCancel;
412 }
413
414 - (void)applicationDidChangeScreenParameters:(NSNotification *) notification
415 {
416     _GLFWwindow* window;
417
418     for (window = _glfw.windowListHead;  window;  window = window->next)
419     {
420         if (window->context.client != GLFW_NO_API)
421             [window->context.nsgl.object update];
422     }
423
424     _glfwPollMonitorsNS();
425 }
426
427 - (void)applicationWillFinishLaunching:(NSNotification *)notification
428 {
429     if (_glfw.hints.init.ns.menubar)
430     {
431         // In case we are unbundled, make us a proper UI application
432         [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
433
434         // Menu bar setup must go between sharedApplication and finishLaunching
435         // in order to properly emulate the behavior of NSApplicationMain
436
437         if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
438         {
439             [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
440                                           owner:NSApp
441                                 topLevelObjects:&_glfw.ns.nibObjects];
442         }
443         else
444             createMenuBar();
445     }
446 }
447
448 - (void)applicationDidFinishLaunching:(NSNotification *)notification
449 {
450     _glfwPlatformPostEmptyEvent();
451     [NSApp stop:nil];
452 }
453
454 - (void)applicationDidHide:(NSNotification *)notification
455 {
456     int i;
457
458     for (i = 0;  i < _glfw.monitorCount;  i++)
459         _glfwRestoreVideoModeNS(_glfw.monitors[i]);
460 }
461
462 @end // GLFWApplicationDelegate
463
464
465 //////////////////////////////////////////////////////////////////////////
466 //////                       GLFW internal API                      //////
467 //////////////////////////////////////////////////////////////////////////
468
469 void* _glfwLoadLocalVulkanLoaderNS(void)
470 {
471     CFBundleRef bundle = CFBundleGetMainBundle();
472     if (!bundle)
473         return NULL;
474
475     CFURLRef url =
476         CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
477     if (!url)
478         return NULL;
479
480     char path[PATH_MAX];
481     void* handle = NULL;
482
483     if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
484         handle = _glfw_dlopen(path);
485
486     CFRelease(url);
487     return handle;
488 }
489
490
491 //////////////////////////////////////////////////////////////////////////
492 //////                       GLFW platform API                      //////
493 //////////////////////////////////////////////////////////////////////////
494
495 int _glfwPlatformInit(void)
496 {
497     @autoreleasepool {
498
499     _glfw.ns.helper = [[GLFWHelper alloc] init];
500
501     [NSThread detachNewThreadSelector:@selector(doNothing:)
502                              toTarget:_glfw.ns.helper
503                            withObject:nil];
504
505     [NSApplication sharedApplication];
506
507     _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
508     if (_glfw.ns.delegate == nil)
509     {
510         _glfwInputError(GLFW_PLATFORM_ERROR,
511                         "Cocoa: Failed to create application delegate");
512         return GLFW_FALSE;
513     }
514
515     [NSApp setDelegate:_glfw.ns.delegate];
516
517     NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
518     {
519         if ([event modifierFlags] & NSEventModifierFlagCommand)
520             [[NSApp keyWindow] sendEvent:event];
521
522         return event;
523     };
524
525     _glfw.ns.keyUpMonitor =
526         [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
527                                               handler:block];
528
529     if (_glfw.hints.init.ns.chdir)
530         changeToResourcesDirectory();
531
532     // Press and Hold prevents some keys from emitting repeated characters
533     NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
534     [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
535
536     [[NSNotificationCenter defaultCenter]
537         addObserver:_glfw.ns.helper
538            selector:@selector(selectedKeyboardInputSourceChanged:)
539                name:NSTextInputContextKeyboardSelectionDidChangeNotification
540              object:nil];
541
542     createKeyTables();
543
544     _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
545     if (!_glfw.ns.eventSource)
546         return GLFW_FALSE;
547
548     CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
549
550     if (!initializeTIS())
551         return GLFW_FALSE;
552
553     _glfwInitTimerNS();
554
555     _glfwPollMonitorsNS();
556
557     if (![[NSRunningApplication currentApplication] isFinishedLaunching])
558         [NSApp run];
559
560     return GLFW_TRUE;
561
562     } // autoreleasepool
563 }
564
565 void _glfwPlatformTerminate(void)
566 {
567     @autoreleasepool {
568
569     if (_glfw.ns.inputSource)
570     {
571         CFRelease(_glfw.ns.inputSource);
572         _glfw.ns.inputSource = NULL;
573         _glfw.ns.unicodeData = nil;
574     }
575
576     if (_glfw.ns.eventSource)
577     {
578         CFRelease(_glfw.ns.eventSource);
579         _glfw.ns.eventSource = NULL;
580     }
581
582     if (_glfw.ns.delegate)
583     {
584         [NSApp setDelegate:nil];
585         [_glfw.ns.delegate release];
586         _glfw.ns.delegate = nil;
587     }
588
589     if (_glfw.ns.helper)
590     {
591         [[NSNotificationCenter defaultCenter]
592             removeObserver:_glfw.ns.helper
593                       name:NSTextInputContextKeyboardSelectionDidChangeNotification
594                     object:nil];
595         [[NSNotificationCenter defaultCenter]
596             removeObserver:_glfw.ns.helper];
597         [_glfw.ns.helper release];
598         _glfw.ns.helper = nil;
599     }
600
601     if (_glfw.ns.keyUpMonitor)
602         [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
603
604     free(_glfw.ns.clipboardString);
605
606     _glfwTerminateNSGL();
607
608     } // autoreleasepool
609 }
610
611 const char* _glfwPlatformGetVersionString(void)
612 {
613     return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa"
614 #if defined(_GLFW_BUILD_DLL)
615         " dynamic"
616 #endif
617         ;
618 }
619