From Stephan Huber, "here are some small fixes/enahncements for the cocoa backend to allow

proper functioning when running the osgViewer run-loop in a secondary
thread (e.g. when embedding GraphicsWindowCocoa-windows in a full blown
cocoa application).

OS X is picky when you want to change the user-interface from another
thread than the main thread, not all UI stuff is thread-safe. So now
window closes and showing / hiding the menu bar is done in the main
thread via Cocoa's performSelectorOnMainThread-mechanism.

These changes don't affect the normal osgViewer usage pattern."
This commit is contained in:
Robert Osfield
2009-06-12 10:00:08 +00:00
parent 4845fe23ae
commit a921031034
2 changed files with 90 additions and 18 deletions

View File

@@ -12,6 +12,39 @@
#include "DarwinUtils.h"
#include <Cocoa/Cocoa.h>
@interface MenubarToggler : NSObject {
}
-(void) show: (ID) data;
-(void) hide: (ID) data;
@end
@implementation MenubarToggler
-(void) hide:(ID) data
{
OSErr error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
if (error) {
osg::notify(osg::DEBUG_INFO) << "MenubarToggler::hide failed with " << error << std::endl;
}
}
-(void) show:(ID) data
{
OSErr error = SetSystemUIMode(kUIModeNormal, 0);
if (error) {
osg::notify(osg::DEBUG_INFO) << "MenubarToggler::show failed with " << error << std::endl;
}
}
@end
namespace osgDarwin {
@@ -83,9 +116,9 @@ void MenubarController::detachWindow(osgViewer::GraphicsWindow* win)
// iterate through all open windows and check, if they intersect the area occupied by the menubar/dock, and if so, hide the menubar/dock
void MenubarController::update()
{
OSErr error(noErr);
unsigned int windowsCoveringMenubarArea = 0;
unsigned int windowsIntersectingMainScreen = 0;
for(WindowList::iterator i = _list.begin(); i != _list.end(); ) {
@@ -115,16 +148,47 @@ void MenubarController::update()
i= _list.erase(i);
}
// see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar
// if we use the cocoa implementation then we have a NSRunLoop in place, and so we can use the deferred menubar-toggling which is thread safe
#ifdef USE_DARWIN_COCOA_IMPLEMENTATION
// SetSystemUIMode is not threadsafe, you'll get crashes if you call this method from other threads
// so use a small NSObject to switch the menubar on the main thread via performSelectorOnMainThread
if (windowsCoveringMenubarArea && _menubarShown)
error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
if (windowsCoveringMenubarArea && _menubarShown)
{
//error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
MenubarToggler* toggler = [[MenubarToggler alloc] init];
[toggler performSelectorOnMainThread: @selector(hide:) withObject:NULL waitUntilDone: YES];
[toggler autorelease];
}
if (!windowsCoveringMenubarArea && !_menubarShown)
{
//error = SetSystemUIMode(kUIModeNormal, 0);
MenubarToggler* toggler = [[MenubarToggler alloc] init];
[toggler performSelectorOnMainThread: @selector(show:) withObject:NULL waitUntilDone: YES];
[toggler autorelease];
}
[pool release];
if (!windowsCoveringMenubarArea && !_menubarShown)
error = SetSystemUIMode(kUIModeNormal, 0);
_menubarShown = !windowsCoveringMenubarArea;
#else
// osg::notify(osg::DEBUG_INFO) << "MenubarController:: " << windowsCoveringMenubarArea << " windows covering the menubar/dock area, " << windowsIntersectingMainScreen << " intersecting mainscreen" << std::endl;
OSErr error;
// see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar
if (windowsCoveringMenubarArea && _menubarShown)
{
error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
}
else
{
error = SetSystemUIMode(kUIModeNormal, 0);
}
#endif
_menubarShown = !windowsCoveringMenubarArea;
}

View File

@@ -19,9 +19,9 @@
#include "DarwinUtils.h"
//#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl;
#define DEBUG_OUT(s) std::cout << "GraphicsWindowCocoa :: " << s << std::endl;
#define DEBUG_OUT(s) ;
//#define DEBUG_OUT(s) ;
static bool s_quit_requested = false;
@@ -388,8 +388,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
- (void) mouseMoved:(NSEvent*)theEvent
{
DEBUG_OUT("Mouse moved");
NSPoint converted_point = [self getLocalPoint: theEvent];
DEBUG_OUT("Mouse moved" << converted_point.x << "/" << converted_point.y);
_win->getEventQueue()->mouseMotion(converted_point.x, converted_point.y);
}
@@ -605,6 +605,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
{
if (!_win) return;
DEBUG_OUT("middleMouseDown ");
NSPoint converted_point = [self getLocalPoint: theEvent];
if([theEvent clickCount] == 1)
@@ -621,6 +623,8 @@ static NSRect convertToQuartzCoordinates(const NSRect& rect)
{
if (!_win) return;
DEBUG_OUT("extraMouseDown btn: " << button_number);
NSPoint converted_point = [self getLocalPoint: theEvent];
if([theEvent clickCount] == 1)
{
@@ -1036,18 +1040,22 @@ void GraphicsWindowCocoa::closeImplementation()
MenubarController* mbc = MenubarController::instance();
if (mbc) mbc->detachWindow(this);
if (_window) {
[_window close];
[_window release];
}
if (_view) {
[_view setGraphicsWindowCocoa: NULL];
}
if (_window) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// we have to close + release the window in the main-thread
[_window performSelectorOnMainThread: @selector(close) withObject:NULL waitUntilDone: YES];
[_window performSelectorOnMainThread: @selector(release) withObject:NULL waitUntilDone: YES];
[pool release];
}
_window = NULL;
_view = NULL;
_view = NULL;
}