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