github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/glfw/src/cocoa_init.m (about)

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