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