diff --git a/readme.html b/readme.html index 19e4285d..5ab86c64 100644 --- a/readme.html +++ b/readme.html @@ -310,9 +310,11 @@ version of GLFW.

  • Bugfix: The FSAA test did not check for the availability of GL_ARB_multisample
  • [Cocoa] Added support for OpenGL 3.2 core profile in 10.7 Lion and above
  • [Cocoa] Added support for joysticks
  • +
  • [Cocoa] Postponed menu creation to first window creation
  • [Cocoa] Replaced NSDate time source with mach_absolute_time
  • [Cocoa] Bugfix: The loop condition for saving video modes used the wrong index variable
  • [Cocoa] Bugfix: The OpenGL framework was not retrieved, making glfwGetProcAddress crash
  • +
  • [Cocoa] Bugfix: glfwInit changed the current directory for unbundled executables
  • [X11] Added support for the GLX_EXT_swap_control extension as an alternative to GLX_SGI_swap_control
  • [X11] Added the POSIX CLOCK_MONOTONIC time source as the preferred method
  • [X11] Added dependency on libm, where present
  • diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31cd9fd9..b5569c40 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -19,9 +19,9 @@ set(common_SOURCES error.c fullscreen.c gamma.c init.c input.c joystick.c opengl.c time.c window.c) if(_GLFW_COCOA_NSGL) - set(libglfw_SOURCES ${common_SOURCES} cocoa_fullscreen.m cocoa_gamma.m + set(libglfw_SOURCES ${common_SOURCES} cocoa_fullscreen.m cocoa_gamma.c cocoa_init.m cocoa_input.m cocoa_joystick.m - cocoa_opengl.m cocoa_time.m cocoa_window.m) + cocoa_opengl.m cocoa_time.c cocoa_window.m) # For some reason, CMake doesn't know about .m set_source_files_properties(${libglfw_SOURCES} PROPERTIES LANGUAGE C) diff --git a/src/cocoa_gamma.m b/src/cocoa_gamma.c similarity index 98% rename from src/cocoa_gamma.m rename to src/cocoa_gamma.c index eb291082..53c47a89 100644 --- a/src/cocoa_gamma.m +++ b/src/cocoa_gamma.c @@ -32,6 +32,8 @@ #include #include +#include + //************************************************************************ //**** GLFW internal functions **** diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 2c747515..16ea6e68 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -27,162 +27,44 @@ // //======================================================================== -// Needed for _NSGetProgname -#include - #include "internal.h" //======================================================================== -// GLFW application class +// Change to our application bundle's resources directory, if present //======================================================================== - -@interface GLFWApplication : NSApplication -@end - -@implementation GLFWApplication - -// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost -// This works around an AppKit bug, where key up events while holding -// down the command key don't get sent to the key window. -- (void)sendEvent:(NSEvent *)event +static void changeToResourcesDirectory(void) { - if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) - [[self keyWindow] sendEvent:event]; - else - [super sendEvent:event]; -} + char resourcesPath[MAXPATHLEN]; -@end + CFBundleRef bundle = CFBundleGetMainBundle(); + if (!bundle) + return; + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); -// Prior to Snow Leopard, we need to use this oddly-named semi-private API -// to get the application menu working properly. Need to be careful in -// case it goes away in a future OS update. -@interface NSApplication (NSAppleMenu) -- (void)setAppleMenu:(NSMenu*)m; -@end - -// Keys to search for as potential application names -NSString* GLFWNameKeys[] = -{ - @"CFBundleDisplayName", - @"CFBundleName", - @"CFBundleExecutable", -}; - - -//======================================================================== -// Try to figure out what the calling application is called -//======================================================================== -static NSString* findAppName(void) -{ - unsigned int i; - NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; - - for (i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++) + CFStringRef last = CFURLCopyLastPathComponent(resourcesURL); + if (CFStringCompare(CFSTR("Resources"), last, 0) != kCFCompareEqualTo) { - id name = [infoDictionary objectForKey:GLFWNameKeys[i]]; - if (name && - [name isKindOfClass:[NSString class]] && - ![@"" isEqualToString:name]) - { - return name; - } + CFRelease(last); + CFRelease(resourcesURL); + return; } - // If we get here, we're unbundled - if (!_glfwLibrary.NS.unbundled) + CFRelease(last); + + if (!CFURLGetFileSystemRepresentation(resourcesURL, + true, + (UInt8*) resourcesPath, + MAXPATHLEN)) { - // Could do this only if we discover we're unbundled, but it should - // do no harm... - ProcessSerialNumber psn = { 0, kCurrentProcess }; - TransformProcessType(&psn, kProcessTransformToForegroundApplication); - - // Having the app in front of the terminal window is also generally - // handy. There is an NSApplication API to do this, but... - SetFrontProcess(&psn); - - _glfwLibrary.NS.unbundled = GL_TRUE; + CFRelease(resourcesURL); + return; } - char** progname = _NSGetProgname(); - if (progname && *progname) - { - // TODO: UTF-8? - return [NSString stringWithUTF8String:*progname]; - } + CFRelease(resourcesURL); - // Really shouldn't get here - return @"GLFW Application"; -} - -//======================================================================== -// Set up the menu bar (manually) -// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that -// could go away at any moment, lots of stuff that really should be -// localize(d|able), etc. Loading a nib would save us this horror, but that -// doesn't seem like a good thing to require of GLFW's clients. -//======================================================================== -static void setUpMenuBar(void) -{ - NSString* appName = findAppName(); - - NSMenu* bar = [[NSMenu alloc] init]; - [NSApp setMainMenu:bar]; - - NSMenuItem* appMenuItem = - [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - NSMenu* appMenu = [[NSMenu alloc] init]; - [appMenuItem setSubmenu:appMenu]; - - [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] - action:@selector(orderFrontStandardAboutPanel:) - keyEquivalent:@""]; - [appMenu addItem:[NSMenuItem separatorItem]]; - NSMenu* servicesMenu = [[NSMenu alloc] init]; - [NSApp setServicesMenu:servicesMenu]; - [[appMenu addItemWithTitle:@"Services" - action:NULL - keyEquivalent:@""] setSubmenu:servicesMenu]; - [appMenu addItem:[NSMenuItem separatorItem]]; - [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] - action:@selector(hide:) - keyEquivalent:@"h"]; - [[appMenu addItemWithTitle:@"Hide Others" - action:@selector(hideOtherApplications:) - keyEquivalent:@"h"] - setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; - [appMenu addItemWithTitle:@"Show All" - action:@selector(unhideAllApplications:) - keyEquivalent:@""]; - [appMenu addItem:[NSMenuItem separatorItem]]; - [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] - action:@selector(terminate:) - keyEquivalent:@"q"]; - - NSMenuItem* windowMenuItem = - [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; - NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; - [NSApp setWindowsMenu:windowMenu]; - [windowMenuItem setSubmenu:windowMenu]; - - [windowMenu addItemWithTitle:@"Miniaturize" - action:@selector(performMiniaturize:) - keyEquivalent:@"m"]; - [windowMenu addItemWithTitle:@"Zoom" - action:@selector(performZoom:) - keyEquivalent:@""]; - [windowMenu addItem:[NSMenuItem separatorItem]]; - [windowMenu addItemWithTitle:@"Bring All to Front" - action:@selector(arrangeInFront:) - keyEquivalent:@""]; - - // At least guard the call to private API to avoid an exception if it - // goes away. Hopefully that means the worst we'll break in future is to - // look ugly... - if ([NSApp respondsToSelector:@selector(setAppleMenu:)]) - [NSApp setAppleMenu:appMenu]; + chdir(resourcesPath); } @@ -196,11 +78,6 @@ static void setUpMenuBar(void) int _glfwPlatformInit(void) { - _glfwLibrary.NS.autoreleasePool = [[NSAutoreleasePool alloc] init]; - - // Implicitly create shared NSApplication instance - [GLFWApplication sharedApplication]; - _glfwLibrary.NS.OpenGLFramework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); if (_glfwLibrary.NS.OpenGLFramework == NULL) @@ -210,17 +87,7 @@ int _glfwPlatformInit(void) return GL_FALSE; } - NSString* resourcePath = [[NSBundle mainBundle] resourcePath]; - - if (access([resourcePath cStringUsingEncoding:NSUTF8StringEncoding], R_OK) == 0) - chdir([resourcePath cStringUsingEncoding:NSUTF8StringEncoding]); - - // Setting up menu bar must go exactly here else weirdness ensues - setUpMenuBar(); - - [NSApp finishLaunching]; - - _glfwPlatformSetTime(0.0); + changeToResourcesDirectory(); _glfwLibrary.NS.desktopMode = (NSDictionary*) CGDisplayCurrentMode(CGMainDisplayID()); diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 93492dbb..1a90af01 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -91,7 +91,6 @@ typedef struct _GLFWlibraryNS // dlopen handle for dynamically loading OpenGL extension entry points void* OpenGLFramework; - GLboolean unbundled; id desktopMode; id delegate; id autoreleasePool; diff --git a/src/cocoa_time.m b/src/cocoa_time.c similarity index 100% rename from src/cocoa_time.m rename to src/cocoa_time.c diff --git a/src/cocoa_window.m b/src/cocoa_window.m index b5dfb436..221dcc5e 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -29,6 +29,9 @@ #include "internal.h" +// Needed for _NSGetProgname +#include + //======================================================================== // Delegate for window related notifications @@ -443,6 +446,175 @@ static int convertMacKeyCode(unsigned int macKeyCode) @end +//======================================================================== +// GLFW application class +//======================================================================== + +@interface GLFWApplication : NSApplication +@end + +@implementation GLFWApplication + +// From http://cocoadev.com/index.pl?GameKeyboardHandlingAlmost +// This works around an AppKit bug, where key up events while holding +// down the command key don't get sent to the key window. +- (void)sendEvent:(NSEvent *)event +{ + if ([event type] == NSKeyUp && ([event modifierFlags] & NSCommandKeyMask)) + [[self keyWindow] sendEvent:event]; + else + [super sendEvent:event]; +} + +@end + + +// Prior to Snow Leopard, we need to use this oddly-named semi-private API +// to get the application menu working properly. Need to be careful in +// case it goes away in a future OS update. +@interface NSApplication (NSAppleMenu) +- (void)setAppleMenu:(NSMenu*)m; +@end + +//======================================================================== +// Try to figure out what the calling application is called +//======================================================================== + +static NSString* findAppName(void) +{ + unsigned int i; + NSDictionary* infoDictionary = [[NSBundle mainBundle] infoDictionary]; + + // Keys to search for as potential application names + NSString* GLFWNameKeys[] = + { + @"CFBundleDisplayName", + @"CFBundleName", + @"CFBundleExecutable", + }; + + for (i = 0; i < sizeof(GLFWNameKeys) / sizeof(GLFWNameKeys[0]); i++) + { + id name = [infoDictionary objectForKey:GLFWNameKeys[i]]; + if (name && + [name isKindOfClass:[NSString class]] && + ![@"" isEqualToString:name]) + { + return name; + } + } + + // If we get here, we're unbundled + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + + // Having the app in front of the terminal window is also generally + // handy. There is an NSApplication API to do this, but... + SetFrontProcess(&psn); + + char** progname = _NSGetProgname(); + if (progname && *progname) + { + // TODO: UTF-8? + return [NSString stringWithUTF8String:*progname]; + } + + // Really shouldn't get here + return @"GLFW Application"; +} + +//======================================================================== +// Set up the menu bar (manually) +// This is nasty, nasty stuff -- calls to undocumented semi-private APIs that +// could go away at any moment, lots of stuff that really should be +// localize(d|able), etc. Loading a nib would save us this horror, but that +// doesn't seem like a good thing to require of GLFW's clients. +//======================================================================== +static void setUpMenuBar(void) +{ + NSString* appName = findAppName(); + + NSMenu* bar = [[NSMenu alloc] init]; + [NSApp setMainMenu:bar]; + + NSMenuItem* appMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* appMenu = [[NSMenu alloc] init]; + [appMenuItem setSubmenu:appMenu]; + + [appMenu addItemWithTitle:[NSString stringWithFormat:@"About %@", appName] + action:@selector(orderFrontStandardAboutPanel:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + NSMenu* servicesMenu = [[NSMenu alloc] init]; + [NSApp setServicesMenu:servicesMenu]; + [[appMenu addItemWithTitle:@"Services" + action:NULL + keyEquivalent:@""] setSubmenu:servicesMenu]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Hide %@", appName] + action:@selector(hide:) + keyEquivalent:@"h"]; + [[appMenu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) + keyEquivalent:@"h"] + setKeyEquivalentModifierMask:NSAlternateKeyMask | NSCommandKeyMask]; + [appMenu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) + keyEquivalent:@""]; + [appMenu addItem:[NSMenuItem separatorItem]]; + [appMenu addItemWithTitle:[NSString stringWithFormat:@"Quit %@", appName] + action:@selector(terminate:) + keyEquivalent:@"q"]; + + NSMenuItem* windowMenuItem = + [bar addItemWithTitle:@"" action:NULL keyEquivalent:@""]; + NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + [NSApp setWindowsMenu:windowMenu]; + [windowMenuItem setSubmenu:windowMenu]; + + [windowMenu addItemWithTitle:@"Miniaturize" + action:@selector(performMiniaturize:) + keyEquivalent:@"m"]; + [windowMenu addItemWithTitle:@"Zoom" + action:@selector(performZoom:) + keyEquivalent:@""]; + [windowMenu addItem:[NSMenuItem separatorItem]]; + [windowMenu addItemWithTitle:@"Bring All to Front" + action:@selector(arrangeInFront:) + keyEquivalent:@""]; + + // At least guard the call to private API to avoid an exception if it + // goes away. Hopefully that means the worst we'll break in future is to + // look ugly... + if ([NSApp respondsToSelector:@selector(setAppleMenu:)]) + [NSApp setAppleMenu:appMenu]; +} + + +//======================================================================== +// Initialize the Cocoa Application Kit +//======================================================================== +static GLboolean initializeCocoa(void) +{ + if (NSApp) + return GL_TRUE; + + _glfwLibrary.NS.autoreleasePool = [[NSAutoreleasePool alloc] init]; + + // Implicitly create shared NSApplication instance + [GLFWApplication sharedApplication]; + + // Setting up the menu bar must go between sharedApplication + // above and finishLaunching below, in order to properly emulate the + // behavior of NSApplicationMain + setUpMenuBar(); + + [NSApp finishLaunching]; + + return GL_TRUE; +} + //======================================================================== // Create the Cocoa window //======================================================================== @@ -641,6 +813,9 @@ int _glfwPlatformOpenWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWfbconfig* fbconfig) { + if (!initializeCocoa()) + return GL_FALSE; + // We can only have one application delegate, but we only allocate it the // first time we create a window to keep all window code in this file if (_glfwLibrary.NS.delegate == nil) diff --git a/tests/iconify.c b/tests/iconify.c index 6d001ea5..dbc4d9cf 100644 --- a/tests/iconify.c +++ b/tests/iconify.c @@ -62,6 +62,8 @@ static void key_callback(GLFWwindow window, int key, int action) static void size_callback(GLFWwindow window, int width, int height) { + printf("%0.2f Size %ix%i\n", glfwGetTime(), width, height); + glViewport(0, 0, width, height); }