mirror of
https://github.com/glfw/glfw.git
synced 2024-11-13 14:03:52 +00:00
Postponed AppKit init to first window creation.
This commit is contained in:
parent
e7f7c19de3
commit
4a9545317e
@ -310,6 +310,7 @@ version of GLFW.</p>
|
|||||||
<li>Bugfix: The FSAA test did not check for the availability of <code>GL_ARB_multisample</code></li>
|
<li>Bugfix: The FSAA test did not check for the availability of <code>GL_ARB_multisample</code></li>
|
||||||
<li>[Cocoa] Added support for OpenGL 3.2 core profile in 10.7 Lion and above</li>
|
<li>[Cocoa] Added support for OpenGL 3.2 core profile in 10.7 Lion and above</li>
|
||||||
<li>[Cocoa] Added support for joysticks</li>
|
<li>[Cocoa] Added support for joysticks</li>
|
||||||
|
<li>[Cocoa] Postponed menu creation to first window creation</li>
|
||||||
<li>[Cocoa] Replaced <code>NSDate</code> time source with <code>mach_absolute_time</code></li>
|
<li>[Cocoa] Replaced <code>NSDate</code> time source with <code>mach_absolute_time</code></li>
|
||||||
<li>[Cocoa] Bugfix: The loop condition for saving video modes used the wrong index variable</li>
|
<li>[Cocoa] Bugfix: The loop condition for saving video modes used the wrong index variable</li>
|
||||||
<li>[Cocoa] Bugfix: The OpenGL framework was not retrieved, making glfwGetProcAddress crash</li>
|
<li>[Cocoa] Bugfix: The OpenGL framework was not retrieved, making glfwGetProcAddress crash</li>
|
||||||
|
183
src/cocoa_init.m
183
src/cocoa_init.m
@ -27,168 +27,39 @@
|
|||||||
//
|
//
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
|
||||||
// Needed for _NSGetProgname
|
|
||||||
#include <crt_externs.h>
|
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Keys to search for as potential application names
|
|
||||||
NSString* GLFWNameKeys[] =
|
|
||||||
{
|
|
||||||
@"CFBundleDisplayName",
|
|
||||||
@"CFBundleName",
|
|
||||||
@"CFBundleExecutable",
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Change to our application bundle's resources directory, if present
|
// Change to our application bundle's resources directory, if present
|
||||||
//========================================================================
|
//========================================================================
|
||||||
static void changeToResourcesDirectory(void)
|
static void changeToResourcesDirectory(void)
|
||||||
{
|
{
|
||||||
char* resourcePath = [[[NSBundle mainBundle] resourcePath] UTF8String];
|
CFBundleRef bundle = CFBundleGetMainBundle();
|
||||||
|
if (!bundle)
|
||||||
|
return;
|
||||||
|
|
||||||
if (access(resourcePath, R_OK) == 0)
|
CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle);
|
||||||
chdir(resourcePath);
|
char resourcesPath[MAXPATHLEN];
|
||||||
|
|
||||||
|
CFStringRef name = CFURLCopyLastPathComponent(resourcesURL);
|
||||||
|
if (CFStringCompare(CFSTR("Resources"), name, 0) != kCFCompareEqualTo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CFRelease(name);
|
||||||
|
|
||||||
|
if (!CFURLGetFileSystemRepresentation(resourcesURL,
|
||||||
|
TRUE,
|
||||||
|
(UInt8*) resourcesPath,
|
||||||
|
MAXPATHLEN));
|
||||||
|
{
|
||||||
|
CFRelease(resourcesURL);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CFRelease(resourcesURL);
|
||||||
|
|
||||||
//========================================================================
|
chdir(resourcesPath);
|
||||||
// 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++)
|
|
||||||
{
|
|
||||||
id name = [infoDictionary objectForKey:GLFWNameKeys[i]];
|
|
||||||
if (name &&
|
|
||||||
[name isKindOfClass:[NSString class]] &&
|
|
||||||
![@"" isEqualToString:name])
|
|
||||||
{
|
|
||||||
_glfwLibrary.NS.bundled = GL_TRUE;
|
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -202,11 +73,6 @@ static void setUpMenuBar(void)
|
|||||||
|
|
||||||
int _glfwPlatformInit(void)
|
int _glfwPlatformInit(void)
|
||||||
{
|
{
|
||||||
_glfwLibrary.NS.autoreleasePool = [[NSAutoreleasePool alloc] init];
|
|
||||||
|
|
||||||
// Implicitly create shared NSApplication instance
|
|
||||||
[GLFWApplication sharedApplication];
|
|
||||||
|
|
||||||
_glfwLibrary.NS.OpenGLFramework =
|
_glfwLibrary.NS.OpenGLFramework =
|
||||||
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||||
if (_glfwLibrary.NS.OpenGLFramework == NULL)
|
if (_glfwLibrary.NS.OpenGLFramework == NULL)
|
||||||
@ -216,13 +82,6 @@ int _glfwPlatformInit(void)
|
|||||||
return GL_FALSE;
|
return GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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];
|
|
||||||
|
|
||||||
if (_glfwLibrary.NS.bundled)
|
if (_glfwLibrary.NS.bundled)
|
||||||
changeToResourcesDirectory();
|
changeToResourcesDirectory();
|
||||||
|
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
|
// Needed for _NSGetProgname
|
||||||
|
#include <crt_externs.h>
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
// Delegate for window related notifications
|
// Delegate for window related notifications
|
||||||
@ -443,6 +446,176 @@ static int convertMacKeyCode(unsigned int macKeyCode)
|
|||||||
|
|
||||||
@end
|
@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])
|
||||||
|
{
|
||||||
|
_glfwLibrary.NS.bundled = GL_TRUE;
|
||||||
|
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
|
// Create the Cocoa window
|
||||||
//========================================================================
|
//========================================================================
|
||||||
@ -641,6 +814,9 @@ int _glfwPlatformOpenWindow(_GLFWwindow* window,
|
|||||||
const _GLFWwndconfig* wndconfig,
|
const _GLFWwndconfig* wndconfig,
|
||||||
const _GLFWfbconfig* fbconfig)
|
const _GLFWfbconfig* fbconfig)
|
||||||
{
|
{
|
||||||
|
if (!initializeCocoa())
|
||||||
|
return GL_FALSE;
|
||||||
|
|
||||||
// We can only have one application delegate, but we only allocate it the
|
// 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
|
// first time we create a window to keep all window code in this file
|
||||||
if (_glfwLibrary.NS.delegate == nil)
|
if (_glfwLibrary.NS.delegate == nil)
|
||||||
|
Loading…
Reference in New Issue
Block a user