master
ブランチ master
cpputils / deps / glfw / src / cocoa_init.m
20.9 KB、621行 生 Blame 履歴
1//========================================================================
2// GLFW 3.3 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//
37static 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//
76static 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//
178static 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//
310static 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//
342static 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 _glfw.ns.finishedLaunching = GLFW_TRUE;
451 _glfwPlatformPostEmptyEvent();
452 [NSApp stop:nil];
453}
454
455- (void)applicationDidHide:(NSNotification *)notification
456{
457 int i;
458
459 for (i = 0; i < _glfw.monitorCount; i++)
460 _glfwRestoreVideoModeNS(_glfw.monitors[i]);
461}
462
463@end // GLFWApplicationDelegate
464
465
466//////////////////////////////////////////////////////////////////////////
467////// GLFW internal API //////
468//////////////////////////////////////////////////////////////////////////
469
470void* _glfwLoadLocalVulkanLoaderNS(void)
471{
472 CFBundleRef bundle = CFBundleGetMainBundle();
473 if (!bundle)
474 return NULL;
475
476 CFURLRef url =
477 CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
478 if (!url)
479 return NULL;
480
481 char path[PATH_MAX];
482 void* handle = NULL;
483
484 if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
485 handle = _glfw_dlopen(path);
486
487 CFRelease(url);
488 return handle;
489}
490
491
492//////////////////////////////////////////////////////////////////////////
493////// GLFW platform API //////
494//////////////////////////////////////////////////////////////////////////
495
496int _glfwPlatformInit(void)
497{
498 @autoreleasepool {
499
500 _glfw.ns.helper = [[GLFWHelper alloc] init];
501
502 [NSThread detachNewThreadSelector:@selector(doNothing:)
503 toTarget:_glfw.ns.helper
504 withObject:nil];
505
506 if (NSApp)
507 _glfw.ns.finishedLaunching = GLFW_TRUE;
508
509 [NSApplication sharedApplication];
510
511 _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
512 if (_glfw.ns.delegate == nil)
513 {
514 _glfwInputError(GLFW_PLATFORM_ERROR,
515 "Cocoa: Failed to create application delegate");
516 return GLFW_FALSE;
517 }
518
519 [NSApp setDelegate:_glfw.ns.delegate];
520
521 NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
522 {
523 if ([event modifierFlags] & NSEventModifierFlagCommand)
524 [[NSApp keyWindow] sendEvent:event];
525
526 return event;
527 };
528
529 _glfw.ns.keyUpMonitor =
530 [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
531 handler:block];
532
533 if (_glfw.hints.init.ns.chdir)
534 changeToResourcesDirectory();
535
536 // Press and Hold prevents some keys from emitting repeated characters
537 NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
538 [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
539
540 [[NSNotificationCenter defaultCenter]
541 addObserver:_glfw.ns.helper
542 selector:@selector(selectedKeyboardInputSourceChanged:)
543 name:NSTextInputContextKeyboardSelectionDidChangeNotification
544 object:nil];
545
546 createKeyTables();
547
548 _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
549 if (!_glfw.ns.eventSource)
550 return GLFW_FALSE;
551
552 CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
553
554 if (!initializeTIS())
555 return GLFW_FALSE;
556
557 _glfwInitTimerNS();
558 _glfwInitJoysticksNS();
559
560 _glfwPollMonitorsNS();
561 return GLFW_TRUE;
562
563 } // autoreleasepool
564}
565
566void _glfwPlatformTerminate(void)
567{
568 @autoreleasepool {
569
570 if (_glfw.ns.inputSource)
571 {
572 CFRelease(_glfw.ns.inputSource);
573 _glfw.ns.inputSource = NULL;
574 _glfw.ns.unicodeData = nil;
575 }
576
577 if (_glfw.ns.eventSource)
578 {
579 CFRelease(_glfw.ns.eventSource);
580 _glfw.ns.eventSource = NULL;
581 }
582
583 if (_glfw.ns.delegate)
584 {
585 [NSApp setDelegate:nil];
586 [_glfw.ns.delegate release];
587 _glfw.ns.delegate = nil;
588 }
589
590 if (_glfw.ns.helper)
591 {
592 [[NSNotificationCenter defaultCenter]
593 removeObserver:_glfw.ns.helper
594 name:NSTextInputContextKeyboardSelectionDidChangeNotification
595 object:nil];
596 [[NSNotificationCenter defaultCenter]
597 removeObserver:_glfw.ns.helper];
598 [_glfw.ns.helper release];
599 _glfw.ns.helper = nil;
600 }
601
602 if (_glfw.ns.keyUpMonitor)
603 [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
604
605 free(_glfw.ns.clipboardString);
606
607 _glfwTerminateNSGL();
608 _glfwTerminateJoysticksNS();
609
610 } // autoreleasepool
611}
612
613const char* _glfwPlatformGetVersionString(void)
614{
615 return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa"
616#if defined(_GLFW_BUILD_DLL)
617 " dynamic"
618#endif
619 ;
620}
621