2007-01-09 18:06:20 +08:00
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and / or modified under
* the terms of the OpenSceneGraph Public License ( OSGPL ) version 0.0 or
* ( at your option ) any later version . The full license is in LICENSE file
* included with this distribution , and on the openscenegraph . org website .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* OpenSceneGraph Public License for more details .
*/
# ifdef __APPLE__
2007-01-13 05:33:19 +08:00
# include <osg/observer_ptr>
2007-01-09 18:06:20 +08:00
# include <osgViewer/GraphicsWindowCarbon>
# include <Carbon/Carbon.h>
# include <OpenGL/OpenGL.h>
using namespace osgViewer ;
// Carbon-Eventhandler to handle the click in the close-widget and the resize of windows
2007-01-13 05:33:19 +08:00
static pascal OSStatus GraphicsWindowEventHandler ( EventHandlerCallRef nextHandler , EventRef event , void * userData )
2007-01-09 18:06:20 +08:00
{
WindowRef window ;
Rect bounds ;
OSStatus result = eventNotHandledErr ; /* report failure by default */
2007-01-13 05:33:19 +08:00
result = CallNextEventHandler ( nextHandler , event ) ;
2007-01-09 18:06:20 +08:00
GraphicsWindowCarbon * w = ( GraphicsWindowCarbon * ) userData ;
if ( ! w )
return result ;
GetEventParameter ( event , kEventParamDirectObject , typeWindowRef , NULL ,
sizeof ( window ) , NULL , & window ) ;
2007-01-13 05:33:19 +08:00
switch ( GetEventClass ( event ) )
{
case kEventClassTablet :
case kEventClassMouse :
if ( w - > handleMouseEvent ( event ) )
2007-01-09 18:06:20 +08:00
result = noErr ;
2007-01-13 05:33:19 +08:00
break ;
case kEventClassKeyboard :
if ( w - > handleKeyboardEvent ( event ) )
2007-01-09 18:06:20 +08:00
result = noErr ;
2007-01-13 05:33:19 +08:00
break ;
case kEventClassWindow : {
switch ( GetEventKind ( event ) )
{
case kEventWindowBoundsChanging :
// left the code for live-resizing, but it is not used, because of window-refreshing issues...
GetEventParameter ( event , kEventParamCurrentBounds , typeQDRectangle , NULL , sizeof ( Rect ) , NULL , & bounds ) ;
w - > resized ( bounds . left , bounds . top , bounds . right - bounds . left , bounds . bottom - bounds . top ) ;
w - > getEventQueue ( ) - > windowResize ( bounds . left , bounds . top , bounds . right - bounds . left , bounds . bottom - bounds . top , w - > getEventQueue ( ) - > getTime ( ) ) ;
w - > requestRedraw ( ) ;
result = noErr ;
break ;
case kEventWindowBoundsChanged :
InvalWindowRect ( window , GetWindowPortBounds ( window , & bounds ) ) ;
GetWindowBounds ( window , kWindowContentRgn , & bounds ) ;
w - > resized ( bounds . left , bounds . top , bounds . right - bounds . left , bounds . bottom - bounds . top ) ;
w - > getEventQueue ( ) - > windowResize ( bounds . left , bounds . top , bounds . right - bounds . left , bounds . bottom - bounds . top , w - > getEventQueue ( ) - > getTime ( ) ) ;
result = noErr ;
break ;
case kEventWindowClosed :
w - > requestClose ( ) ;
break ;
default :
break ;
}
}
default :
break ;
}
2007-01-09 18:06:20 +08:00
return result ;
}
static bool s_quit_requested = false ;
// Application eventhandler -- listens for a quit-event
static pascal OSStatus ApplicationEventHandler ( EventHandlerCallRef inHandlerCallRef , EventRef inEvent , void * inUserData )
{
HICommand commandStruct ;
OSErr err = eventNotHandledErr ;
GetEventParameter ( inEvent , kEventParamDirectObject , typeHICommand , NULL , sizeof ( HICommand ) , NULL , & commandStruct ) ;
switch ( commandStruct . commandID ) {
case kHICommandQuit :
s_quit_requested = true ;
err = noErr ;
break ;
}
return err ;
}
// AppleEventHandler, listens to the Quit-AppleEvent
static pascal OSErr QuitAppleEventHandler ( const AppleEvent * theAppleEvent , AppleEvent * reply , long handlerRefcon ) {
s_quit_requested = true ;
return ( noErr ) ;
}
namespace osgViewer
{
// small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys
class OSXKeyboardMap {
public :
OSXKeyboardMap ( )
{
_keymap [ 53 ] = osgGA : : GUIEventAdapter : : KEY_Escape ;
_keymap [ 115 ] = osgGA : : GUIEventAdapter : : KEY_Home ;
_keymap [ 76 ] = osgGA : : GUIEventAdapter : : KEY_KP_Enter ;
_keymap [ 119 ] = osgGA : : GUIEventAdapter : : KEY_End ;
_keymap [ 36 ] = osgGA : : GUIEventAdapter : : KEY_Return ;
_keymap [ 116 ] = osgGA : : GUIEventAdapter : : KEY_Page_Up ;
_keymap [ 121 ] = osgGA : : GUIEventAdapter : : KEY_Page_Down ;
_keymap [ 123 ] = osgGA : : GUIEventAdapter : : KEY_Left ;
_keymap [ 124 ] = osgGA : : GUIEventAdapter : : KEY_Right ;
_keymap [ 126 ] = osgGA : : GUIEventAdapter : : KEY_Up ;
_keymap [ 125 ] = osgGA : : GUIEventAdapter : : KEY_Down ;
_keymap [ 51 ] = osgGA : : GUIEventAdapter : : KEY_BackSpace ;
_keymap [ 48 ] = osgGA : : GUIEventAdapter : : KEY_Tab ;
_keymap [ 49 ] = osgGA : : GUIEventAdapter : : KEY_Space ;
_keymap [ 117 ] = osgGA : : GUIEventAdapter : : KEY_Delete ;
_keymap [ 122 ] = osgGA : : GUIEventAdapter : : KEY_F1 ;
_keymap [ 120 ] = osgGA : : GUIEventAdapter : : KEY_F2 ;
_keymap [ 99 ] = osgGA : : GUIEventAdapter : : KEY_F3 ;
_keymap [ 118 ] = osgGA : : GUIEventAdapter : : KEY_F4 ;
_keymap [ 96 ] = osgGA : : GUIEventAdapter : : KEY_F5 ;
_keymap [ 97 ] = osgGA : : GUIEventAdapter : : KEY_F6 ;
_keymap [ 98 ] = osgGA : : GUIEventAdapter : : KEY_F7 ;
_keymap [ 100 ] = osgGA : : GUIEventAdapter : : KEY_F8 ;
_keymap [ 101 ] = osgGA : : GUIEventAdapter : : KEY_F9 ;
_keymap [ 109 ] = osgGA : : GUIEventAdapter : : KEY_F10 ;
_keymap [ 103 ] = osgGA : : GUIEventAdapter : : KEY_F11 ;
_keymap [ 111 ] = osgGA : : GUIEventAdapter : : KEY_F12 ;
_keymap [ 75 ] = osgGA : : GUIEventAdapter : : KEY_KP_Divide ;
_keymap [ 67 ] = osgGA : : GUIEventAdapter : : KEY_KP_Multiply ;
_keymap [ 78 ] = osgGA : : GUIEventAdapter : : KEY_KP_Subtract ;
_keymap [ 69 ] = osgGA : : GUIEventAdapter : : KEY_KP_Add ;
_keymap [ 89 ] = osgGA : : GUIEventAdapter : : KEY_KP_Home ;
_keymap [ 91 ] = osgGA : : GUIEventAdapter : : KEY_KP_Up ;
_keymap [ 92 ] = osgGA : : GUIEventAdapter : : KEY_KP_Page_Up ;
_keymap [ 86 ] = osgGA : : GUIEventAdapter : : KEY_KP_Left ;
_keymap [ 87 ] = osgGA : : GUIEventAdapter : : KEY_KP_Begin ;
_keymap [ 88 ] = osgGA : : GUIEventAdapter : : KEY_KP_Right ;
_keymap [ 83 ] = osgGA : : GUIEventAdapter : : KEY_KP_End ;
_keymap [ 84 ] = osgGA : : GUIEventAdapter : : KEY_KP_Down ;
_keymap [ 85 ] = osgGA : : GUIEventAdapter : : KEY_KP_Page_Down ;
_keymap [ 82 ] = osgGA : : GUIEventAdapter : : KEY_KP_Insert ;
_keymap [ 65 ] = osgGA : : GUIEventAdapter : : KEY_KP_Delete ;
}
~ OSXKeyboardMap ( ) {
}
unsigned int remapKey ( unsigned int key , unsigned int rawkey )
{
KeyMap : : iterator itr = _keymap . find ( rawkey ) ;
if ( itr = = _keymap . end ( ) ) return key ;
else return itr - > second ;
}
private :
typedef std : : map < unsigned int , osgGA : : GUIEventAdapter : : KeySymbol > KeyMap ;
KeyMap _keymap ;
} ;
/** remaps a native os x keycode to a GUIEventAdapter-keycode */
static unsigned int remapOSXKey ( unsigned int key , unsigned int rawkey )
{
static OSXKeyboardMap s_OSXKeyboardMap ;
return s_OSXKeyboardMap . remapKey ( key , rawkey ) ;
}
/** creates a pixelformat from a Trait */
static AGLPixelFormat createPixelFormat ( osg : : GraphicsContext : : Traits * traits ) {
std : : vector < GLint > attributes ;
2007-02-07 04:03:13 +08:00
if ( ! traits - > pbuffer ) attributes . push_back ( AGL_NO_RECOVERY ) ;
2007-01-09 18:06:20 +08:00
attributes . push_back ( AGL_RGBA ) ;
2007-02-07 04:03:13 +08:00
if ( ! traits - > pbuffer ) attributes . push_back ( AGL_COMPLIANT ) ;
2007-01-09 18:06:20 +08:00
if ( traits - > doubleBuffer ) attributes . push_back ( AGL_DOUBLEBUFFER ) ;
if ( traits - > quadBufferStereo ) attributes . push_back ( AGL_STEREO ) ;
attributes . push_back ( AGL_RED_SIZE ) ; attributes . push_back ( traits - > red ) ;
attributes . push_back ( AGL_GREEN_SIZE ) ; attributes . push_back ( traits - > green ) ;
attributes . push_back ( AGL_BLUE_SIZE ) ; attributes . push_back ( traits - > blue ) ;
attributes . push_back ( AGL_DEPTH_SIZE ) ; attributes . push_back ( traits - > depth ) ;
if ( traits - > alpha ) { attributes . push_back ( AGL_ALPHA_SIZE ) ; attributes . push_back ( traits - > alpha ) ; }
if ( traits - > stencil ) { attributes . push_back ( AGL_STENCIL_SIZE ) ; attributes . push_back ( traits - > stencil ) ; }
// TODO
// missing accumulation-buffer-stuff
# if defined(AGL_SAMPLE_BUFFERS_ARB) && defined (AGL_SAMPLES_ARB)
if ( traits - > sampleBuffers ) { attributes . push_back ( AGL_SAMPLE_BUFFERS_ARB ) ; attributes . push_back ( traits - > sampleBuffers ) ; }
if ( traits - > sampleBuffers ) { attributes . push_back ( AGL_SAMPLES_ARB ) ; attributes . push_back ( traits - > samples ) ; }
# endif
attributes . push_back ( AGL_NONE ) ;
return aglChoosePixelFormat ( NULL , 0 , & ( attributes . front ( ) ) ) ;
}
2007-01-13 05:33:19 +08:00
# pragma mark * * * GraphicsContextCarbon * * *
2007-01-09 18:06:20 +08:00
/** This is the class we need to create for pbuffers, note its not a GraphicsWindow as it won't need any of the event handling and window mapping facilities.*/
class GraphicsContextCarbon : public osg : : GraphicsContext
{
public :
GraphicsContextCarbon ( osg : : GraphicsContext : : Traits * traits ) :
2007-02-07 04:03:13 +08:00
_valid ( false ) ,
_realized ( false ) ,
_context ( NULL )
2007-01-09 18:06:20 +08:00
{
_traits = traits ;
2007-02-07 04:03:13 +08:00
_valid = true ;
2007-01-09 18:06:20 +08:00
}
virtual bool valid ( ) const { return _valid ; }
/** Realise the GraphicsContext implementation,
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
2007-02-07 04:03:13 +08:00
virtual bool realizeImplementation ( )
{
AGLPixelFormat pixelformat = createPixelFormat ( _traits . get ( ) ) ;
if ( ! pixelformat ) {
osg : : notify ( osg : : WARN ) < < " GraphicsContext::realizeImplementation() aglChoosePixelFormat failed! " < < aglErrorString ( aglGetError ( ) ) < < std : : endl ;
return false ;
}
2007-02-15 20:24:04 +08:00
2007-02-07 04:03:13 +08:00
_context = aglCreateContext ( pixelformat , NULL ) ;
2007-02-15 20:24:04 +08:00
2007-02-07 04:03:13 +08:00
if ( ! _context ) {
osg : : notify ( osg : : WARN ) < < " GraphicsContext::realizeImplementation() aglCreateContext failed! " < < aglErrorString ( aglGetError ( ) ) < < std : : endl ;
return false ;
}
aglDestroyPixelFormat ( pixelformat ) ;
_realized = aglCreatePBuffer ( _traits - > width , _traits - > height , _traits - > target , GL_RGBA , _traits - > level , & ( _pbuffer ) ) ;
if ( ! _realized ) {
osg : : notify ( osg : : WARN ) < < " GraphicsContext::realizeImplementation() aglCreatePBuffer failed! " < < aglErrorString ( aglGetError ( ) ) < < std : : endl ;
}
return _realized ;
}
2007-01-09 18:06:20 +08:00
/** Return true if the graphics context has been realised, and is ready to use, implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
2007-02-07 04:03:13 +08:00
virtual bool isRealizedImplementation ( ) const { return _realized ; }
2007-01-09 18:06:20 +08:00
/** Close the graphics context implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
2007-02-07 04:03:13 +08:00
virtual void closeImplementation ( )
{
if ( _pbuffer ) aglDestroyPBuffer ( _pbuffer ) ;
if ( _context ) aglDestroyContext ( _context ) ;
_valid = _realized = false ;
}
2007-01-09 18:06:20 +08:00
/** Make this graphics context current implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
2007-02-07 04:03:13 +08:00
virtual bool makeCurrentImplementation ( )
{
return ( _realized ) ? ( aglSetCurrentContext ( _context ) = = GL_TRUE ) : false ;
}
2007-01-09 18:06:20 +08:00
/** Make this graphics context current with specified read context implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
virtual bool makeContextCurrentImplementation ( GraphicsContext * /*readContext*/ ) { osg : : notify ( osg : : NOTICE ) < < " GraphicsWindow::makeContextCurrentImplementation(..) not implemented. " < < std : : endl ; return false ; }
/** Release the graphics context.*/
2007-02-07 04:03:13 +08:00
virtual bool releaseContextImplementation ( )
{
return ( aglSetCurrentContext ( NULL ) = = GL_TRUE ) ;
}
2007-01-09 18:06:20 +08:00
/** Pure virtual, Bind the graphics context to associated texture implementation.
* Pure virtual - must be implemented by concrate implementations of GraphicsContext . */
virtual void bindPBufferToTextureImplementation ( GLenum /*buffer*/ ) { osg : : notify ( osg : : NOTICE ) < < " GraphicsWindow::void bindPBufferToTextureImplementation(..) not implemented. " < < std : : endl ; }
/** Swap the front and back buffers implementation.
* Pure virtual - must be implemented by Concrate implementations of GraphicsContext . */
2007-02-07 04:03:13 +08:00
virtual void swapBuffersImplementation ( )
{
aglSwapBuffers ( _context ) ;
}
2007-01-09 18:06:20 +08:00
protected :
bool _valid ;
2007-02-07 04:03:13 +08:00
bool _realized ;
AGLContext _context ;
AGLPbuffer _pbuffer ;
2007-01-09 18:06:20 +08:00
} ;
2007-02-07 04:03:13 +08:00
# pragma mark * * * MenubarController * * *
2007-01-13 05:33:19 +08:00
class MenubarController : public osg : : Referenced
{
public :
MenubarController ( ) : osg : : Referenced ( ) , _list ( ) , _menubarShown ( false ) {
// the following code will query the system for the available ect on the main-display (typically the displaying showing the menubar + the dock
GDHandle mainScreenDevice ;
DMGetGDeviceByDisplayID ( ( DisplayIDType ) CGMainDisplayID ( ) , & mainScreenDevice , true ) ;
GetAvailableWindowPositioningBounds ( mainScreenDevice , & _availRect ) ;
// now we need the rect of the main-display including the menubar and the dock
_mainScreenBounds = CGDisplayBounds ( CGMainDisplayID ( ) ) ;
// hide the menubar initially
SetSystemUIMode ( kUIModeAllHidden , kUIOptionAutoShowMenuBar ) ;
}
static MenubarController * instance ( ) ;
void attachWindow ( GraphicsWindowCarbon * win ) ;
void update ( ) ;
void detachWindow ( GraphicsWindowCarbon * win ) ;
private :
typedef std : : list < osg : : observer_ptr < GraphicsWindowCarbon > > WindowList ;
WindowList _list ;
bool _menubarShown ;
Rect _availRect ;
CGRect _mainScreenBounds ;
} ;
MenubarController * MenubarController : : instance ( )
{
static osg : : ref_ptr < MenubarController > s_menubar_controller = new MenubarController ( ) ;
return s_menubar_controller . get ( ) ;
2007-01-09 18:06:20 +08:00
}
2007-01-13 05:33:19 +08:00
void MenubarController : : attachWindow ( GraphicsWindowCarbon * win )
{
_list . push_back ( win ) ;
update ( ) ;
}
void MenubarController : : detachWindow ( GraphicsWindowCarbon * win )
{
for ( WindowList : : iterator i = _list . begin ( ) ; i ! = _list . end ( ) ; ) {
if ( ( * i ) . get ( ) = = win )
i = _list . erase ( i ) ;
else
+ + i ;
}
update ( ) ;
}
// 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 ( ) ; ) {
if ( ( * i ) . valid ( ) ) {
GraphicsWindowCarbon * w = ( * i ) . get ( ) ;
Rect windowBounds ;
error = GetWindowBounds ( w - > getNativeWindowRef ( ) , kWindowStructureRgn , & windowBounds ) ;
bool intersect = ! ( ( _mainScreenBounds . origin . x > windowBounds . right ) | |
( _mainScreenBounds . origin . x + _mainScreenBounds . size . width < windowBounds . left ) | |
( _mainScreenBounds . origin . y > windowBounds . bottom ) | |
( _mainScreenBounds . origin . y + _mainScreenBounds . size . height < windowBounds . top ) ) ;
if ( intersect & & ! error )
{
+ + windowsIntersectingMainScreen ;
// the window intersects the main-screen, does it intersect with the menubar/dock?
if ( ( ( _availRect . top > _mainScreenBounds . origin . y ) & & ( _availRect . top > windowBounds . top ) ) | |
( ( _availRect . left > _mainScreenBounds . origin . x ) & & ( _availRect . left > windowBounds . left ) ) | |
( ( _availRect . right < _mainScreenBounds . origin . x + _mainScreenBounds . size . width ) & & ( _availRect . right < windowBounds . right ) ) | |
( ( _availRect . bottom < _mainScreenBounds . origin . y + _mainScreenBounds . size . height ) & & ( _availRect . bottom < windowBounds . bottom ) ) )
{
+ + windowsCoveringMenubarArea ;
}
}
+ + i ;
}
else
i = _list . erase ( i ) ;
}
// see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar
if ( windowsCoveringMenubarArea & & _menubarShown )
error = SetSystemUIMode ( kUIModeAllHidden , kUIOptionAutoShowMenuBar ) ;
if ( ! windowsCoveringMenubarArea & & ! _menubarShown )
error = SetSystemUIMode ( kUIModeNormal , 0 ) ;
_menubarShown = ! windowsCoveringMenubarArea ;
// osg::notify(osg::DEBUG_INFO) << "MenubarController:: " << windowsCoveringMenubarArea << " windows covering the menubar/dock area, " << windowsIntersectingMainScreen << " intersecting mainscreen" << std::endl;
}
# pragma mark * * * OSXWindowingSystemInterface * * *
struct OSXCarbonWindowingSystemInterface : public osg : : GraphicsContext : : WindowingSystemInterface
{
/** ctor, get a list of all attached displays */
OSXCarbonWindowingSystemInterface ( ) :
_displayCount ( 0 ) ,
_displayIds ( NULL )
{
2007-02-07 04:03:13 +08:00
ProcessSerialNumber sn = { 0 , kCurrentProcess } ;
TransformProcessType ( & sn , kProcessTransformToForegroundApplication ) ;
SetFrontProcess ( & sn ) ;
2007-01-13 05:33:19 +08:00
if ( CGGetActiveDisplayList ( 0 , NULL , & _displayCount ) ! = CGDisplayNoErr )
osg : : notify ( osg : : WARN ) < < " OSXCarbonWindowingSystemInterface: could not get # of screens " < < std : : endl ;
_displayIds = new CGDirectDisplayID [ _displayCount ] ;
if ( CGGetActiveDisplayList ( _displayCount , _displayIds , & _displayCount ) ! = CGDisplayNoErr )
osg : : notify ( osg : : WARN ) < < " OSXCarbonWindowingSystemInterface: CGGetActiveDisplayList failed " < < std : : endl ;
// register application event handler and AppleEventHandler to get quit-events:
static const EventTypeSpec menueventSpec = { kEventClassCommand , kEventCommandProcess } ;
OSErr status = InstallEventHandler ( GetApplicationEventTarget ( ) , NewEventHandlerUPP ( ApplicationEventHandler ) , 1 , & menueventSpec , 0 , NULL ) ;
status = AEInstallEventHandler ( kCoreEventClass , kAEQuitApplication , NewAEEventHandlerUPP ( QuitAppleEventHandler ) , 0 , false ) ;
}
/** dtor */
~ OSXCarbonWindowingSystemInterface ( ) {
if ( _displayIds )
delete [ ] _displayIds ;
_displayIds = NULL ;
}
/** @return a CGDirectDisplayID for a ScreenIdentifier */
inline CGDirectDisplayID getDisplayID ( const osg : : GraphicsContext : : ScreenIdentifier & si ) {
return _displayIds [ si . screenNum ] ;
}
/** @return count of attached screens */
virtual unsigned int getNumScreens ( const osg : : GraphicsContext : : ScreenIdentifier & si )
{
return _displayCount ;
}
/** returns the resolution of a specific display */
virtual void getScreenResolution ( const osg : : GraphicsContext : : ScreenIdentifier & si , unsigned int & width , unsigned int & height )
{
CGDirectDisplayID id = getDisplayID ( si ) ;
width = CGDisplayPixelsWide ( id ) ;
height = CGDisplayPixelsHigh ( id ) ;
}
/** return the top left coord of a specific screen in global screen space */
void getScreenTopLeft ( const osg : : GraphicsContext : : ScreenIdentifier & si , int & x , int & y ) {
CGRect bounds = CGDisplayBounds ( getDisplayID ( si ) ) ;
x = bounds . origin . x ;
y = bounds . origin . y ;
// osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl;
}
virtual osg : : GraphicsContext * createGraphicsContext ( osg : : GraphicsContext : : Traits * traits )
{
if ( traits - > pbuffer )
{
osg : : ref_ptr < osgViewer : : GraphicsContextCarbon > pbuffer = new GraphicsContextCarbon ( traits ) ;
if ( pbuffer - > valid ( ) ) return pbuffer . release ( ) ;
else return 0 ;
}
else
{
osg : : ref_ptr < osgViewer : : GraphicsWindowCarbon > window = new GraphicsWindowCarbon ( traits ) ;
if ( window - > valid ( ) ) return window . release ( ) ;
else return 0 ;
}
}
private :
CGDisplayCount _displayCount ;
CGDirectDisplayID * _displayIds ;
} ;
}
# pragma mark * * * GraphicsWindowCarbon * * *
2007-01-09 18:06:20 +08:00
void GraphicsWindowCarbon : : setWindowDecoration ( bool flag )
{
_useWindowDecoration = flag ;
}
void GraphicsWindowCarbon : : init ( )
{
_closeRequested = false ;
_context = NULL ;
_window = NULL ;
_pixelFormat = createPixelFormat ( _traits . get ( ) ) ;
if ( ! _pixelFormat )
osg : : notify ( osg : : WARN ) < < " GraphicsWindowCarbon::init could not create a valid pixelformat " < < std : : endl ;
_valid = ( _pixelFormat ! = NULL ) ;
_initialized = true ;
}
bool GraphicsWindowCarbon : : realizeImplementation ( )
{
if ( ! _initialized ) init ( ) ;
if ( ! _initialized ) return false ;
if ( ! _traits ) return false ;
setWindowDecoration ( _traits - > windowDecoration ) ;
2007-01-13 05:33:19 +08:00
// move the window to the right screen
OSXCarbonWindowingSystemInterface * wsi = dynamic_cast < OSXCarbonWindowingSystemInterface * > ( osg : : GraphicsContext : : getWindowingSystemInterface ( ) ) ;
int screenLeft ( 0 ) , screenTop ( 0 ) ;
if ( wsi ) {
wsi - > getScreenTopLeft ( ( * _traits ) , screenLeft , screenTop ) ;
_traits - > y + = screenTop ;
_traits - > x + = screenLeft ;
}
2007-01-09 18:06:20 +08:00
// create the window
Rect bounds = { _traits - > y , _traits - > x , _traits - > y + _traits - > height , _traits - > x + _traits - > width } ;
OSStatus err = 0 ;
WindowAttributes attr ;
2007-01-13 05:33:19 +08:00
if ( _useWindowDecoration )
{
2007-01-09 18:06:20 +08:00
if ( _traits - > supportsResize )
attr = ( kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute ) ;
else
attr = ( kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute ) & ~ kWindowResizableAttribute ;
2007-01-13 05:33:19 +08:00
err = CreateNewWindow ( kDocumentWindowClass , attr , & bounds , & _window ) ;
}
2007-01-09 18:06:20 +08:00
else {
attr = kWindowStandardHandlerAttribute ;
if ( _traits - > supportsResize )
attr | = kWindowResizableAttribute ;
2007-01-13 05:33:19 +08:00
err = CreateNewWindow ( kSimpleWindowClass , attr , & bounds , & _window ) ;
2007-01-09 18:06:20 +08:00
}
2007-01-13 05:33:19 +08:00
2007-01-09 18:06:20 +08:00
if ( err ) {
osg : : notify ( osg : : WARN ) < < " GraphicsWindowCarbon::realizeImplementation() failed creating a window: " < < err < < std : : endl ;
return false ;
}
// register window event handler to receive resize-events
2007-01-13 05:33:19 +08:00
EventTypeSpec windEventList [ ] = {
{ kEventClassWindow , kEventWindowBoundsChanged } ,
{ kEventClassWindow , kEventWindowClosed } ,
{ kEventClassMouse , kEventMouseDown } ,
{ kEventClassMouse , kEventMouseUp } ,
{ kEventClassMouse , kEventMouseMoved } ,
{ kEventClassMouse , kEventMouseDragged } ,
{ kEventClassMouse , kEventMouseWheelMoved } ,
{ kEventClassKeyboard , kEventRawKeyDown } ,
{ kEventClassKeyboard , kEventRawKeyRepeat } ,
{ kEventClassKeyboard , kEventRawKeyUp } ,
{ kEventClassKeyboard , kEventRawKeyModifiersChanged } ,
{ kEventClassKeyboard , kEventHotKeyPressed } ,
{ kEventClassKeyboard , kEventHotKeyReleased } ,
} ;
InstallWindowEventHandler ( _window , NewEventHandlerUPP ( GraphicsWindowEventHandler ) , GetEventTypeCount ( windEventList ) , windEventList , this , NULL ) ;
2007-01-09 18:06:20 +08:00
// set the window title
if ( ! _traits - > windowName . empty ( ) ) {
CFStringRef windowtitle = CFStringCreateWithBytes ( kCFAllocatorDefault , ( const UInt8 * ) ( _traits - > windowName . c_str ( ) ) , _traits - > windowName . length ( ) , kCFStringEncodingUTF8 , false ) ;
SetWindowTitleWithCFString ( _window , windowtitle ) ;
}
// create the context
2007-02-15 20:24:04 +08:00
GraphicsWindowCarbon * sharedContextCarbon = dynamic_cast < GraphicsWindowCarbon * > ( _traits - > sharedContext ) ;
if ( sharedContextCarbon )
{
_context = aglCreateContext ( _pixelFormat , sharedContextCarbon - > getAGLContext ( ) ) ;
}
else
{
_context = aglCreateContext ( _pixelFormat , NULL ) ;
}
2007-01-09 18:06:20 +08:00
if ( ! _context ) {
osg : : notify ( osg : : WARN ) < < " GraphicsWindowCarbon::realizeImplementation failed creating a context: " < < aglGetError ( ) < < std : : endl ;
return false ;
}
makeCurrent ( ) ;
2007-02-07 04:03:13 +08:00
// disabling Multi-threaded OpenGL Execution because it slows down rendering, perhaps we should add a new attribute to traits?
/*
// enable Multi-threaded OpenGL Execution:
CGLError cgerr = kCGLNoError ;
CGLContextObj ctx = CGLGetCurrentContext ( ) ;
2007-01-09 18:06:20 +08:00
2007-02-07 04:03:13 +08:00
cgerr = CGLEnable ( ctx , kCGLCEMPEngine ) ;
if ( cgerr ! = kCGLNoError )
{
osg : : notify ( osg : : INFO ) < < " GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available " < < std : : endl ;
}
*/
2007-01-09 18:06:20 +08:00
aglSetDrawable ( _context , GetWindowPort ( _window ) ) ;
ShowWindow ( _window ) ;
//enable vsync
if ( _traits - > vsync ) {
GLint swap = 1 ;
aglSetInteger ( _context , AGL_SWAP_INTERVAL , & swap ) ;
}
2007-01-13 05:33:19 +08:00
MenubarController : : instance ( ) - > attachWindow ( this ) ;
2007-01-09 18:06:20 +08:00
_realized = true ;
return _realized ;
}
bool GraphicsWindowCarbon : : makeCurrentImplementation ( )
{
return ( aglSetCurrentContext ( _context ) = = GL_TRUE ) ;
}
bool GraphicsWindowCarbon : : releaseContextImplementation ( )
{
if ( ! _realized )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: GraphicsWindow not realized, cannot do makeCurrent. " < < std : : endl ;
return false ;
}
// osg::notify(osg::NOTICE)<<"makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
// osg::notify(osg::NOTICE)<<" glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
return ( aglSetCurrentContext ( NULL ) = = GL_TRUE ) ;
}
void GraphicsWindowCarbon : : closeImplementation ( )
{
_valid = false ;
_realized = false ;
2007-01-13 05:33:19 +08:00
MenubarController : : instance ( ) - > detachWindow ( this ) ;
2007-01-09 18:06:20 +08:00
if ( _pixelFormat )
{
aglDestroyPixelFormat ( _pixelFormat ) ;
_pixelFormat = NULL ;
}
if ( _context )
{
aglSetDrawable ( _context , NULL ) ;
aglSetCurrentContext ( NULL ) ;
aglDestroyContext ( _context ) ;
_context = NULL ;
}
if ( _window ) DisposeWindow ( _window ) ;
_window = NULL ;
}
void GraphicsWindowCarbon : : swapBuffersImplementation ( )
{
aglSwapBuffers ( _context ) ;
}
void GraphicsWindowCarbon : : resizedImplementation ( int x , int y , int width , int height )
{
2007-01-13 05:33:19 +08:00
GraphicsContext : : resizedImplementation ( x , y , width , height ) ;
2007-01-09 18:06:20 +08:00
aglUpdateContext ( _context ) ;
2007-01-13 05:33:19 +08:00
MenubarController : : instance ( ) - > update ( ) ;
2007-01-09 18:06:20 +08:00
}
2007-01-13 05:33:19 +08:00
bool GraphicsWindowCarbon : : handleMouseEvent ( EventRef theEvent )
2007-01-09 18:06:20 +08:00
{
2007-01-13 05:33:19 +08:00
static unsigned int lastEmulatedMouseButton = 0 ;
2007-01-09 18:06:20 +08:00
// mouse down event
Point wheresMyMouse ;
2007-01-13 05:33:19 +08:00
GetEventParameter ( theEvent , kEventParamWindowMouseLocation , typeQDPoint , NULL , sizeof ( wheresMyMouse ) , NULL , & wheresMyMouse ) ;
Point wheresMyMouseGlobal ;
GetEventParameter ( theEvent , kEventParamMouseLocation , typeQDPoint , NULL , sizeof ( wheresMyMouse ) , NULL , & wheresMyMouseGlobal ) ;
2007-01-09 18:06:20 +08:00
EventMouseButton mouseButton = 0 ;
GetEventParameter ( theEvent , kEventParamMouseButton , typeMouseButton , NULL , sizeof ( mouseButton ) , NULL , & mouseButton ) ;
2007-01-13 05:33:19 +08:00
UInt32 modifierKeys ;
GetEventParameter ( theEvent , kEventParamKeyModifiers , typeUInt32 , NULL , sizeof ( modifierKeys ) , NULL , & modifierKeys ) ;
2007-01-09 18:06:20 +08:00
WindowRef win ;
2007-01-13 05:33:19 +08:00
int fwres = FindWindow ( wheresMyMouseGlobal , & win ) ;
if ( ( fwres ! = inContent ) & & ( fwres > 0 ) & & ( mouseButton > = 1 ) )
2007-01-09 18:06:20 +08:00
{
2007-01-13 05:33:19 +08:00
return false ;
2007-01-09 18:06:20 +08:00
}
else
{
2007-01-13 05:33:19 +08:00
2007-01-09 18:06:20 +08:00
// swap right and middle buttons so that middle button is 2, right button is 3.
if ( mouseButton = = 3 ) mouseButton = 2 ;
else if ( mouseButton = = 2 ) mouseButton = 3 ;
// check tablet pointer device and map it to a musebutton
TabletProximityRec theTabletRecord ; // The Tablet Proximity Record
// Extract the Tablet Proximity reccord from the event.
if ( noErr = = GetEventParameter ( theEvent , kEventParamTabletProximityRec ,
typeTabletProximityRec , NULL ,
sizeof ( TabletProximityRec ) ,
NULL , ( void * ) & theTabletRecord ) )
{
osgGA : : GUIEventAdapter : : TabletPointerType pointerType ;
switch ( theTabletRecord . pointerType )
{
case 1 : // pen
pointerType = osgGA : : GUIEventAdapter : : PEN ;
break ;
case 2 : // puck
pointerType = osgGA : : GUIEventAdapter : : PUCK ;
break ;
case 3 : //eraser
pointerType = osgGA : : GUIEventAdapter : : ERASER ;
break ;
default :
pointerType = osgGA : : GUIEventAdapter : : UNKNOWN ;
break ;
}
getEventQueue ( ) - > penProximity ( pointerType , ( theTabletRecord . enterProximity ! = 0 ) ) ;
}
switch ( GetEventKind ( theEvent ) )
{
case kEventMouseDown :
{
float mx = wheresMyMouse . h ;
float my = wheresMyMouse . v ;
transformMouseXY ( mx , my ) ;
2007-01-13 05:33:19 +08:00
lastEmulatedMouseButton = 0 ;
if ( mouseButton = = 1 )
{
if ( modifierKeys & cmdKey )
{
mouseButton = lastEmulatedMouseButton = 3 ;
}
else if ( modifierKeys & optionKey )
{
mouseButton = lastEmulatedMouseButton = 2 ;
}
}
2007-01-09 18:06:20 +08:00
getEventQueue ( ) - > mouseButtonPress ( mx , my , mouseButton ) ;
}
break ;
case kEventMouseUp :
{
float mx = wheresMyMouse . h ;
float my = wheresMyMouse . v ;
transformMouseXY ( mx , my ) ;
2007-01-13 05:33:19 +08:00
if ( lastEmulatedMouseButton > 0 ) {
getEventQueue ( ) - > mouseButtonRelease ( mx , my , lastEmulatedMouseButton ) ;
lastEmulatedMouseButton = 0 ;
}
else {
getEventQueue ( ) - > mouseButtonRelease ( mx , my , mouseButton ) ;
}
2007-01-09 18:06:20 +08:00
}
break ;
case kEventMouseDragged :
{
// get pressure from the pen, only when mouse/pen is dragged
TabletPointRec theTabletRecord ;
if ( noErr = = GetEventParameter ( theEvent , kEventParamTabletPointRec , typeTabletPointRec , NULL ,
sizeof ( TabletPointRec ) , NULL , ( void * ) & theTabletRecord ) ) {
getEventQueue ( ) - > penPressure ( theTabletRecord . pressure / 65535.0f ) ;
}
float mx = wheresMyMouse . h ;
float my = wheresMyMouse . v ;
transformMouseXY ( mx , my ) ;
getEventQueue ( ) - > mouseMotion ( mx , my ) ;
}
break ;
case kEventMouseMoved :
{
float mx = wheresMyMouse . h ;
float my = wheresMyMouse . v ;
transformMouseXY ( mx , my ) ;
getEventQueue ( ) - > mouseMotion ( mx , my ) ;
}
break ;
// mouse with scroll-wheels
case kEventMouseWheelMoved :
{
EventMouseWheelAxis axis ;
SInt32 delta ;
if ( noErr = = GetEventParameter ( theEvent , kEventParamMouseWheelAxis , typeMouseWheelAxis , NULL , sizeof ( axis ) , NULL , & axis ) ) {
if ( noErr = = GetEventParameter ( theEvent , kEventParamMouseWheelDelta , typeLongInteger , NULL , sizeof ( delta ) , NULL , & delta ) ) {
switch ( axis ) {
case kEventMouseWheelAxisX :
getEventQueue ( ) - > mouseScroll ( ( delta > 0 ) ? osgGA : : GUIEventAdapter : : SCROLL_RIGHT : osgGA : : GUIEventAdapter : : SCROLL_LEFT ) ;
break ;
case kEventMouseWheelAxisY :
getEventQueue ( ) - > mouseScroll ( ( delta < 0 ) ? osgGA : : GUIEventAdapter : : SCROLL_DOWN : osgGA : : GUIEventAdapter : : SCROLL_UP ) ;
break ;
}
}
}
}
break ;
// new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html )
case 11 :
{
enum
{
kEventParamMouseWheelSmoothVerticalDelta = ' saxy ' , // typeSInt32
kEventParamMouseWheelSmoothHorizontalDelta = ' saxx ' , // typeSInt32
} ;
SInt32 scroll_delta_x = 0 ;
SInt32 scroll_delta_y = 0 ;
OSErr err = noErr ;
err = GetEventParameter ( theEvent , kEventParamMouseWheelSmoothVerticalDelta , typeLongInteger , NULL , sizeof ( scroll_delta_y ) , NULL , & scroll_delta_y ) ;
err = GetEventParameter ( theEvent , kEventParamMouseWheelSmoothHorizontalDelta , typeLongInteger , NULL , sizeof ( scroll_delta_x ) , NULL , & scroll_delta_x ) ;
if ( ( scroll_delta_x ! = 0 ) | | ( scroll_delta_y ! = 0 ) ) {
getEventQueue ( ) - > mouseScroll2D ( scroll_delta_x , scroll_delta_y ) ;
}
}
break ;
default :
2007-01-13 05:33:19 +08:00
return false ;
2007-01-09 18:06:20 +08:00
}
}
2007-01-13 05:33:19 +08:00
return true ;
2007-01-09 18:06:20 +08:00
}
2007-01-13 05:33:19 +08:00
bool GraphicsWindowCarbon : : handleKeyboardEvent ( EventRef theEvent )
2007-01-09 18:06:20 +08:00
{
OSStatus status ;
// Key modifiers, Numlock not supported...
UInt32 modifierKeys ;
unsigned int modifierMask = 0 ;
GetEventParameter ( theEvent , kEventParamKeyModifiers , typeUInt32 , NULL , sizeof ( modifierKeys ) , NULL , & modifierKeys ) ;
if ( modifierKeys & shiftKey )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_SHIFT ;
}
if ( modifierKeys & alphaLock )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_CAPS_LOCK ;
}
if ( modifierKeys & controlKey )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_CTRL ;
}
if ( modifierKeys & optionKey )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_ALT ;
}
// we map the command-key to the META-key
if ( modifierKeys & cmdKey )
{
modifierMask | = osgGA : : GUIEventAdapter : : MODKEY_META ;
}
UInt32 rawkey ;
GetEventParameter ( theEvent , kEventParamKeyCode , typeUInt32 , NULL , sizeof ( rawkey ) , NULL , & rawkey ) ;
// std::cout << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
UInt32 dataSize ;
/* jbw check return status so that we don't allocate a huge array */
status = GetEventParameter ( theEvent , kEventParamKeyUnicodes , typeUnicodeText , NULL , 0 , & dataSize , NULL ) ;
2007-01-13 05:33:19 +08:00
if ( status ! = noErr ) return false ;
if ( dataSize < = 1 ) return false ;
2007-01-09 18:06:20 +08:00
UniChar * uniChars = new UniChar [ dataSize + 1 ] ;
GetEventParameter ( theEvent , kEventParamKeyUnicodes , typeUnicodeText , NULL , dataSize , NULL , ( void * ) uniChars ) ;
unsigned int keychar = remapOSXKey ( static_cast < unsigned long > ( uniChars [ 0 ] ) , rawkey ) ;
switch ( GetEventKind ( theEvent ) )
{
case kEventRawKeyDown :
case kEventRawKeyRepeat :
{
getEventQueue ( ) - > keyPress ( keychar ) ;
getEventQueue ( ) - > getCurrentEventState ( ) - > setModKeyMask ( modifierMask ) ;
break ;
}
case kEventRawKeyUp :
{
getEventQueue ( ) - > keyRelease ( keychar ) ;
getEventQueue ( ) - > getCurrentEventState ( ) - > setModKeyMask ( modifierMask ) ;
break ;
}
default :
break ;
}
delete [ ] uniChars ;
2007-01-13 05:33:19 +08:00
return true ;
2007-01-09 18:06:20 +08:00
}
void GraphicsWindowCarbon : : checkEvents ( )
{
if ( ! _realized ) return ;
EventRef theEvent ;
EventTargetRef theTarget = GetEventDispatcherTarget ( ) ;
while ( ReceiveNextEvent ( 0 , NULL , 0 , true , & theEvent ) = = noErr )
{
switch ( GetEventClass ( theEvent ) )
{
2007-01-13 05:33:19 +08:00
case kEventClassMouse :
{
// handle the menubar
Point wheresMyMouse ;
GetEventParameter ( theEvent , kEventParamMouseLocation , typeQDPoint , NULL , sizeof ( wheresMyMouse ) , NULL , & wheresMyMouse ) ;
EventMouseButton mouseButton = 0 ;
GetEventParameter ( theEvent , kEventParamMouseButton , typeMouseButton , NULL , sizeof ( mouseButton ) , NULL , & mouseButton ) ;
WindowRef win ;
int fwres = FindWindow ( wheresMyMouse , & win ) ;
if ( ( fwres = = inMenuBar ) & & ( mouseButton > = 1 ) ) {
MenuSelect ( wheresMyMouse ) ;
HiliteMenu ( 0 ) ;
return ;
}
break ;
}
2007-01-09 18:06:20 +08:00
case kEventClassApplication :
switch ( GetEventKind ( theEvent ) ) {
case kEventAppQuit :
getEventQueue ( ) - > quitApplication ( ) ;
break ;
}
break ;
case kEventClassAppleEvent :
{
EventRecord eventRecord ;
ConvertEventRefToEventRecord ( theEvent , & eventRecord ) ;
AEProcessAppleEvent ( & eventRecord ) ;
return ;
}
break ;
}
SendEventToEventTarget ( theEvent , theTarget ) ;
ReleaseEvent ( theEvent ) ;
}
if ( _closeRequested )
close ( true ) ;
if ( s_quit_requested ) {
getEventQueue ( ) - > quitApplication ( ) ;
s_quit_requested = false ;
}
}
void GraphicsWindowCarbon : : grabFocus ( )
{
SelectWindow ( _window ) ;
}
void GraphicsWindowCarbon : : grabFocusIfPointerInWindow ( )
{
// TODO: implement
2007-01-13 05:33:19 +08:00
osg : : notify ( osg : : ALWAYS ) < < " GraphicsWindowCarbon::grabFocusIfPointerInWindow " < < std : : endl ;
2007-01-09 18:06:20 +08:00
}
void GraphicsWindowCarbon : : transformMouseXY ( float & x , float & y )
{
if ( getEventQueue ( ) - > getUseFixedMouseInputRange ( ) )
{
osgGA : : GUIEventAdapter * eventState = getEventQueue ( ) - > getCurrentEventState ( ) ;
x = eventState - > getXmin ( ) + ( eventState - > getXmax ( ) - eventState - > getXmin ( ) ) * x / float ( _traits - > width ) ;
y = eventState - > getYmin ( ) + ( eventState - > getYmax ( ) - eventState - > getYmin ( ) ) * y / float ( _traits - > height ) ;
}
}
struct RegisterWindowingSystemInterfaceProxy
{
RegisterWindowingSystemInterfaceProxy ( )
{
2007-01-13 05:33:19 +08:00
osg : : GraphicsContext : : setWindowingSystemInterface ( new osgViewer : : OSXCarbonWindowingSystemInterface ( ) ) ;
2007-01-09 18:06:20 +08:00
}
~ RegisterWindowingSystemInterfaceProxy ( )
{
osg : : GraphicsContext : : setWindowingSystemInterface ( 0 ) ;
}
} ;
RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy ;
# endif