From 6a269e24e51cebabe87ab5915ba71fcdef28ac19 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 14 May 2009 15:34:15 +0000 Subject: [PATCH] From Stephan Huber, "attached you'll find some bugfixes and enhancements for the Cocoa implementation of GraoicsWindowCocoa: Enhancements/Bugfixes: + now it's possible to integrate osgViewer better into existing cocoa-applications: * create one or more NSOpenGLView(s) and add these to your window(s) * create one or more NSWindows * disable the integrated event-polling of osgViewer, and let the work be done by Cocoa / NSApplicationRun. You'll have to run the osgViewer's runloop in a separate thread + missing menu-event-handling implemented + added NSAutoReleasePools where necessary, this fixes some memory-leaks + fixed some crashes and thread-issues" --- .../osgViewer/api/Cocoa/GraphicsWindowCocoa | 62 ++-- src/osgViewer/DarwinUtils.h | 16 +- src/osgViewer/DarwinUtils.mm | 14 +- src/osgViewer/GraphicsWindowCocoa.mm | 288 ++++++++++++++++-- 4 files changed, 320 insertions(+), 60 deletions(-) diff --git a/include/osgViewer/api/Cocoa/GraphicsWindowCocoa b/include/osgViewer/api/Cocoa/GraphicsWindowCocoa index 601507f9b..fd11ef64a 100755 --- a/include/osgViewer/api/Cocoa/GraphicsWindowCocoa +++ b/include/osgViewer/api/Cocoa/GraphicsWindowCocoa @@ -23,12 +23,16 @@ #ifdef __OBJC__ @class GraphicsWindowCocoaWindow; +@class GraphicsWindowCocoaGLView; @class NSOpenGLContext; @class NSWindow; +@class NSView; #else +class GraphicsWindowCocoaGLView; class GraphicsWindowCocoaWindow; class NSOpenGLContext; class NSWindow; +class NSView; #endif #include @@ -41,14 +45,18 @@ namespace osgViewer class GraphicsWindowCocoa : public osgViewer::GraphicsWindow { public: - class Implementation; + class Implementation; GraphicsWindowCocoa(osg::GraphicsContext::Traits* traits): _valid(false), _initialized(false), _realized(false), + _closeRequested(false), + _checkForEvents(true), _ownsWindow(true), - _currentCursor(RightArrowCursor) + _currentCursor(RightArrowCursor), + _window(NULL), + _context(NULL) { _traits = traits; @@ -121,26 +129,38 @@ class GraphicsWindowCocoa : public osgViewer::GraphicsWindow class WindowData : public osg::Referenced { public: - WindowData(NSWindow* window) - : _window(window) - { - } - - inline NSWindow* getNativeWindowRef() { return _window; } - - private: - NSWindow* _window; - bool _installEventHandler; + enum Options { CreateOnlyView = 1, CheckForEvents = 2, PoseAsStandaloneApp = 4}; + WindowData(unsigned int options) + : _createOnlyView(options & CreateOnlyView), + _checkForEvents(options & CheckForEvents), + _poseAsStandaloneApp(options & PoseAsStandaloneApp), + _view(NULL) + { + } + + inline NSView* getCreatedNSView() { return _view; } + bool createOnlyView() const { return _createOnlyView; } + bool checkForEvents() const { return _checkForEvents; } + bool poseAsStandaloneApp() const { return _poseAsStandaloneApp; } + protected: + inline void setCreatedNSView(NSView* view) { _view = view; } + + private: + bool _createOnlyView, _checkForEvents, _poseAsStandaloneApp; + NSView* _view; + + friend class GraphicsWindowCocoa; + }; NSOpenGLContext* getContext() { return _context; } GraphicsWindowCocoaWindow* getWindow() { return _window; } void setVSync(bool f); - - /** adapts a resize / move of the window, coords in global screen space */ - void adaptResize(int x, int y, int w, int h); + + /** adapts a resize / move of the window, coords in global screen space */ + void adaptResize(int x, int y, int w, int h); protected: @@ -157,17 +177,17 @@ class GraphicsWindowCocoa : public osgViewer::GraphicsWindow bool _initialized; bool _realized; bool _useWindowDecoration; - bool _ownsWindow; - + private: - bool _closeRequested; - MouseCursor _currentCursor; - GraphicsWindowCocoaWindow* _window; - NSOpenGLContext* _context; + bool _closeRequested, _checkForEvents,_ownsWindow; + MouseCursor _currentCursor; + GraphicsWindowCocoaWindow* _window; + GraphicsWindowCocoaGLView* _view; + NSOpenGLContext* _context; }; } diff --git a/src/osgViewer/DarwinUtils.h b/src/osgViewer/DarwinUtils.h index 3140aef34..bed2ffa4d 100755 --- a/src/osgViewer/DarwinUtils.h +++ b/src/osgViewer/DarwinUtils.h @@ -78,22 +78,26 @@ struct DarwinWindowingSystemInterface : public osg::GraphicsContext::WindowingSy virtual void getScreenSettings(const osg::GraphicsContext::ScreenIdentifier& si, osg::GraphicsContext::ScreenSettings & resolution); virtual void enumerateScreenSettings(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, osg::GraphicsContext::ScreenSettingsList & resolutionList); + + virtual bool setScreenSettings (const osg::GraphicsContext::ScreenIdentifier & si, const osg::GraphicsContext::ScreenSettings & settings); /** return the top left coord of a specific screen in global screen space */ void getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y); - /** implementation of setScreenResolution */ - virtual bool setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) ; - - /** implementation of setScreenRefreshRate */ - virtual bool setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate); - + /** returns screen-ndx containing rect x,y,w,h */ unsigned int getScreenContaining(int x, int y, int w, int h); protected: + /** implementation of setScreenResolution */ + bool setScreenResolutionImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) ; + + /** implementation of setScreenRefreshRate */ + bool setScreenRefreshRateImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate); + + template osg::GraphicsContext* createGraphicsContextImplementation(osg::GraphicsContext::Traits* traits) { diff --git a/src/osgViewer/DarwinUtils.mm b/src/osgViewer/DarwinUtils.mm index 1842d9f3b..ea1a85286 100755 --- a/src/osgViewer/DarwinUtils.mm +++ b/src/osgViewer/DarwinUtils.mm @@ -248,9 +248,19 @@ void DarwinWindowingSystemInterface::getScreenTopLeft(const osg::GraphicsContext } +bool DarwinWindowingSystemInterface::setScreenSettings(const osg::GraphicsContext::ScreenIdentifier &si, const osg::GraphicsContext::ScreenSettings & settings) +{ + bool result = setScreenResolutionImpl(si, settings.width, settings.height); + if (result) + setScreenRefreshRateImpl(si, settings.refreshRate); + + return result; +} + + /** implementation of setScreenResolution */ -bool DarwinWindowingSystemInterface::setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) +bool DarwinWindowingSystemInterface::setScreenResolutionImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height) { CGDirectDisplayID displayID = getDisplayID(screenIdentifier); @@ -270,7 +280,7 @@ bool DarwinWindowingSystemInterface::setScreenResolution(const osg::GraphicsCont } /** implementation of setScreenRefreshRate */ -bool DarwinWindowingSystemInterface::setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) { +bool DarwinWindowingSystemInterface::setScreenRefreshRateImpl(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) { boolean_t success(false); unsigned width, height; diff --git a/src/osgViewer/GraphicsWindowCocoa.mm b/src/osgViewer/GraphicsWindowCocoa.mm index b5b962d08..14a634966 100755 --- a/src/osgViewer/GraphicsWindowCocoa.mm +++ b/src/osgViewer/GraphicsWindowCocoa.mm @@ -7,6 +7,8 @@ * * Some code borrowed from the implementation of CocoaViewer, * Created by Eric Wing on 11/12/06. and ported by Martin Lavery 7/06/07 + * + * Other snippets are borrowed from the Cocoa-implementation of the SDL-lib */ #include @@ -17,9 +19,18 @@ #include "DarwinUtils.h" +//#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl; + +#define DEBUG_OUT(s) ; static bool s_quit_requested = false; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +@interface NSApplication(NSAppleMenu) +- (void)setAppleMenu:(NSMenu *)menu; +@end +#endif + // ---------------------------------------------------------------------------------------------------------- // small helper class remapping key-codes @@ -187,14 +198,20 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; @end @implementation CocoaAppDelegate - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { s_quit_requested = true; - // std::cout << "quit requested " << std::endl; - return NSTerminateNow; + DEBUG_OUT("quit requested "); + return NSTerminateCancel; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + DEBUG_OUT("applicationDidFinishLaunching"); } @end @@ -322,6 +339,11 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) handleModifiers: (NSEvent*)theEvent { + DEBUG_OUT("handling modifiers"); + + if ((!_win) || (!_win->getEventQueue())) + return; // no event queue in place + unsigned int flags = [theEvent modifierFlags]; if (flags == _cachedModifierFlags) @@ -366,6 +388,7 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) mouseMoved:(NSEvent*)theEvent { + DEBUG_OUT("Mouse moved"); NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); } @@ -374,6 +397,7 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) mouseDown:(NSEvent*)theEvent { + DEBUG_OUT("Mouse down"); // Because many Mac users have only a 1-button mouse, we should provide ways // to access the button 2 and 3 actions of osgViewer. // I will use the Ctrl modifer to represent right-clicking @@ -402,6 +426,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) mouseDragged:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); @@ -440,7 +466,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) rightMouseDragged:(NSEvent*)theEvent { - + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); } @@ -472,6 +499,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) otherMouseDragged:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y); @@ -523,6 +552,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doLeftMouseButtonDown:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; if([theEvent clickCount] == 1) @@ -537,6 +568,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doLeftMouseButtonUp:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 1); @@ -545,6 +578,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doRightMouseButtonDown:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; if([theEvent clickCount] == 1) { @@ -560,12 +595,16 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doRightMouseButtonUp:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 3); } - (void) doMiddleMouseButtonDown:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; if([theEvent clickCount] == 1) @@ -580,6 +619,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doExtraMouseButtonDown:(NSEvent*)theEvent buttonNumber:(int)button_number { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; if([theEvent clickCount] == 1) { @@ -594,6 +635,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doMiddleMouseButtonUp:(NSEvent*)theEvent { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, 2); @@ -601,6 +644,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) doExtraMouseButtonUp:(NSEvent*)theEvent buttonNumber:(int)button_number { + if (!_win) return; + NSPoint converted_point = [self getLocalPoint: theEvent]; _win->getEventQueue()->mouseButtonRelease(converted_point.x, converted_point.y, button_number+1); } @@ -609,6 +654,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void) scrollWheel:(NSEvent*)theEvent { + if (!_win) return; + // Unfortunately, it turns out mouseScroll2D doesn't actually do anything. // The camera manipulators don't seem to implement any code that utilize the scroll values. // This this call does nothing. @@ -619,6 +666,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void)keyDown:(NSEvent *)theEvent { + if (!_win) return; + NSString* chars = [theEvent charactersIgnoringModifiers]; unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask) ); // std::cout << "key dn: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl; @@ -628,6 +677,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void)keyUp:(NSEvent *)theEvent { + if (!_win) return; + NSString* chars = [theEvent charactersIgnoringModifiers]; unsigned int keyCode = remapCocoaKey([chars characterAtIndex:0], ([theEvent modifierFlags] & NSFunctionKeyMask)); // std::cout << "key up: " <<[chars characterAtIndex:0] << "=" << keyCode << std::endl; @@ -643,6 +694,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) -(void)handleTabletEvents:(NSEvent *)theEvent { + if (!_win) return; + float pressure = [theEvent pressure]; _win->getEventQueue()->penPressure(pressure); NSPoint tilt = [theEvent tilt]; @@ -653,6 +706,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect) - (void)tabletProximity:(NSEvent *)theEvent { + if (!_win) return; + osgGA::GUIEventAdapter::TabletPointerType pt(osgGA::GUIEventAdapter::UNKNOWN); switch ([theEvent pointingDeviceType]) { case NSPenPointingDevice: @@ -844,16 +899,34 @@ bool GraphicsWindowCocoa::realizeImplementation() NSRect rect = NSMakeRect(_traits->x + screenLeft, _traits->y + screenTop, _traits->width, _traits->height); - _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO]; + _ownsWindow = true; - if (!_window) { - osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl; - return false; - } + // should we create a NSView only?? + WindowData* windowData = _traits->inheritedWindowData ? dynamic_cast(_traits->inheritedWindowData.get()) : NULL; + if (windowData) + { + if (windowData->createOnlyView()) + _ownsWindow = false; + _checkForEvents = windowData->checkForEvents(); + + } - rect = convertFromQuartzCoordinates(rect); - [_window setFrameOrigin: rect.origin]; - + + osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / ownsWindow: " << _ownsWindow << " checkForEvents: " << _checkForEvents << std::endl; + + if (_ownsWindow) + { + _window = [[GraphicsWindowCocoaWindow alloc] initWithContentRect: rect styleMask: style backing: NSBackingStoreBuffered defer: NO]; + + if (!_window) { + osg::notify(osg::WARN) << "GraphicsWindowCocoa::realizeImplementation :: could not create window" << std::endl; + return false; + } + + rect = convertFromQuartzCoordinates(rect); + [_window setFrameOrigin: rect.origin]; + } + NSOpenGLPixelFormatAttribute attr[32]; int i = 0; @@ -913,14 +986,23 @@ bool GraphicsWindowCocoa::realizeImplementation() [theView setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable) ]; [theView setGraphicsWindowCocoa: this]; [theView setOpenGLContext:_context]; - [_window setContentView: theView]; - - setupNSWindow(_window); - - [theView release]; + _view = theView; + osg::notify(osg::DEBUG_INFO) << "GraphicsWindowCocoa::realizeImplementation / view: " << theView << std::endl; + + if (_ownsWindow) { + [_window setContentView: theView]; + setupNSWindow(_window); + [theView release]; + + MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) ); + } + else + { + windowData->setCreatedNSView(theView); + } + [pool release]; - MenubarController::instance()->attachWindow( new CocoaWindowAdapter(this) ); useCursor(_traits->useCursor); setWindowName(_traits->windowName); @@ -950,8 +1032,18 @@ void GraphicsWindowCocoa::closeImplementation() MenubarController* mbc = MenubarController::instance(); if (mbc) mbc->detachWindow(this); - [_window close]; - [_window release]; + if (_window) { + [_window close]; + [_window release]; + } + + if (_view) { + [_view setGraphicsWindowCocoa: NULL]; + } + + _window = NULL; + _view = NULL; + } @@ -993,6 +1085,9 @@ void GraphicsWindowCocoa::swapBuffersImplementation() // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::checkEvents() { + if (!_checkForEvents) + return; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; while(1) @@ -1004,14 +1099,14 @@ void GraphicsWindowCocoa::checkEvents() NSEventTrackingRunLoopMode is in the common set of modes so it may not effectively make much of a difference. */ - NSEvent *event = [ [NSApplication sharedApplication] + NSEvent *event = [ NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue: YES]; if(!event) break; - [[NSApplication sharedApplication] sendEvent: event]; + [NSApp sendEvent: event]; } if (_closeRequested) @@ -1036,7 +1131,9 @@ void GraphicsWindowCocoa::checkEvents() bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag) { - if (!_realized) return false; + if (!_realized || !_ownsWindow) return false; + + NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; unsigned int style(NSBorderlessWindowMask); @@ -1061,6 +1158,8 @@ bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag) [_window makeKeyAndOrderFront: nil]; } + [localPool release]; + return true; } @@ -1070,7 +1169,8 @@ bool GraphicsWindowCocoa::setWindowDecorationImplementation(bool flag) // ---------------------------------------------------------------------------------------------------------- void GraphicsWindowCocoa::grabFocus() { - [_window makeKeyAndOrderFront: nil]; + if (_ownsWindow) + [_window makeKeyAndOrderFront: nil]; } @@ -1089,12 +1189,16 @@ void GraphicsWindowCocoa::grabFocusIfPointerInWindow() void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int height) { - std::cout << "resized implementation" << x << " " << y << " " << width << " " << height << std::endl; + DEBUG_OUT("resized implementation" << x << " " << y << " " << width << " " << height); GraphicsContext::resizedImplementation(x, y, width, height); + + NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; - [_context update]; + if (_context) + [_context update]; MenubarController::instance()->update(); getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime()); + [localPool release]; } @@ -1105,6 +1209,11 @@ void GraphicsWindowCocoa::resizedImplementation(int x, int y, int width, int hei // ---------------------------------------------------------------------------------------------------------- bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int width, int height) { + if (!_ownsWindow) + return false; + + NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; + DarwinWindowingSystemInterface* wsi = dynamic_cast(osg::GraphicsContext::getWindowingSystemInterface()); int screenLeft(0), screenTop(0); if (wsi) { @@ -1119,6 +1228,8 @@ bool GraphicsWindowCocoa::setWindowRectangleImplementation(int x, int y, int wid [_context update]; MenubarController::instance()->update(); + [localPool release]; + return true; } @@ -1154,6 +1265,11 @@ void GraphicsWindowCocoa::adaptResize(int x, int y, int w, int h) void GraphicsWindowCocoa::setWindowName (const std::string & name) { + if (_traits.valid()) _traits->windowName = name; + + if (!_ownsWindow) + return; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSString* title = [NSString stringWithCString: name.c_str() encoding: NSUTF8StringEncoding]; @@ -1200,6 +1316,8 @@ void GraphicsWindowCocoa::useCursor(bool cursorOn) void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor) { + NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; + switch (mouseCursor) { @@ -1222,6 +1340,8 @@ void GraphicsWindowCocoa::setCursor(MouseCursor mouseCursor) default: osg::notify(osg::INFO) << "GraphicsWindowCocoa::setCursor :: unsupported MouseCursor: " << mouseCursor << std::endl; } + + [localPool release]; } @@ -1242,6 +1362,7 @@ void GraphicsWindowCocoa::setVSync(bool f) GraphicsWindowCocoa::~GraphicsWindowCocoa() { + close(); } @@ -1255,27 +1376,132 @@ GraphicsWindowCocoa::~GraphicsWindowCocoa() struct CocoaWindowingSystemInterface : public DarwinWindowingSystemInterface { CocoaWindowingSystemInterface() - : DarwinWindowingSystemInterface() + : DarwinWindowingSystemInterface() + + { + } + + void initAsStandaloneApplication() { - localPool = [[NSAutoreleasePool alloc] init]; - [[NSApplication sharedApplication] setDelegate: [[CocoaAppDelegate alloc] init] ]; + static bool s_inited = false; + if (s_inited) return; + s_inited = true; + + osg::notify(osg::INFO) << "CocoaWindowingSystemInterface::initAsStandaloneApplication " << std::endl; + + ProcessSerialNumber psn; + if (!GetCurrentProcess(&psn)) { + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + } + + NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init]; + + if (NSApp == nil) { + [NSApplication sharedApplication]; + } + + [NSApp setDelegate: [[CocoaAppDelegate alloc] init] ]; + + createApplicationMenus(); + + [NSApp finishLaunching]; + + [localPool release]; } virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits) { + if (!traits->pbuffer) + { + GraphicsWindowCocoa::WindowData* windowData = traits->inheritedWindowData ? dynamic_cast(traits->inheritedWindowData.get()) : NULL; + + if (!windowData || (windowData && windowData->poseAsStandaloneApp())) + { + initAsStandaloneApplication(); + } + } + return createGraphicsContextImplementation(traits); } virtual ~CocoaWindowingSystemInterface() { - [localPool release]; } - NSAutoreleasePool *localPool; +private: + NSString *getApplicationName(void) + { + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; + } + + void createApplicationMenus(void) + { + NSString *appName; + NSString *title; + NSMenu *appleMenu; + NSMenuItem *menuItem; + + /* Create the main menu bar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + + /* Create the application menu */ + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + NSMenu* service_menu = [[NSMenu alloc] init]; + NSMenuItem* service_menu_item = [[NSMenuItem alloc] initWithTitle:@"Services" action:nil keyEquivalent:@""]; + [service_menu_item setSubmenu: service_menu]; + [appleMenu addItem: service_menu_item]; + [NSApp setServicesMenu: service_menu]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@/*"h"*/"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@/*"h"*/""]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@/*"q"*/"q"]; + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + [menuItem release]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + [appleMenu release]; + + + } }; - } #ifdef USE_DARWIN_COCOA_IMPLEMENTATION