volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

cocoa_init.m (24873B)


      1 //========================================================================
      2 // GLFW 3.4 macOS (modified for raylib) - www.glfw.org; www.raylib.com
      3 //------------------------------------------------------------------------
      4 // Copyright (c) 2009-2019 Camilla Löwy <elmindreda@glfw.org>
      5 // Copyright (c) 2024 M374LX <wilsalx@gmail.com>
      6 //
      7 // This software is provided 'as-is', without any express or implied
      8 // warranty. In no event will the authors be held liable for any damages
      9 // arising from the use of this software.
     10 //
     11 // Permission is granted to anyone to use this software for any purpose,
     12 // including commercial applications, and to alter it and redistribute it
     13 // freely, subject to the following restrictions:
     14 //
     15 // 1. The origin of this software must not be misrepresented; you must not
     16 //    claim that you wrote the original software. If you use this software
     17 //    in a product, an acknowledgment in the product documentation would
     18 //    be appreciated but is not required.
     19 //
     20 // 2. Altered source versions must be plainly marked as such, and must not
     21 //    be misrepresented as being the original software.
     22 //
     23 // 3. This notice may not be removed or altered from any source
     24 //    distribution.
     25 //
     26 //========================================================================
     27 
     28 #include "internal.h"
     29 
     30 #if defined(_GLFW_COCOA)
     31 
     32 #include <sys/param.h> // For MAXPATHLEN
     33 
     34 // Needed for _NSGetProgname
     35 #include <crt_externs.h>
     36 
     37 // Change to our application bundle's resources directory, if present
     38 //
     39 static void changeToResourcesDirectory(void)
     40 {
     41     char resourcesPath[MAXPATHLEN];
     42 
     43     CFBundleRef bundle = CFBundleGetMainBundle();
     44     if (!bundle)
     45         return;
     46 
     47     CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
     48 
     49     CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
     50     if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
     51     {
     52         CFRelease(last);
     53         CFRelease(resourcesURL);
     54         return;
     55     }
     56 
     57     CFRelease(last);
     58 
     59     if (!CFURLGetFileSystemRepresentation(resourcesURL,
     60                                           true,
     61                                           (UInt8*) resourcesPath,
     62                                           MAXPATHLEN))
     63     {
     64         CFRelease(resourcesURL);
     65         return;
     66     }
     67 
     68     CFRelease(resourcesURL);
     69 
     70     chdir(resourcesPath);
     71 }
     72 
     73 // Set up the menu bar (manually)
     74 // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
     75 // could go away at any moment, lots of stuff that really should be
     76 // localize(d|able), etc.  Add a nib to save us this horror.
     77 //
     78 static void createMenuBar(void)
     79 {
     80     NSString* appName = nil;
     81     NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
     82     NSString* nameKeys[] =
     83     {
     84         @"CFBundleDisplayName",
     85         @"CFBundleName",
     86         @"CFBundleExecutable",
     87     };
     88 
     89     // Try to figure out what the calling application is called
     90 
     91     for (size_t i = 0;  i < sizeof(nameKeys) / sizeof(nameKeys[0]);  i++)
     92     {
     93         id name = bundleInfo[nameKeys[i]];
     94         if (name &&
     95             [name isKindOfClass:[NSString class]] &&
     96             ![name isEqualToString:@""])
     97         {
     98             appName = name;
     99             break;
    100         }
    101     }
    102 
    103     if (!appName)
    104     {
    105         char** progname = _NSGetProgname();
    106         if (progname && *progname)
    107             appName = @(*progname);
    108         else
    109             appName = @"GLFW Application";
    110     }
    111 
    112     NSMenu* bar = [[NSMenu alloc] init];
    113     [NSApp setMainMenu:bar];
    114 
    115     NSMenuItem* appMenuItem =
    116         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
    117     NSMenu* appMenu = [[NSMenu alloc] init];
    118     [appMenuItem setSubmenu:appMenu];
    119 
    120     [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
    121                        action:@selector(orderFrontStandardAboutPanel:)
    122                 keyEquivalent:@""];
    123     [appMenu addItem:[NSMenuItem separatorItem]];
    124     NSMenu* servicesMenu = [[NSMenu alloc] init];
    125     [NSApp setServicesMenu:servicesMenu];
    126     [[appMenu addItemWithTitle:@"Services"
    127                        action:NULL
    128                 keyEquivalent:@""] setSubmenu:servicesMenu];
    129     [servicesMenu release];
    130     [appMenu addItem:[NSMenuItem separatorItem]];
    131     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
    132                        action:@selector(hide:)
    133                 keyEquivalent:@"h"];
    134     [[appMenu addItemWithTitle:@"Hide Others"
    135                        action:@selector(hideOtherApplications:)
    136                 keyEquivalent:@"h"]
    137         setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
    138     [appMenu addItemWithTitle:@"Show All"
    139                        action:@selector(unhideAllApplications:)
    140                 keyEquivalent:@""];
    141     [appMenu addItem:[NSMenuItem separatorItem]];
    142     [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
    143                        action:@selector(terminate:)
    144                 keyEquivalent:@"q"];
    145 
    146     NSMenuItem* windowMenuItem =
    147         [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
    148     [bar release];
    149     NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
    150     [NSApp setWindowsMenu:windowMenu];
    151     [windowMenuItem setSubmenu:windowMenu];
    152 
    153     [windowMenu addItemWithTitle:@"Minimize"
    154                           action:@selector(performMiniaturize:)
    155                    keyEquivalent:@"m"];
    156     [windowMenu addItemWithTitle:@"Zoom"
    157                           action:@selector(performZoom:)
    158                    keyEquivalent:@""];
    159     [windowMenu addItem:[NSMenuItem separatorItem]];
    160     [windowMenu addItemWithTitle:@"Bring All to Front"
    161                           action:@selector(arrangeInFront:)
    162                    keyEquivalent:@""];
    163 
    164     // TODO: Make this appear at the bottom of the menu (for consistency)
    165     [windowMenu addItem:[NSMenuItem separatorItem]];
    166     [[windowMenu addItemWithTitle:@"Enter Full Screen"
    167                            action:@selector(toggleFullScreen:)
    168                     keyEquivalent:@"f"]
    169      setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
    170 
    171     // Prior to Snow Leopard, we need to use this oddly-named semi-private API
    172     // to get the application menu working properly.
    173     SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
    174     [NSApp performSelector:setAppleMenuSelector withObject:appMenu];
    175 }
    176 
    177 // Create key code translation tables
    178 //
    179 static void createKeyTablesCocoa(void)
    180 {
    181     memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
    182     memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
    183 
    184     _glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
    185     _glfw.ns.keycodes[0x12] = GLFW_KEY_1;
    186     _glfw.ns.keycodes[0x13] = GLFW_KEY_2;
    187     _glfw.ns.keycodes[0x14] = GLFW_KEY_3;
    188     _glfw.ns.keycodes[0x15] = GLFW_KEY_4;
    189     _glfw.ns.keycodes[0x17] = GLFW_KEY_5;
    190     _glfw.ns.keycodes[0x16] = GLFW_KEY_6;
    191     _glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
    192     _glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
    193     _glfw.ns.keycodes[0x19] = GLFW_KEY_9;
    194     _glfw.ns.keycodes[0x00] = GLFW_KEY_A;
    195     _glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
    196     _glfw.ns.keycodes[0x08] = GLFW_KEY_C;
    197     _glfw.ns.keycodes[0x02] = GLFW_KEY_D;
    198     _glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
    199     _glfw.ns.keycodes[0x03] = GLFW_KEY_F;
    200     _glfw.ns.keycodes[0x05] = GLFW_KEY_G;
    201     _glfw.ns.keycodes[0x04] = GLFW_KEY_H;
    202     _glfw.ns.keycodes[0x22] = GLFW_KEY_I;
    203     _glfw.ns.keycodes[0x26] = GLFW_KEY_J;
    204     _glfw.ns.keycodes[0x28] = GLFW_KEY_K;
    205     _glfw.ns.keycodes[0x25] = GLFW_KEY_L;
    206     _glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
    207     _glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
    208     _glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
    209     _glfw.ns.keycodes[0x23] = GLFW_KEY_P;
    210     _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
    211     _glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
    212     _glfw.ns.keycodes[0x01] = GLFW_KEY_S;
    213     _glfw.ns.keycodes[0x11] = GLFW_KEY_T;
    214     _glfw.ns.keycodes[0x20] = GLFW_KEY_U;
    215     _glfw.ns.keycodes[0x09] = GLFW_KEY_V;
    216     _glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
    217     _glfw.ns.keycodes[0x07] = GLFW_KEY_X;
    218     _glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
    219     _glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
    220 
    221     _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
    222     _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
    223     _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
    224     _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
    225     _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
    226     _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
    227     _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
    228     _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
    229     _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
    230     _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
    231     _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
    232     _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
    233 
    234     _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
    235     _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
    236     _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
    237     _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
    238     _glfw.ns.keycodes[0x77] = GLFW_KEY_END;
    239     _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
    240     _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
    241     _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
    242     _glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
    243     _glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
    244     _glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
    245     _glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
    246     _glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
    247     _glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
    248     _glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
    249     _glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
    250     _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
    251     _glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
    252     _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
    253     _glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN;
    254     _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
    255     _glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
    256     _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
    257     _glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
    258     _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
    259     _glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
    260     _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
    261     _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
    262     _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
    263     _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
    264     _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
    265     _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
    266     _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
    267     _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
    268     _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
    269     _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
    270     _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
    271     _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
    272     _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
    273     _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
    274     _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
    275     _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
    276     _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
    277     _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
    278     _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
    279     _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
    280 
    281     _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
    282     _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
    283     _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
    284     _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
    285     _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
    286     _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
    287     _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
    288     _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
    289     _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
    290     _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
    291     _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
    292     _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
    293     _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
    294     _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
    295     _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
    296     _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
    297     _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
    298 
    299     for (int scancode = 0;  scancode < 256;  scancode++)
    300     {
    301         // Store the reverse translation for faster key name lookup
    302         if (_glfw.ns.keycodes[scancode] >= 0)
    303             _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
    304     }
    305 }
    306 
    307 // Retrieve Unicode data for the current keyboard layout
    308 //
    309 static GLFWbool updateUnicodeData(void)
    310 {
    311     if (_glfw.ns.inputSource)
    312     {
    313         CFRelease(_glfw.ns.inputSource);
    314         _glfw.ns.inputSource = NULL;
    315         _glfw.ns.unicodeData = nil;
    316     }
    317 
    318     _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
    319     if (!_glfw.ns.inputSource)
    320     {
    321         _glfwInputError(GLFW_PLATFORM_ERROR,
    322                         "Cocoa: Failed to retrieve keyboard layout input source");
    323         return GLFW_FALSE;
    324     }
    325 
    326     _glfw.ns.unicodeData =
    327         TISGetInputSourceProperty(_glfw.ns.inputSource,
    328                                   kTISPropertyUnicodeKeyLayoutData);
    329     if (!_glfw.ns.unicodeData)
    330     {
    331         _glfwInputError(GLFW_PLATFORM_ERROR,
    332                         "Cocoa: Failed to retrieve keyboard layout Unicode data");
    333         return GLFW_FALSE;
    334     }
    335 
    336     return GLFW_TRUE;
    337 }
    338 
    339 // Load HIToolbox.framework and the TIS symbols we need from it
    340 //
    341 static GLFWbool initializeTIS(void)
    342 {
    343     // This works only because Cocoa has already loaded it properly
    344     _glfw.ns.tis.bundle =
    345         CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
    346     if (!_glfw.ns.tis.bundle)
    347     {
    348         _glfwInputError(GLFW_PLATFORM_ERROR,
    349                         "Cocoa: Failed to load HIToolbox.framework");
    350         return GLFW_FALSE;
    351     }
    352 
    353     CFStringRef* kPropertyUnicodeKeyLayoutData =
    354         CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
    355                                       CFSTR("kTISPropertyUnicodeKeyLayoutData"));
    356     _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource =
    357         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
    358                                           CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
    359     _glfw.ns.tis.GetInputSourceProperty =
    360         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
    361                                           CFSTR("TISGetInputSourceProperty"));
    362     _glfw.ns.tis.GetKbdType =
    363         CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
    364                                           CFSTR("LMGetKbdType"));
    365 
    366     if (!kPropertyUnicodeKeyLayoutData ||
    367         !TISCopyCurrentKeyboardLayoutInputSource ||
    368         !TISGetInputSourceProperty ||
    369         !LMGetKbdType)
    370     {
    371         _glfwInputError(GLFW_PLATFORM_ERROR,
    372                         "Cocoa: Failed to load TIS API symbols");
    373         return GLFW_FALSE;
    374     }
    375 
    376     _glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
    377         *kPropertyUnicodeKeyLayoutData;
    378 
    379     return updateUnicodeData();
    380 }
    381 
    382 @interface GLFWHelper : NSObject
    383 @end
    384 
    385 @implementation GLFWHelper
    386 
    387 - (void)selectedKeyboardInputSourceChanged:(NSObject* )object
    388 {
    389     updateUnicodeData();
    390 }
    391 
    392 - (void)doNothing:(id)object
    393 {
    394 }
    395 
    396 @end // GLFWHelper
    397 
    398 @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
    399 @end
    400 
    401 @implementation GLFWApplicationDelegate
    402 
    403 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
    404 {
    405     for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
    406         _glfwInputWindowCloseRequest(window);
    407 
    408     return NSTerminateCancel;
    409 }
    410 
    411 - (void)applicationDidChangeScreenParameters:(NSNotification *) notification
    412 {
    413     for (_GLFWwindow* window = _glfw.windowListHead;  window;  window = window->next)
    414     {
    415         if (window->context.client != GLFW_NO_API)
    416             [window->context.nsgl.object update];
    417     }
    418 
    419     _glfwPollMonitorsCocoa();
    420 }
    421 
    422 - (void)applicationWillFinishLaunching:(NSNotification *)notification
    423 {
    424     if (_glfw.hints.init.ns.menubar)
    425     {
    426         // Menu bar setup must go between sharedApplication and finishLaunching
    427         // in order to properly emulate the behavior of NSApplicationMain
    428 
    429         if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
    430         {
    431             [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
    432                                           owner:NSApp
    433                                 topLevelObjects:&_glfw.ns.nibObjects];
    434         }
    435         else
    436             createMenuBar();
    437     }
    438 }
    439 
    440 - (void)applicationDidFinishLaunching:(NSNotification *)notification
    441 {
    442     _glfwPostEmptyEventCocoa();
    443     [NSApp stop:nil];
    444 }
    445 
    446 - (void)applicationDidHide:(NSNotification *)notification
    447 {
    448     for (int i = 0;  i < _glfw.monitorCount;  i++)
    449         _glfwRestoreVideoModeCocoa(_glfw.monitors[i]);
    450 }
    451 
    452 @end // GLFWApplicationDelegate
    453 
    454 
    455 //////////////////////////////////////////////////////////////////////////
    456 //////                       GLFW internal API                      //////
    457 //////////////////////////////////////////////////////////////////////////
    458 
    459 void* _glfwLoadLocalVulkanLoaderCocoa(void)
    460 {
    461     CFBundleRef bundle = CFBundleGetMainBundle();
    462     if (!bundle)
    463         return NULL;
    464 
    465     CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);
    466     if (!frameworksUrl)
    467         return NULL;
    468 
    469     CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(
    470         kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);
    471     if (!loaderUrl)
    472     {
    473         CFRelease(frameworksUrl);
    474         return NULL;
    475     }
    476 
    477     char path[PATH_MAX];
    478     void* handle = NULL;
    479 
    480     if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1))
    481         handle = _glfwPlatformLoadModule(path);
    482 
    483     CFRelease(loaderUrl);
    484     CFRelease(frameworksUrl);
    485     return handle;
    486 }
    487 
    488 
    489 //////////////////////////////////////////////////////////////////////////
    490 //////                       GLFW platform API                      //////
    491 //////////////////////////////////////////////////////////////////////////
    492 
    493 GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform)
    494 {
    495     const _GLFWplatform cocoa =
    496     {
    497         .platformID = GLFW_PLATFORM_COCOA,
    498         .init = _glfwInitCocoa,
    499         .terminate = _glfwTerminateCocoa,
    500         .getCursorPos = _glfwGetCursorPosCocoa,
    501         .setCursorPos = _glfwSetCursorPosCocoa,
    502         .setCursorMode = _glfwSetCursorModeCocoa,
    503         .setRawMouseMotion = _glfwSetRawMouseMotionCocoa,
    504         .rawMouseMotionSupported = _glfwRawMouseMotionSupportedCocoa,
    505         .createCursor = _glfwCreateCursorCocoa,
    506         .createStandardCursor = _glfwCreateStandardCursorCocoa,
    507         .destroyCursor = _glfwDestroyCursorCocoa,
    508         .setCursor = _glfwSetCursorCocoa,
    509         .getScancodeName = _glfwGetScancodeNameCocoa,
    510         .getKeyScancode = _glfwGetKeyScancodeCocoa,
    511         .setClipboardString = _glfwSetClipboardStringCocoa,
    512         .getClipboardString = _glfwGetClipboardStringCocoa,
    513         .initJoysticks = _glfwInitJoysticksCocoa,
    514         .terminateJoysticks = _glfwTerminateJoysticksCocoa,
    515         .pollJoystick = _glfwPollJoystickCocoa,
    516         .getMappingName = _glfwGetMappingNameCocoa,
    517         .updateGamepadGUID = _glfwUpdateGamepadGUIDCocoa,
    518         .freeMonitor = _glfwFreeMonitorCocoa,
    519         .getMonitorPos = _glfwGetMonitorPosCocoa,
    520         .getMonitorContentScale = _glfwGetMonitorContentScaleCocoa,
    521         .getMonitorWorkarea = _glfwGetMonitorWorkareaCocoa,
    522         .getVideoModes = _glfwGetVideoModesCocoa,
    523         .getVideoMode = _glfwGetVideoModeCocoa,
    524         .getGammaRamp = _glfwGetGammaRampCocoa,
    525         .setGammaRamp = _glfwSetGammaRampCocoa,
    526         .createWindow = _glfwCreateWindowCocoa,
    527         .destroyWindow = _glfwDestroyWindowCocoa,
    528         .setWindowTitle = _glfwSetWindowTitleCocoa,
    529         .setWindowIcon = _glfwSetWindowIconCocoa,
    530         .getWindowPos = _glfwGetWindowPosCocoa,
    531         .setWindowPos = _glfwSetWindowPosCocoa,
    532         .getWindowSize = _glfwGetWindowSizeCocoa,
    533         .setWindowSize = _glfwSetWindowSizeCocoa,
    534         .setWindowSizeLimits = _glfwSetWindowSizeLimitsCocoa,
    535         .setWindowAspectRatio = _glfwSetWindowAspectRatioCocoa,
    536         .getFramebufferSize = _glfwGetFramebufferSizeCocoa,
    537         .getWindowFrameSize = _glfwGetWindowFrameSizeCocoa,
    538         .getWindowContentScale = _glfwGetWindowContentScaleCocoa,
    539         .iconifyWindow = _glfwIconifyWindowCocoa,
    540         .restoreWindow = _glfwRestoreWindowCocoa,
    541         .maximizeWindow = _glfwMaximizeWindowCocoa,
    542         .showWindow = _glfwShowWindowCocoa,
    543         .hideWindow = _glfwHideWindowCocoa,
    544         .requestWindowAttention = _glfwRequestWindowAttentionCocoa,
    545         .focusWindow = _glfwFocusWindowCocoa,
    546         .setWindowMonitor = _glfwSetWindowMonitorCocoa,
    547         .windowFocused = _glfwWindowFocusedCocoa,
    548         .windowIconified = _glfwWindowIconifiedCocoa,
    549         .windowVisible = _glfwWindowVisibleCocoa,
    550         .windowMaximized = _glfwWindowMaximizedCocoa,
    551         .windowHovered = _glfwWindowHoveredCocoa,
    552         .framebufferTransparent = _glfwFramebufferTransparentCocoa,
    553         .getWindowOpacity = _glfwGetWindowOpacityCocoa,
    554         .setWindowResizable = _glfwSetWindowResizableCocoa,
    555         .setWindowDecorated = _glfwSetWindowDecoratedCocoa,
    556         .setWindowFloating = _glfwSetWindowFloatingCocoa,
    557         .setWindowOpacity = _glfwSetWindowOpacityCocoa,
    558         .setWindowMousePassthrough = _glfwSetWindowMousePassthroughCocoa,
    559         .pollEvents = _glfwPollEventsCocoa,
    560         .waitEvents = _glfwWaitEventsCocoa,
    561         .waitEventsTimeout = _glfwWaitEventsTimeoutCocoa,
    562         .postEmptyEvent = _glfwPostEmptyEventCocoa,
    563         .getEGLPlatform = _glfwGetEGLPlatformCocoa,
    564         .getEGLNativeDisplay = _glfwGetEGLNativeDisplayCocoa,
    565         .getEGLNativeWindow = _glfwGetEGLNativeWindowCocoa,
    566         .getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsCocoa,
    567         .getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportCocoa,
    568         .createWindowSurface = _glfwCreateWindowSurfaceCocoa
    569     };
    570 
    571     *platform = cocoa;
    572     return GLFW_TRUE;
    573 }
    574 
    575 int _glfwInitCocoa(void)
    576 {
    577     @autoreleasepool {
    578 
    579     _glfw.ns.helper = [[GLFWHelper alloc] init];
    580 
    581     [NSThread detachNewThreadSelector:@selector(doNothing:)
    582                              toTarget:_glfw.ns.helper
    583                            withObject:nil];
    584 
    585     [NSApplication sharedApplication];
    586 
    587     _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
    588     if (_glfw.ns.delegate == nil)
    589     {
    590         _glfwInputError(GLFW_PLATFORM_ERROR,
    591                         "Cocoa: Failed to create application delegate");
    592         return GLFW_FALSE;
    593     }
    594 
    595     [NSApp setDelegate:_glfw.ns.delegate];
    596 
    597     NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
    598     {
    599         if ([event modifierFlags] & NSEventModifierFlagCommand)
    600             [[NSApp keyWindow] sendEvent:event];
    601 
    602         return event;
    603     };
    604 
    605     _glfw.ns.keyUpMonitor =
    606         [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
    607                                               handler:block];
    608 
    609     if (_glfw.hints.init.ns.chdir)
    610         changeToResourcesDirectory();
    611 
    612     // Press and Hold prevents some keys from emitting repeated characters
    613     NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
    614     [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
    615 
    616     [[NSNotificationCenter defaultCenter]
    617         addObserver:_glfw.ns.helper
    618            selector:@selector(selectedKeyboardInputSourceChanged:)
    619                name:NSTextInputContextKeyboardSelectionDidChangeNotification
    620              object:nil];
    621 
    622     createKeyTablesCocoa();
    623 
    624     _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
    625     if (!_glfw.ns.eventSource)
    626         return GLFW_FALSE;
    627 
    628     CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
    629 
    630     if (!initializeTIS())
    631         return GLFW_FALSE;
    632 
    633     _glfwPollMonitorsCocoa();
    634 
    635     if (![[NSRunningApplication currentApplication] isFinishedLaunching])
    636         [NSApp run];
    637 
    638     // In case we are unbundled, make us a proper UI application
    639     if (_glfw.hints.init.ns.menubar)
    640         [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    641 
    642     return GLFW_TRUE;
    643 
    644     } // autoreleasepool
    645 }
    646 
    647 void _glfwTerminateCocoa(void)
    648 {
    649     @autoreleasepool {
    650 
    651     if (_glfw.ns.inputSource)
    652     {
    653         CFRelease(_glfw.ns.inputSource);
    654         _glfw.ns.inputSource = NULL;
    655         _glfw.ns.unicodeData = nil;
    656     }
    657 
    658     if (_glfw.ns.eventSource)
    659     {
    660         CFRelease(_glfw.ns.eventSource);
    661         _glfw.ns.eventSource = NULL;
    662     }
    663 
    664     if (_glfw.ns.delegate)
    665     {
    666         [NSApp setDelegate:nil];
    667         [_glfw.ns.delegate release];
    668         _glfw.ns.delegate = nil;
    669     }
    670 
    671     if (_glfw.ns.helper)
    672     {
    673         [[NSNotificationCenter defaultCenter]
    674             removeObserver:_glfw.ns.helper
    675                       name:NSTextInputContextKeyboardSelectionDidChangeNotification
    676                     object:nil];
    677         [[NSNotificationCenter defaultCenter]
    678             removeObserver:_glfw.ns.helper];
    679         [_glfw.ns.helper release];
    680         _glfw.ns.helper = nil;
    681     }
    682 
    683     if (_glfw.ns.keyUpMonitor)
    684         [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
    685 
    686     _glfw_free(_glfw.ns.clipboardString);
    687 
    688     _glfwTerminateNSGL();
    689     _glfwTerminateEGL();
    690     _glfwTerminateOSMesa();
    691 
    692     } // autoreleasepool
    693 }
    694 
    695 #endif // _GLFW_COCOA
    696