zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

cocoa_init.m (20783B)


      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         // Menu bar setup must go between sharedApplication and finishLaunching
    432         // in order to properly emulate the behavior of NSApplicationMain
    433 
    434         if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
    435         {
    436             [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
    437                                           owner:NSApp
    438                                 topLevelObjects:&_glfw.ns.nibObjects];
    439         }
    440         else
    441             createMenuBar();
    442     }
    443 }
    444 
    445 - (void)applicationDidFinishLaunching:(NSNotification *)notification
    446 {
    447     _glfw.ns.finishedLaunching = GLFW_TRUE;
    448     _glfwPlatformPostEmptyEvent();
    449 
    450     // In case we are unbundled, make us a proper UI application
    451     if (_glfw.hints.init.ns.menubar)
    452         [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    453 
    454     [NSApp stop:nil];
    455 }
    456 
    457 - (void)applicationDidHide:(NSNotification *)notification
    458 {
    459     int i;
    460 
    461     for (i = 0;  i < _glfw.monitorCount;  i++)
    462         _glfwRestoreVideoModeNS(_glfw.monitors[i]);
    463 }
    464 
    465 @end // GLFWApplicationDelegate
    466 
    467 
    468 //////////////////////////////////////////////////////////////////////////
    469 //////                       GLFW internal API                      //////
    470 //////////////////////////////////////////////////////////////////////////
    471 
    472 void* _glfwLoadLocalVulkanLoaderNS(void)
    473 {
    474     CFBundleRef bundle = CFBundleGetMainBundle();
    475     if (!bundle)
    476         return NULL;
    477 
    478     CFURLRef url =
    479         CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
    480     if (!url)
    481         return NULL;
    482 
    483     char path[PATH_MAX];
    484     void* handle = NULL;
    485 
    486     if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
    487         handle = _glfw_dlopen(path);
    488 
    489     CFRelease(url);
    490     return handle;
    491 }
    492 
    493 
    494 //////////////////////////////////////////////////////////////////////////
    495 //////                       GLFW platform API                      //////
    496 //////////////////////////////////////////////////////////////////////////
    497 
    498 int _glfwPlatformInit(void)
    499 {
    500     @autoreleasepool {
    501 
    502     _glfw.ns.helper = [[GLFWHelper alloc] init];
    503 
    504     [NSThread detachNewThreadSelector:@selector(doNothing:)
    505                              toTarget:_glfw.ns.helper
    506                            withObject:nil];
    507 
    508     if (NSApp)
    509         _glfw.ns.finishedLaunching = GLFW_TRUE;
    510 
    511     [NSApplication sharedApplication];
    512 
    513     _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
    514     if (_glfw.ns.delegate == nil)
    515     {
    516         _glfwInputError(GLFW_PLATFORM_ERROR,
    517                         "Cocoa: Failed to create application delegate");
    518         return GLFW_FALSE;
    519     }
    520 
    521     [NSApp setDelegate:_glfw.ns.delegate];
    522 
    523     NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
    524     {
    525         if ([event modifierFlags] & NSEventModifierFlagCommand)
    526             [[NSApp keyWindow] sendEvent:event];
    527 
    528         return event;
    529     };
    530 
    531     _glfw.ns.keyUpMonitor =
    532         [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
    533                                               handler:block];
    534 
    535     if (_glfw.hints.init.ns.chdir)
    536         changeToResourcesDirectory();
    537 
    538     // Press and Hold prevents some keys from emitting repeated characters
    539     NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
    540     [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
    541 
    542     [[NSNotificationCenter defaultCenter]
    543         addObserver:_glfw.ns.helper
    544            selector:@selector(selectedKeyboardInputSourceChanged:)
    545                name:NSTextInputContextKeyboardSelectionDidChangeNotification
    546              object:nil];
    547 
    548     createKeyTables();
    549 
    550     _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
    551     if (!_glfw.ns.eventSource)
    552         return GLFW_FALSE;
    553 
    554     CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
    555 
    556     if (!initializeTIS())
    557         return GLFW_FALSE;
    558 
    559     _glfwInitTimerNS();
    560     _glfwInitJoysticksNS();
    561 
    562     _glfwPollMonitorsNS();
    563     return GLFW_TRUE;
    564 
    565     } // autoreleasepool
    566 }
    567 
    568 void _glfwPlatformTerminate(void)
    569 {
    570     @autoreleasepool {
    571 
    572     if (_glfw.ns.inputSource)
    573     {
    574         CFRelease(_glfw.ns.inputSource);
    575         _glfw.ns.inputSource = NULL;
    576         _glfw.ns.unicodeData = nil;
    577     }
    578 
    579     if (_glfw.ns.eventSource)
    580     {
    581         CFRelease(_glfw.ns.eventSource);
    582         _glfw.ns.eventSource = NULL;
    583     }
    584 
    585     if (_glfw.ns.delegate)
    586     {
    587         [NSApp setDelegate:nil];
    588         [_glfw.ns.delegate release];
    589         _glfw.ns.delegate = nil;
    590     }
    591 
    592     if (_glfw.ns.helper)
    593     {
    594         [[NSNotificationCenter defaultCenter]
    595             removeObserver:_glfw.ns.helper
    596                       name:NSTextInputContextKeyboardSelectionDidChangeNotification
    597                     object:nil];
    598         [[NSNotificationCenter defaultCenter]
    599             removeObserver:_glfw.ns.helper];
    600         [_glfw.ns.helper release];
    601         _glfw.ns.helper = nil;
    602     }
    603 
    604     if (_glfw.ns.keyUpMonitor)
    605         [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
    606 
    607     free(_glfw.ns.clipboardString);
    608 
    609     _glfwTerminateNSGL();
    610     _glfwTerminateJoysticksNS();
    611 
    612     } // autoreleasepool
    613 }
    614 
    615 const char* _glfwPlatformGetVersionString(void)
    616 {
    617     return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa"
    618 #if defined(_GLFW_BUILD_DLL)
    619         " dynamic"
    620 #endif
    621         ;
    622 }
    623