cocoa_init.m 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. //========================================================================
  2. // GLFW 3.4 macOS - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2009-2019 Camilla Löwy <[email protected]>
  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. #include "internal.h"
  29. #include <sys/param.h> // For MAXPATHLEN
  30. // Needed for _NSGetProgname
  31. #include <crt_externs.h>
  32. // Change to our application bundle's resources directory, if present
  33. //
  34. static void changeToResourcesDirectory(void)
  35. {
  36. char resourcesPath[MAXPATHLEN];
  37. CFBundleRef bundle = CFBundleGetMainBundle();
  38. if (!bundle)
  39. return;
  40. CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
  41. CFStringRef last = CFURLCopyLastPathComponent(resourcesURL);
  42. if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo)
  43. {
  44. CFRelease(last);
  45. CFRelease(resourcesURL);
  46. return;
  47. }
  48. CFRelease(last);
  49. if (!CFURLGetFileSystemRepresentation(resourcesURL,
  50. true,
  51. (UInt8*) resourcesPath,
  52. MAXPATHLEN))
  53. {
  54. CFRelease(resourcesURL);
  55. return;
  56. }
  57. CFRelease(resourcesURL);
  58. chdir(resourcesPath);
  59. }
  60. // Set up the menu bar (manually)
  61. // This is nasty, nasty stuff -- calls to undocumented semi-private APIs that
  62. // could go away at any moment, lots of stuff that really should be
  63. // localize(d|able), etc. Add a nib to save us this horror.
  64. //
  65. static void createMenuBar(void)
  66. {
  67. size_t i;
  68. NSString* appName = nil;
  69. NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary];
  70. NSString* nameKeys[] =
  71. {
  72. @"CFBundleDisplayName",
  73. @"CFBundleName",
  74. @"CFBundleExecutable",
  75. };
  76. // Try to figure out what the calling application is called
  77. for (i = 0; i < sizeof(nameKeys) / sizeof(nameKeys[0]); i++)
  78. {
  79. id name = bundleInfo[nameKeys[i]];
  80. if (name &&
  81. [name isKindOfClass:[NSString class]] &&
  82. ![name isEqualToString:@""])
  83. {
  84. appName = name;
  85. break;
  86. }
  87. }
  88. if (!appName)
  89. {
  90. char** progname = _NSGetProgname();
  91. if (progname && *progname)
  92. appName = @(*progname);
  93. else
  94. appName = @"GLFW Application";
  95. }
  96. NSMenu* bar = [[NSMenu alloc] init];
  97. [NSApp setMainMenu:bar];
  98. NSMenuItem* appMenuItem =
  99. [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
  100. NSMenu* appMenu = [[NSMenu alloc] init];
  101. [appMenuItem setSubmenu:appMenu];
  102. [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName]
  103. action:@selector(orderFrontStandardAboutPanel:)
  104. keyEquivalent:@""];
  105. [appMenu addItem:[NSMenuItem separatorItem]];
  106. NSMenu* servicesMenu = [[NSMenu alloc] init];
  107. [NSApp setServicesMenu:servicesMenu];
  108. [[appMenu addItemWithTitle:@"Services"
  109. action:NULL
  110. keyEquivalent:@""] setSubmenu:servicesMenu];
  111. [servicesMenu release];
  112. [appMenu addItem:[NSMenuItem separatorItem]];
  113. [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName]
  114. action:@selector(hide:)
  115. keyEquivalent:@"h"];
  116. [[appMenu addItemWithTitle:@"Hide Others"
  117. action:@selector(hideOtherApplications:)
  118. keyEquivalent:@"h"]
  119. setKeyEquivalentModifierMask:NSEventModifierFlagOption | NSEventModifierFlagCommand];
  120. [appMenu addItemWithTitle:@"Show All"
  121. action:@selector(unhideAllApplications:)
  122. keyEquivalent:@""];
  123. [appMenu addItem:[NSMenuItem separatorItem]];
  124. [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName]
  125. action:@selector(terminate:)
  126. keyEquivalent:@"q"];
  127. NSMenuItem* windowMenuItem =
  128. [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""];
  129. [bar release];
  130. NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
  131. [NSApp setWindowsMenu:windowMenu];
  132. [windowMenuItem setSubmenu:windowMenu];
  133. [windowMenu addItemWithTitle:@"Minimize"
  134. action:@selector(performMiniaturize:)
  135. keyEquivalent:@"m"];
  136. [windowMenu addItemWithTitle:@"Zoom"
  137. action:@selector(performZoom:)
  138. keyEquivalent:@""];
  139. [windowMenu addItem:[NSMenuItem separatorItem]];
  140. [windowMenu addItemWithTitle:@"Bring All to Front"
  141. action:@selector(arrangeInFront:)
  142. keyEquivalent:@""];
  143. // TODO: Make this appear at the bottom of the menu (for consistency)
  144. [windowMenu addItem:[NSMenuItem separatorItem]];
  145. [[windowMenu addItemWithTitle:@"Enter Full Screen"
  146. action:@selector(toggleFullScreen:)
  147. keyEquivalent:@"f"]
  148. setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand];
  149. // Prior to Snow Leopard, we need to use this oddly-named semi-private API
  150. // to get the application menu working properly.
  151. SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:");
  152. [NSApp performSelector:setAppleMenuSelector withObject:appMenu];
  153. }
  154. // Create key code translation tables
  155. //
  156. static void createKeyTables(void)
  157. {
  158. int scancode;
  159. memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes));
  160. memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes));
  161. _glfw.ns.keycodes[0x1D] = GLFW_KEY_0;
  162. _glfw.ns.keycodes[0x12] = GLFW_KEY_1;
  163. _glfw.ns.keycodes[0x13] = GLFW_KEY_2;
  164. _glfw.ns.keycodes[0x14] = GLFW_KEY_3;
  165. _glfw.ns.keycodes[0x15] = GLFW_KEY_4;
  166. _glfw.ns.keycodes[0x17] = GLFW_KEY_5;
  167. _glfw.ns.keycodes[0x16] = GLFW_KEY_6;
  168. _glfw.ns.keycodes[0x1A] = GLFW_KEY_7;
  169. _glfw.ns.keycodes[0x1C] = GLFW_KEY_8;
  170. _glfw.ns.keycodes[0x19] = GLFW_KEY_9;
  171. _glfw.ns.keycodes[0x00] = GLFW_KEY_A;
  172. _glfw.ns.keycodes[0x0B] = GLFW_KEY_B;
  173. _glfw.ns.keycodes[0x08] = GLFW_KEY_C;
  174. _glfw.ns.keycodes[0x02] = GLFW_KEY_D;
  175. _glfw.ns.keycodes[0x0E] = GLFW_KEY_E;
  176. _glfw.ns.keycodes[0x03] = GLFW_KEY_F;
  177. _glfw.ns.keycodes[0x05] = GLFW_KEY_G;
  178. _glfw.ns.keycodes[0x04] = GLFW_KEY_H;
  179. _glfw.ns.keycodes[0x22] = GLFW_KEY_I;
  180. _glfw.ns.keycodes[0x26] = GLFW_KEY_J;
  181. _glfw.ns.keycodes[0x28] = GLFW_KEY_K;
  182. _glfw.ns.keycodes[0x25] = GLFW_KEY_L;
  183. _glfw.ns.keycodes[0x2E] = GLFW_KEY_M;
  184. _glfw.ns.keycodes[0x2D] = GLFW_KEY_N;
  185. _glfw.ns.keycodes[0x1F] = GLFW_KEY_O;
  186. _glfw.ns.keycodes[0x23] = GLFW_KEY_P;
  187. _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q;
  188. _glfw.ns.keycodes[0x0F] = GLFW_KEY_R;
  189. _glfw.ns.keycodes[0x01] = GLFW_KEY_S;
  190. _glfw.ns.keycodes[0x11] = GLFW_KEY_T;
  191. _glfw.ns.keycodes[0x20] = GLFW_KEY_U;
  192. _glfw.ns.keycodes[0x09] = GLFW_KEY_V;
  193. _glfw.ns.keycodes[0x0D] = GLFW_KEY_W;
  194. _glfw.ns.keycodes[0x07] = GLFW_KEY_X;
  195. _glfw.ns.keycodes[0x10] = GLFW_KEY_Y;
  196. _glfw.ns.keycodes[0x06] = GLFW_KEY_Z;
  197. _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE;
  198. _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH;
  199. _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA;
  200. _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL;
  201. _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT;
  202. _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET;
  203. _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS;
  204. _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD;
  205. _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET;
  206. _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON;
  207. _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH;
  208. _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1;
  209. _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE;
  210. _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK;
  211. _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE;
  212. _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN;
  213. _glfw.ns.keycodes[0x77] = GLFW_KEY_END;
  214. _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER;
  215. _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE;
  216. _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1;
  217. _glfw.ns.keycodes[0x78] = GLFW_KEY_F2;
  218. _glfw.ns.keycodes[0x63] = GLFW_KEY_F3;
  219. _glfw.ns.keycodes[0x76] = GLFW_KEY_F4;
  220. _glfw.ns.keycodes[0x60] = GLFW_KEY_F5;
  221. _glfw.ns.keycodes[0x61] = GLFW_KEY_F6;
  222. _glfw.ns.keycodes[0x62] = GLFW_KEY_F7;
  223. _glfw.ns.keycodes[0x64] = GLFW_KEY_F8;
  224. _glfw.ns.keycodes[0x65] = GLFW_KEY_F9;
  225. _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
  226. _glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
  227. _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
  228. _glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
  229. _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
  230. _glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
  231. _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
  232. _glfw.ns.keycodes[0x40] = GLFW_KEY_F17;
  233. _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18;
  234. _glfw.ns.keycodes[0x50] = GLFW_KEY_F19;
  235. _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20;
  236. _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME;
  237. _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT;
  238. _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT;
  239. _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT;
  240. _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL;
  241. _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT;
  242. _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER;
  243. _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU;
  244. _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK;
  245. _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN;
  246. _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP;
  247. _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT;
  248. _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT;
  249. _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL;
  250. _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT;
  251. _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER;
  252. _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE;
  253. _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB;
  254. _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP;
  255. _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0;
  256. _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1;
  257. _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2;
  258. _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3;
  259. _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4;
  260. _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5;
  261. _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6;
  262. _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7;
  263. _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8;
  264. _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9;
  265. _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD;
  266. _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL;
  267. _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE;
  268. _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER;
  269. _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL;
  270. _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY;
  271. _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT;
  272. for (scancode = 0; scancode < 256; scancode++)
  273. {
  274. // Store the reverse translation for faster key name lookup
  275. if (_glfw.ns.keycodes[scancode] >= 0)
  276. _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode;
  277. }
  278. }
  279. // Retrieve Unicode data for the current keyboard layout
  280. //
  281. static GLFWbool updateUnicodeDataNS(void)
  282. {
  283. if (_glfw.ns.inputSource)
  284. {
  285. CFRelease(_glfw.ns.inputSource);
  286. _glfw.ns.inputSource = NULL;
  287. _glfw.ns.unicodeData = nil;
  288. }
  289. _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource();
  290. if (!_glfw.ns.inputSource)
  291. {
  292. _glfwInputError(GLFW_PLATFORM_ERROR,
  293. "Cocoa: Failed to retrieve keyboard layout input source");
  294. return GLFW_FALSE;
  295. }
  296. _glfw.ns.unicodeData = (id)
  297. TISGetInputSourceProperty(_glfw.ns.inputSource,
  298. kTISPropertyUnicodeKeyLayoutData);
  299. if (!_glfw.ns.unicodeData)
  300. {
  301. _glfwInputError(GLFW_PLATFORM_ERROR,
  302. "Cocoa: Failed to retrieve keyboard layout Unicode data");
  303. return GLFW_FALSE;
  304. }
  305. return GLFW_TRUE;
  306. }
  307. // Load HIToolbox.framework and the TIS symbols we need from it
  308. //
  309. static GLFWbool initializeTIS(void)
  310. {
  311. // This works only because Cocoa has already loaded it properly
  312. _glfw.ns.tis.bundle =
  313. CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox"));
  314. if (!_glfw.ns.tis.bundle)
  315. {
  316. _glfwInputError(GLFW_PLATFORM_ERROR,
  317. "Cocoa: Failed to load HIToolbox.framework");
  318. return GLFW_FALSE;
  319. }
  320. CFStringRef* kPropertyUnicodeKeyLayoutData =
  321. (CFStringRef*)CFBundleGetDataPointerForName(_glfw.ns.tis.bundle,
  322. CFSTR("kTISPropertyUnicodeKeyLayoutData"));
  323. _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = (PFN_TISCopyCurrentKeyboardLayoutInputSource)
  324. CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
  325. CFSTR("TISCopyCurrentKeyboardLayoutInputSource"));
  326. _glfw.ns.tis.GetInputSourceProperty = (PFN_TISGetInputSourceProperty)
  327. CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
  328. CFSTR("TISGetInputSourceProperty"));
  329. _glfw.ns.tis.GetKbdType = (PFN_LMGetKbdType)
  330. CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle,
  331. CFSTR("LMGetKbdType"));
  332. if (!kPropertyUnicodeKeyLayoutData ||
  333. !TISCopyCurrentKeyboardLayoutInputSource ||
  334. !TISGetInputSourceProperty ||
  335. !LMGetKbdType)
  336. {
  337. _glfwInputError(GLFW_PLATFORM_ERROR,
  338. "Cocoa: Failed to load TIS API symbols");
  339. return GLFW_FALSE;
  340. }
  341. _glfw.ns.tis.kPropertyUnicodeKeyLayoutData =
  342. *kPropertyUnicodeKeyLayoutData;
  343. return updateUnicodeDataNS();
  344. }
  345. @interface GLFWHelper : NSObject
  346. @end
  347. @implementation GLFWHelper
  348. - (void)selectedKeyboardInputSourceChanged:(NSObject*)object
  349. {
  350. updateUnicodeDataNS();
  351. }
  352. - (void)doNothing:(id)object
  353. {
  354. }
  355. @end // GLFWHelper
  356. @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate>
  357. @end
  358. @implementation GLFWApplicationDelegate
  359. - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
  360. {
  361. _GLFWwindow* window;
  362. for (window = _glfw.windowListHead; window; window = window->next)
  363. _glfwInputWindowCloseRequest(window);
  364. return NSTerminateCancel;
  365. }
  366. - (void)applicationDidChangeScreenParameters:(NSNotification *) notification
  367. {
  368. _GLFWwindow* window;
  369. for (window = _glfw.windowListHead; window; window = window->next)
  370. {
  371. if (window->context.client != GLFW_NO_API)
  372. [window->context.nsgl.object update];
  373. }
  374. _glfwPollMonitorsNS();
  375. }
  376. - (void)applicationWillFinishLaunching:(NSNotification *)notification
  377. {
  378. if (_glfw.hints.init.ns.menubar)
  379. {
  380. // In case we are unbundled, make us a proper UI application
  381. [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
  382. // Menu bar setup must go between sharedApplication and finishLaunching
  383. // in order to properly emulate the behavior of NSApplicationMain
  384. if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"])
  385. {
  386. [[NSBundle mainBundle] loadNibNamed:@"MainMenu"
  387. owner:NSApp
  388. topLevelObjects:&_glfw.ns.nibObjects];
  389. }
  390. else
  391. createMenuBar();
  392. }
  393. }
  394. - (void)applicationDidFinishLaunching:(NSNotification *)notification
  395. {
  396. _glfwPlatformPostEmptyEvent();
  397. [NSApp stop:nil];
  398. }
  399. - (void)applicationDidHide:(NSNotification *)notification
  400. {
  401. int i;
  402. for (i = 0; i < _glfw.monitorCount; i++)
  403. _glfwRestoreVideoModeNS(_glfw.monitors[i]);
  404. }
  405. @end // GLFWApplicationDelegate
  406. //////////////////////////////////////////////////////////////////////////
  407. ////// GLFW internal API //////
  408. //////////////////////////////////////////////////////////////////////////
  409. void* _glfwLoadLocalVulkanLoaderNS(void)
  410. {
  411. CFBundleRef bundle = CFBundleGetMainBundle();
  412. if (!bundle)
  413. return NULL;
  414. CFURLRef url =
  415. CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
  416. if (!url)
  417. return NULL;
  418. char path[PATH_MAX];
  419. void* handle = NULL;
  420. if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
  421. handle = _glfw_dlopen(path);
  422. CFRelease(url);
  423. return handle;
  424. }
  425. //////////////////////////////////////////////////////////////////////////
  426. ////// GLFW platform API //////
  427. //////////////////////////////////////////////////////////////////////////
  428. int _glfwPlatformInit(void)
  429. {
  430. @autoreleasepool {
  431. _glfw.ns.helper = [[GLFWHelper alloc] init];
  432. [NSThread detachNewThreadSelector:@selector(doNothing:)
  433. toTarget:_glfw.ns.helper
  434. withObject:nil];
  435. [NSApplication sharedApplication];
  436. _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
  437. if (_glfw.ns.delegate == nil)
  438. {
  439. _glfwInputError(GLFW_PLATFORM_ERROR,
  440. "Cocoa: Failed to create application delegate");
  441. return GLFW_FALSE;
  442. }
  443. [NSApp setDelegate:_glfw.ns.delegate];
  444. NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event)
  445. {
  446. if ([event modifierFlags] & NSEventModifierFlagCommand)
  447. [[NSApp keyWindow] sendEvent:event];
  448. return event;
  449. };
  450. _glfw.ns.keyUpMonitor =
  451. [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp
  452. handler:block];
  453. if (_glfw.hints.init.ns.chdir)
  454. changeToResourcesDirectory();
  455. // Press and Hold prevents some keys from emitting repeated characters
  456. NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO};
  457. [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
  458. [[NSNotificationCenter defaultCenter]
  459. addObserver:_glfw.ns.helper
  460. selector:@selector(selectedKeyboardInputSourceChanged:)
  461. name:NSTextInputContextKeyboardSelectionDidChangeNotification
  462. object:nil];
  463. createKeyTables();
  464. _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
  465. if (!_glfw.ns.eventSource)
  466. return GLFW_FALSE;
  467. CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0);
  468. if (!initializeTIS())
  469. return GLFW_FALSE;
  470. _glfwInitTimerNS();
  471. _glfwInitJoysticksNS();
  472. _glfwPollMonitorsNS();
  473. if (![[NSRunningApplication currentApplication] isFinishedLaunching])
  474. [NSApp run];
  475. return GLFW_TRUE;
  476. } // autoreleasepool
  477. }
  478. void _glfwPlatformTerminate(void)
  479. {
  480. @autoreleasepool {
  481. if (_glfw.ns.inputSource)
  482. {
  483. CFRelease(_glfw.ns.inputSource);
  484. _glfw.ns.inputSource = NULL;
  485. _glfw.ns.unicodeData = nil;
  486. }
  487. if (_glfw.ns.eventSource)
  488. {
  489. CFRelease(_glfw.ns.eventSource);
  490. _glfw.ns.eventSource = NULL;
  491. }
  492. if (_glfw.ns.delegate)
  493. {
  494. [NSApp setDelegate:nil];
  495. [_glfw.ns.delegate release];
  496. _glfw.ns.delegate = nil;
  497. }
  498. if (_glfw.ns.helper)
  499. {
  500. [[NSNotificationCenter defaultCenter]
  501. removeObserver:_glfw.ns.helper
  502. name:NSTextInputContextKeyboardSelectionDidChangeNotification
  503. object:nil];
  504. [[NSNotificationCenter defaultCenter]
  505. removeObserver:_glfw.ns.helper];
  506. [_glfw.ns.helper release];
  507. _glfw.ns.helper = nil;
  508. }
  509. if (_glfw.ns.keyUpMonitor)
  510. [NSEvent removeMonitor:_glfw.ns.keyUpMonitor];
  511. free(_glfw.ns.clipboardString);
  512. _glfwTerminateNSGL();
  513. _glfwTerminateJoysticksNS();
  514. } // autoreleasepool
  515. }
  516. const char* _glfwPlatformGetVersionString(void)
  517. {
  518. return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa"
  519. #if defined(_GLFW_BUILD_DLL)
  520. " dynamic"
  521. #endif
  522. ;
  523. }