twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

cocoa_init.m (20749B)


      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 //
     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     _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 
    470 void* _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 
    496 int _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 
    566 void _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 
    613 const 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