| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | #include "internal.h" |
| 30 | #include <sys/param.h> |
| 31 | |
| 32 | |
| 33 | #include <crt_externs.h> |
| 34 | |
| 35 | |
| 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 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | static void createMenuBar(void) |
| 77 | { |
| 78 | size_t i; |
| 79 | NSString* appName = nil; |
| 80 | NSDictionary* bundleInfo = [[NSBundle mainBundle] infoDictionary]; |
| 81 | NSString* nameKeys[] = |
| 82 | { |
| 83 | @"CFBundleDisplayName", |
| 84 | @"CFBundleName", |
| 85 | @"CFBundleExecutable", |
| 86 | }; |
| 87 | |
| 88 | |
| 89 | |
| 90 | for (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 | |
| 164 | [windowMenu addItem:[NSMenuItem separatorItem]]; |
| 165 | [[windowMenu addItemWithTitle:@"Enter Full Screen" |
| 166 | action:@selector(toggleFullScreen:) |
| 167 | keyEquivalent:@"f"] |
| 168 | setKeyEquivalentModifierMask:NSEventModifierFlagControl | NSEventModifierFlagCommand]; |
| 169 | |
| 170 | |
| 171 | |
| 172 | SEL setAppleMenuSelector = NSSelectorFromString(@"setAppleMenu:"); |
| 173 | [NSApp performSelector:setAppleMenuSelector withObject:appMenu]; |
| 174 | } |
| 175 | |
| 176 | |
| 177 | |
| 178 | static void createKeyTables(void) |
| 179 | { |
| 180 | int scancode; |
| 181 | |
| 182 | memset(_glfw.ns.keycodes, -1, sizeof(_glfw.ns.keycodes)); |
| 183 | memset(_glfw.ns.scancodes, -1, sizeof(_glfw.ns.scancodes)); |
| 184 | |
| 185 | _glfw.ns.keycodes[0x1D] = GLFW_KEY_0; |
| 186 | _glfw.ns.keycodes[0x12] = GLFW_KEY_1; |
| 187 | _glfw.ns.keycodes[0x13] = GLFW_KEY_2; |
| 188 | _glfw.ns.keycodes[0x14] = GLFW_KEY_3; |
| 189 | _glfw.ns.keycodes[0x15] = GLFW_KEY_4; |
| 190 | _glfw.ns.keycodes[0x17] = GLFW_KEY_5; |
| 191 | _glfw.ns.keycodes[0x16] = GLFW_KEY_6; |
| 192 | _glfw.ns.keycodes[0x1A] = GLFW_KEY_7; |
| 193 | _glfw.ns.keycodes[0x1C] = GLFW_KEY_8; |
| 194 | _glfw.ns.keycodes[0x19] = GLFW_KEY_9; |
| 195 | _glfw.ns.keycodes[0x00] = GLFW_KEY_A; |
| 196 | _glfw.ns.keycodes[0x0B] = GLFW_KEY_B; |
| 197 | _glfw.ns.keycodes[0x08] = GLFW_KEY_C; |
| 198 | _glfw.ns.keycodes[0x02] = GLFW_KEY_D; |
| 199 | _glfw.ns.keycodes[0x0E] = GLFW_KEY_E; |
| 200 | _glfw.ns.keycodes[0x03] = GLFW_KEY_F; |
| 201 | _glfw.ns.keycodes[0x05] = GLFW_KEY_G; |
| 202 | _glfw.ns.keycodes[0x04] = GLFW_KEY_H; |
| 203 | _glfw.ns.keycodes[0x22] = GLFW_KEY_I; |
| 204 | _glfw.ns.keycodes[0x26] = GLFW_KEY_J; |
| 205 | _glfw.ns.keycodes[0x28] = GLFW_KEY_K; |
| 206 | _glfw.ns.keycodes[0x25] = GLFW_KEY_L; |
| 207 | _glfw.ns.keycodes[0x2E] = GLFW_KEY_M; |
| 208 | _glfw.ns.keycodes[0x2D] = GLFW_KEY_N; |
| 209 | _glfw.ns.keycodes[0x1F] = GLFW_KEY_O; |
| 210 | _glfw.ns.keycodes[0x23] = GLFW_KEY_P; |
| 211 | _glfw.ns.keycodes[0x0C] = GLFW_KEY_Q; |
| 212 | _glfw.ns.keycodes[0x0F] = GLFW_KEY_R; |
| 213 | _glfw.ns.keycodes[0x01] = GLFW_KEY_S; |
| 214 | _glfw.ns.keycodes[0x11] = GLFW_KEY_T; |
| 215 | _glfw.ns.keycodes[0x20] = GLFW_KEY_U; |
| 216 | _glfw.ns.keycodes[0x09] = GLFW_KEY_V; |
| 217 | _glfw.ns.keycodes[0x0D] = GLFW_KEY_W; |
| 218 | _glfw.ns.keycodes[0x07] = GLFW_KEY_X; |
| 219 | _glfw.ns.keycodes[0x10] = GLFW_KEY_Y; |
| 220 | _glfw.ns.keycodes[0x06] = GLFW_KEY_Z; |
| 221 | |
| 222 | _glfw.ns.keycodes[0x27] = GLFW_KEY_APOSTROPHE; |
| 223 | _glfw.ns.keycodes[0x2A] = GLFW_KEY_BACKSLASH; |
| 224 | _glfw.ns.keycodes[0x2B] = GLFW_KEY_COMMA; |
| 225 | _glfw.ns.keycodes[0x18] = GLFW_KEY_EQUAL; |
| 226 | _glfw.ns.keycodes[0x32] = GLFW_KEY_GRAVE_ACCENT; |
| 227 | _glfw.ns.keycodes[0x21] = GLFW_KEY_LEFT_BRACKET; |
| 228 | _glfw.ns.keycodes[0x1B] = GLFW_KEY_MINUS; |
| 229 | _glfw.ns.keycodes[0x2F] = GLFW_KEY_PERIOD; |
| 230 | _glfw.ns.keycodes[0x1E] = GLFW_KEY_RIGHT_BRACKET; |
| 231 | _glfw.ns.keycodes[0x29] = GLFW_KEY_SEMICOLON; |
| 232 | _glfw.ns.keycodes[0x2C] = GLFW_KEY_SLASH; |
| 233 | _glfw.ns.keycodes[0x0A] = GLFW_KEY_WORLD_1; |
| 234 | |
| 235 | _glfw.ns.keycodes[0x33] = GLFW_KEY_BACKSPACE; |
| 236 | _glfw.ns.keycodes[0x39] = GLFW_KEY_CAPS_LOCK; |
| 237 | _glfw.ns.keycodes[0x75] = GLFW_KEY_DELETE; |
| 238 | _glfw.ns.keycodes[0x7D] = GLFW_KEY_DOWN; |
| 239 | _glfw.ns.keycodes[0x77] = GLFW_KEY_END; |
| 240 | _glfw.ns.keycodes[0x24] = GLFW_KEY_ENTER; |
| 241 | _glfw.ns.keycodes[0x35] = GLFW_KEY_ESCAPE; |
| 242 | _glfw.ns.keycodes[0x7A] = GLFW_KEY_F1; |
| 243 | _glfw.ns.keycodes[0x78] = GLFW_KEY_F2; |
| 244 | _glfw.ns.keycodes[0x63] = GLFW_KEY_F3; |
| 245 | _glfw.ns.keycodes[0x76] = GLFW_KEY_F4; |
| 246 | _glfw.ns.keycodes[0x60] = GLFW_KEY_F5; |
| 247 | _glfw.ns.keycodes[0x61] = GLFW_KEY_F6; |
| 248 | _glfw.ns.keycodes[0x62] = GLFW_KEY_F7; |
| 249 | _glfw.ns.keycodes[0x64] = GLFW_KEY_F8; |
| 250 | _glfw.ns.keycodes[0x65] = GLFW_KEY_F9; |
| 251 | _glfw.ns.keycodes[0x6D] = GLFW_KEY_F10; |
| 252 | _glfw.ns.keycodes[0x67] = GLFW_KEY_F11; |
| 253 | _glfw.ns.keycodes[0x6F] = GLFW_KEY_F12; |
| 254 | _glfw.ns.keycodes[0x69] = GLFW_KEY_F13; |
| 255 | _glfw.ns.keycodes[0x6B] = GLFW_KEY_F14; |
| 256 | _glfw.ns.keycodes[0x71] = GLFW_KEY_F15; |
| 257 | _glfw.ns.keycodes[0x6A] = GLFW_KEY_F16; |
| 258 | _glfw.ns.keycodes[0x40] = GLFW_KEY_F17; |
| 259 | _glfw.ns.keycodes[0x4F] = GLFW_KEY_F18; |
| 260 | _glfw.ns.keycodes[0x50] = GLFW_KEY_F19; |
| 261 | _glfw.ns.keycodes[0x5A] = GLFW_KEY_F20; |
| 262 | _glfw.ns.keycodes[0x73] = GLFW_KEY_HOME; |
| 263 | _glfw.ns.keycodes[0x72] = GLFW_KEY_INSERT; |
| 264 | _glfw.ns.keycodes[0x7B] = GLFW_KEY_LEFT; |
| 265 | _glfw.ns.keycodes[0x3A] = GLFW_KEY_LEFT_ALT; |
| 266 | _glfw.ns.keycodes[0x3B] = GLFW_KEY_LEFT_CONTROL; |
| 267 | _glfw.ns.keycodes[0x38] = GLFW_KEY_LEFT_SHIFT; |
| 268 | _glfw.ns.keycodes[0x37] = GLFW_KEY_LEFT_SUPER; |
| 269 | _glfw.ns.keycodes[0x6E] = GLFW_KEY_MENU; |
| 270 | _glfw.ns.keycodes[0x47] = GLFW_KEY_NUM_LOCK; |
| 271 | _glfw.ns.keycodes[0x79] = GLFW_KEY_PAGE_DOWN; |
| 272 | _glfw.ns.keycodes[0x74] = GLFW_KEY_PAGE_UP; |
| 273 | _glfw.ns.keycodes[0x7C] = GLFW_KEY_RIGHT; |
| 274 | _glfw.ns.keycodes[0x3D] = GLFW_KEY_RIGHT_ALT; |
| 275 | _glfw.ns.keycodes[0x3E] = GLFW_KEY_RIGHT_CONTROL; |
| 276 | _glfw.ns.keycodes[0x3C] = GLFW_KEY_RIGHT_SHIFT; |
| 277 | _glfw.ns.keycodes[0x36] = GLFW_KEY_RIGHT_SUPER; |
| 278 | _glfw.ns.keycodes[0x31] = GLFW_KEY_SPACE; |
| 279 | _glfw.ns.keycodes[0x30] = GLFW_KEY_TAB; |
| 280 | _glfw.ns.keycodes[0x7E] = GLFW_KEY_UP; |
| 281 | |
| 282 | _glfw.ns.keycodes[0x52] = GLFW_KEY_KP_0; |
| 283 | _glfw.ns.keycodes[0x53] = GLFW_KEY_KP_1; |
| 284 | _glfw.ns.keycodes[0x54] = GLFW_KEY_KP_2; |
| 285 | _glfw.ns.keycodes[0x55] = GLFW_KEY_KP_3; |
| 286 | _glfw.ns.keycodes[0x56] = GLFW_KEY_KP_4; |
| 287 | _glfw.ns.keycodes[0x57] = GLFW_KEY_KP_5; |
| 288 | _glfw.ns.keycodes[0x58] = GLFW_KEY_KP_6; |
| 289 | _glfw.ns.keycodes[0x59] = GLFW_KEY_KP_7; |
| 290 | _glfw.ns.keycodes[0x5B] = GLFW_KEY_KP_8; |
| 291 | _glfw.ns.keycodes[0x5C] = GLFW_KEY_KP_9; |
| 292 | _glfw.ns.keycodes[0x45] = GLFW_KEY_KP_ADD; |
| 293 | _glfw.ns.keycodes[0x41] = GLFW_KEY_KP_DECIMAL; |
| 294 | _glfw.ns.keycodes[0x4B] = GLFW_KEY_KP_DIVIDE; |
| 295 | _glfw.ns.keycodes[0x4C] = GLFW_KEY_KP_ENTER; |
| 296 | _glfw.ns.keycodes[0x51] = GLFW_KEY_KP_EQUAL; |
| 297 | _glfw.ns.keycodes[0x43] = GLFW_KEY_KP_MULTIPLY; |
| 298 | _glfw.ns.keycodes[0x4E] = GLFW_KEY_KP_SUBTRACT; |
| 299 | |
| 300 | for (scancode = 0; scancode < 256; scancode++) |
| 301 | { |
| 302 | |
| 303 | if (_glfw.ns.keycodes[scancode] >= 0) |
| 304 | _glfw.ns.scancodes[_glfw.ns.keycodes[scancode]] = scancode; |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | |
| 309 | |
| 310 | static GLFWbool updateUnicodeDataNS(void) |
| 311 | { |
| 312 | if (_glfw.ns.inputSource) |
| 313 | { |
| 314 | CFRelease(_glfw.ns.inputSource); |
| 315 | _glfw.ns.inputSource = NULL; |
| 316 | _glfw.ns.unicodeData = nil; |
| 317 | } |
| 318 | |
| 319 | _glfw.ns.inputSource = TISCopyCurrentKeyboardLayoutInputSource(); |
| 320 | if (!_glfw.ns.inputSource) |
| 321 | { |
| 322 | _glfwInputError(GLFW_PLATFORM_ERROR, |
| 323 | "Cocoa: Failed to retrieve keyboard layout input source"); |
| 324 | return GLFW_FALSE; |
| 325 | } |
| 326 | |
| 327 | _glfw.ns.unicodeData = |
| 328 | TISGetInputSourceProperty(_glfw.ns.inputSource, |
| 329 | kTISPropertyUnicodeKeyLayoutData); |
| 330 | if (!_glfw.ns.unicodeData) |
| 331 | { |
| 332 | _glfwInputError(GLFW_PLATFORM_ERROR, |
| 333 | "Cocoa: Failed to retrieve keyboard layout Unicode data"); |
| 334 | return GLFW_FALSE; |
| 335 | } |
| 336 | |
| 337 | return GLFW_TRUE; |
| 338 | } |
| 339 | |
| 340 | |
| 341 | |
| 342 | static GLFWbool initializeTIS(void) |
| 343 | { |
| 344 | |
| 345 | _glfw.ns.tis.bundle = |
| 346 | CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIToolbox")); |
| 347 | if (!_glfw.ns.tis.bundle) |
| 348 | { |
| 349 | _glfwInputError(GLFW_PLATFORM_ERROR, |
| 350 | "Cocoa: Failed to load HIToolbox.framework"); |
| 351 | return GLFW_FALSE; |
| 352 | } |
| 353 | |
| 354 | CFStringRef* kPropertyUnicodeKeyLayoutData = |
| 355 | CFBundleGetDataPointerForName(_glfw.ns.tis.bundle, |
| 356 | CFSTR("kTISPropertyUnicodeKeyLayoutData")); |
| 357 | _glfw.ns.tis.CopyCurrentKeyboardLayoutInputSource = |
| 358 | CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, |
| 359 | CFSTR("TISCopyCurrentKeyboardLayoutInputSource")); |
| 360 | _glfw.ns.tis.GetInputSourceProperty = |
| 361 | CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, |
| 362 | CFSTR("TISGetInputSourceProperty")); |
| 363 | _glfw.ns.tis.GetKbdType = |
| 364 | CFBundleGetFunctionPointerForName(_glfw.ns.tis.bundle, |
| 365 | CFSTR("LMGetKbdType")); |
| 366 | |
| 367 | if (!kPropertyUnicodeKeyLayoutData || |
| 368 | !TISCopyCurrentKeyboardLayoutInputSource || |
| 369 | !TISGetInputSourceProperty || |
| 370 | !LMGetKbdType) |
| 371 | { |
| 372 | _glfwInputError(GLFW_PLATFORM_ERROR, |
| 373 | "Cocoa: Failed to load TIS API symbols"); |
| 374 | return GLFW_FALSE; |
| 375 | } |
| 376 | |
| 377 | _glfw.ns.tis.kPropertyUnicodeKeyLayoutData = |
| 378 | *kPropertyUnicodeKeyLayoutData; |
| 379 | |
| 380 | return updateUnicodeDataNS(); |
| 381 | } |
| 382 | |
| 383 | @interface GLFWHelper : NSObject |
| 384 | @end |
| 385 | |
| 386 | @implementation GLFWHelper |
| 387 | |
| 388 | - (void)selectedKeyboardInputSourceChanged:(NSObject* )object |
| 389 | { |
| 390 | updateUnicodeDataNS(); |
| 391 | } |
| 392 | |
| 393 | - (void)doNothing:(id)object |
| 394 | { |
| 395 | } |
| 396 | |
| 397 | @end |
| 398 | |
| 399 | @interface GLFWApplicationDelegate : NSObject <NSApplicationDelegate> |
| 400 | @end |
| 401 | |
| 402 | @implementation GLFWApplicationDelegate |
| 403 | |
| 404 | - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender |
| 405 | { |
| 406 | _GLFWwindow* window; |
| 407 | |
| 408 | for (window = _glfw.windowListHead; window; window = window->next) |
| 409 | _glfwInputWindowCloseRequest(window); |
| 410 | |
| 411 | return NSTerminateCancel; |
| 412 | } |
| 413 | |
| 414 | - (void)applicationDidChangeScreenParameters:(NSNotification *) notification |
| 415 | { |
| 416 | _GLFWwindow* window; |
| 417 | |
| 418 | for (window = _glfw.windowListHead; window; window = window->next) |
| 419 | { |
| 420 | if (window->context.client != GLFW_NO_API) |
| 421 | [window->context.nsgl.object update]; |
| 422 | } |
| 423 | |
| 424 | _glfwPollMonitorsNS(); |
| 425 | } |
| 426 | |
| 427 | - (void)applicationWillFinishLaunching:(NSNotification *)notification |
| 428 | { |
| 429 | if (_glfw.hints.init.ns.menubar) |
| 430 | { |
| 431 | |
| 432 | [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; |
| 433 | |
| 434 | |
| 435 | |
| 436 | |
| 437 | if ([[NSBundle mainBundle] pathForResource:@"MainMenu" ofType:@"nib"]) |
| 438 | { |
| 439 | [[NSBundle mainBundle] loadNibNamed:@"MainMenu" |
| 440 | owner:NSApp |
| 441 | topLevelObjects:&_glfw.ns.nibObjects]; |
| 442 | } |
| 443 | else |
| 444 | createMenuBar(); |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | - (void)applicationDidFinishLaunching:(NSNotification *)notification |
| 449 | { |
| 450 | _glfw.ns.finishedLaunching = GLFW_TRUE; |
| 451 | _glfwPlatformPostEmptyEvent(); |
| 452 | [NSApp stop:nil]; |
| 453 | } |
| 454 | |
| 455 | - (void)applicationDidHide:(NSNotification *)notification |
| 456 | { |
| 457 | int i; |
| 458 | |
| 459 | for (i = 0; i < _glfw.monitorCount; i++) |
| 460 | _glfwRestoreVideoModeNS(_glfw.monitors[i]); |
| 461 | } |
| 462 | |
| 463 | @end |
| 464 | |
| 465 | |
| 466 | |
| 467 | |
| 468 | |
| 469 | |
| 470 | void* _glfwLoadLocalVulkanLoaderNS(void) |
| 471 | { |
| 472 | CFBundleRef bundle = CFBundleGetMainBundle(); |
| 473 | if (!bundle) |
| 474 | return NULL; |
| 475 | |
| 476 | CFURLRef url = |
| 477 | CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib")); |
| 478 | if (!url) |
| 479 | return NULL; |
| 480 | |
| 481 | char path[PATH_MAX]; |
| 482 | void* handle = NULL; |
| 483 | |
| 484 | if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1)) |
| 485 | handle = _glfw_dlopen(path); |
| 486 | |
| 487 | CFRelease(url); |
| 488 | return handle; |
| 489 | } |
| 490 | |
| 491 | |
| 492 | |
| 493 | |
| 494 | |
| 495 | |
| 496 | int _glfwPlatformInit(void) |
| 497 | { |
| 498 | @autoreleasepool { |
| 499 | |
| 500 | _glfw.ns.helper = [[GLFWHelper alloc] init]; |
| 501 | |
| 502 | [NSThread detachNewThreadSelector:@selector(doNothing:) |
| 503 | toTarget:_glfw.ns.helper |
| 504 | withObject:nil]; |
| 505 | |
| 506 | if (NSApp) |
| 507 | _glfw.ns.finishedLaunching = GLFW_TRUE; |
| 508 | |
| 509 | [NSApplication sharedApplication]; |
| 510 | |
| 511 | _glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init]; |
| 512 | if (_glfw.ns.delegate == nil) |
| 513 | { |
| 514 | _glfwInputError(GLFW_PLATFORM_ERROR, |
| 515 | "Cocoa: Failed to create application delegate"); |
| 516 | return GLFW_FALSE; |
| 517 | } |
| 518 | |
| 519 | [NSApp setDelegate:_glfw.ns.delegate]; |
| 520 | |
| 521 | NSEvent* (^block)(NSEvent*) = ^ NSEvent* (NSEvent* event) |
| 522 | { |
| 523 | if ([event modifierFlags] & NSEventModifierFlagCommand) |
| 524 | [[NSApp keyWindow] sendEvent:event]; |
| 525 | |
| 526 | return event; |
| 527 | }; |
| 528 | |
| 529 | _glfw.ns.keyUpMonitor = |
| 530 | [NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskKeyUp |
| 531 | handler:block]; |
| 532 | |
| 533 | if (_glfw.hints.init.ns.chdir) |
| 534 | changeToResourcesDirectory(); |
| 535 | |
| 536 | |
| 537 | NSDictionary* defaults = @{@"ApplePressAndHoldEnabled":@NO}; |
| 538 | [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; |
| 539 | |
| 540 | [[NSNotificationCenter defaultCenter] |
| 541 | addObserver:_glfw.ns.helper |
| 542 | selector:@selector(selectedKeyboardInputSourceChanged:) |
| 543 | name:NSTextInputContextKeyboardSelectionDidChangeNotification |
| 544 | object:nil]; |
| 545 | |
| 546 | createKeyTables(); |
| 547 | |
| 548 | _glfw.ns.eventSource = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); |
| 549 | if (!_glfw.ns.eventSource) |
| 550 | return GLFW_FALSE; |
| 551 | |
| 552 | CGEventSourceSetLocalEventsSuppressionInterval(_glfw.ns.eventSource, 0.0); |
| 553 | |
| 554 | if (!initializeTIS()) |
| 555 | return GLFW_FALSE; |
| 556 | |
| 557 | _glfwInitTimerNS(); |
| 558 | _glfwInitJoysticksNS(); |
| 559 | |
| 560 | _glfwPollMonitorsNS(); |
| 561 | return GLFW_TRUE; |
| 562 | |
| 563 | } |
| 564 | } |
| 565 | |
| 566 | void _glfwPlatformTerminate(void) |
| 567 | { |
| 568 | @autoreleasepool { |
| 569 | |
| 570 | if (_glfw.ns.inputSource) |
| 571 | { |
| 572 | CFRelease(_glfw.ns.inputSource); |
| 573 | _glfw.ns.inputSource = NULL; |
| 574 | _glfw.ns.unicodeData = nil; |
| 575 | } |
| 576 | |
| 577 | if (_glfw.ns.eventSource) |
| 578 | { |
| 579 | CFRelease(_glfw.ns.eventSource); |
| 580 | _glfw.ns.eventSource = NULL; |
| 581 | } |
| 582 | |
| 583 | if (_glfw.ns.delegate) |
| 584 | { |
| 585 | [NSApp setDelegate:nil]; |
| 586 | [_glfw.ns.delegate release]; |
| 587 | _glfw.ns.delegate = nil; |
| 588 | } |
| 589 | |
| 590 | if (_glfw.ns.helper) |
| 591 | { |
| 592 | [[NSNotificationCenter defaultCenter] |
| 593 | removeObserver:_glfw.ns.helper |
| 594 | name:NSTextInputContextKeyboardSelectionDidChangeNotification |
| 595 | object:nil]; |
| 596 | [[NSNotificationCenter defaultCenter] |
| 597 | removeObserver:_glfw.ns.helper]; |
| 598 | [_glfw.ns.helper release]; |
| 599 | _glfw.ns.helper = nil; |
| 600 | } |
| 601 | |
| 602 | if (_glfw.ns.keyUpMonitor) |
| 603 | [NSEvent removeMonitor:_glfw.ns.keyUpMonitor]; |
| 604 | |
| 605 | free(_glfw.ns.clipboardString); |
| 606 | |
| 607 | _glfwTerminateNSGL(); |
| 608 | _glfwTerminateJoysticksNS(); |
| 609 | |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | const char* _glfwPlatformGetVersionString(void) |
| 614 | { |
| 615 | return _GLFW_VERSION_NUMBER " Cocoa NSGL EGL OSMesa" |
| 616 | #if defined(_GLFW_BUILD_DLL) |
| 617 | " dynamic" |
| 618 | #endif |
| 619 | ; |
| 620 | } |
| 621 | |