root/OpenSceneGraph/trunk/src/osgViewer/GraphicsWindowCarbon.cpp @ 7066

Revision 7066, 41.8 kB (checked in by robert, 10 years ago)

Commented out "fix" that explictly sets the key modifier state as this change
actually broke the key modifier state management.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#ifdef __APPLE__
15#include <osg/observer_ptr>
16#include <osgViewer/api/Carbon/PixelBufferCarbon>
17#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
18#include <Carbon/Carbon.h>
19#include <OpenGL/OpenGL.h>
20using namespace osgViewer;
21
22
23// Carbon-Eventhandler to handle the click in the close-widget and the resize of windows
24
25static pascal OSStatus GraphicsWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void* userData)
26{
27    WindowRef           window;
28    Rect                bounds;
29    OSStatus            result = eventNotHandledErr; /* report failure by default */
30   
31   
32    result = CallNextEventHandler (nextHandler, event);
33
34    GraphicsWindowCarbon* w = (GraphicsWindowCarbon*)userData;
35    if (!w)
36        return result;
37   
38    GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL,
39                         sizeof(window), NULL, &window);
40                         
41    switch(GetEventClass(event))
42    {
43        case kEventClassTablet:
44        case kEventClassMouse:
45            if (w->handleMouseEvent(event))
46                result = noErr;
47            break;
48       
49        case kEventClassKeyboard:
50            if (w->handleKeyboardEvent(event))
51                result = noErr;
52            break;
53           
54        case kEventClassWindow: {
55       
56            switch (GetEventKind(event))
57                {
58                    case kEventWindowBoundsChanging:
59                        // left the code for live-resizing, but it is not used, because of window-refreshing issues...
60                        GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &bounds );
61                       
62                        w->resized(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
63                        w->getEventQueue()->windowResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top, w->getEventQueue()->getTime());
64                        w->requestRedraw();
65                        result = noErr;
66                        break;
67                           
68                    case kEventWindowBoundsChanged:
69                        InvalWindowRect(window, GetWindowPortBounds(window, &bounds));
70                        GetWindowBounds(window, kWindowContentRgn, &bounds);
71                        w->resized(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
72                        w->getEventQueue()->windowResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top, w->getEventQueue()->getTime());
73                        result = noErr;
74                        break;
75                   
76                    case kEventWindowClosed:
77                        w->requestClose();
78                        break;
79         
80                    default:
81                        break;
82                }
83            }
84        default:
85            break;
86    }
87    return result;
88}
89
90static bool s_quit_requested = false;
91
92// Application eventhandler -- listens for a quit-event
93static pascal OSStatus ApplicationEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
94{
95   
96    HICommand commandStruct;
97
98    OSErr  err = eventNotHandledErr;
99
100    GetEventParameter (inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &commandStruct);
101
102    switch(commandStruct.commandID) {
103        case kHICommandQuit:
104            s_quit_requested = true;
105            err = noErr;
106            break;
107                   
108    }
109   
110    return err;
111}
112
113// AppleEventHandler, listens to the Quit-AppleEvent
114static pascal OSErr QuitAppleEventHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) {
115    s_quit_requested = true;
116    return (noErr);
117}
118
119
120namespace osgViewer
121{
122
123// small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys
124
125class OSXKeyboardMap {
126
127    public:
128        OSXKeyboardMap()
129        {
130            _keymap[53                ] =  osgGA::GUIEventAdapter::KEY_Escape;
131            _keymap[115                ] =  osgGA::GUIEventAdapter::KEY_Home;
132            _keymap[76                ] =  osgGA::GUIEventAdapter::KEY_KP_Enter;
133            _keymap[119                ] =  osgGA::GUIEventAdapter::KEY_End;
134            _keymap[36                ] =  osgGA::GUIEventAdapter::KEY_Return;
135            _keymap[116                ] =  osgGA::GUIEventAdapter::KEY_Page_Up;
136            _keymap[121                ] = osgGA::GUIEventAdapter::KEY_Page_Down;
137            _keymap[123                ] = osgGA::GUIEventAdapter::KEY_Left;
138            _keymap[124                ] = osgGA::GUIEventAdapter::KEY_Right;
139            _keymap[126                ] = osgGA::GUIEventAdapter::KEY_Up;
140            _keymap[125                ] = osgGA::GUIEventAdapter::KEY_Down;
141            _keymap[51                ] = osgGA::GUIEventAdapter::KEY_BackSpace;
142            _keymap[48                ] = osgGA::GUIEventAdapter::KEY_Tab;
143            _keymap[49                ] = osgGA::GUIEventAdapter::KEY_Space;
144            _keymap[117                ] = osgGA::GUIEventAdapter::KEY_Delete;
145           
146            _keymap[122                    ] = osgGA::GUIEventAdapter::KEY_F1;
147            _keymap[120                    ] = osgGA::GUIEventAdapter::KEY_F2;
148            _keymap[99                    ] = osgGA::GUIEventAdapter::KEY_F3;
149            _keymap[118                    ] = osgGA::GUIEventAdapter::KEY_F4;
150            _keymap[96                    ] = osgGA::GUIEventAdapter::KEY_F5;
151            _keymap[97                    ] = osgGA::GUIEventAdapter::KEY_F6;
152            _keymap[98                    ] = osgGA::GUIEventAdapter::KEY_F7;
153            _keymap[100                    ] = osgGA::GUIEventAdapter::KEY_F8;
154            _keymap[101                    ] = osgGA::GUIEventAdapter::KEY_F9;
155            _keymap[109                    ] = osgGA::GUIEventAdapter::KEY_F10;
156            _keymap[103                    ] = osgGA::GUIEventAdapter::KEY_F11;
157            _keymap[111                    ] = osgGA::GUIEventAdapter::KEY_F12;
158           
159            _keymap[75                    ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
160            _keymap[67                    ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
161            _keymap[78                    ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
162            _keymap[69                    ] = osgGA::GUIEventAdapter::KEY_KP_Add;
163            _keymap[89                    ] = osgGA::GUIEventAdapter::KEY_KP_Home;
164            _keymap[91                    ] = osgGA::GUIEventAdapter::KEY_KP_Up;
165            _keymap[92                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
166            _keymap[86                    ] = osgGA::GUIEventAdapter::KEY_KP_Left;
167            _keymap[87                    ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
168            _keymap[88                    ] = osgGA::GUIEventAdapter::KEY_KP_Right;
169            _keymap[83                    ] = osgGA::GUIEventAdapter::KEY_KP_End;
170            _keymap[84                    ] = osgGA::GUIEventAdapter::KEY_KP_Down;
171            _keymap[85                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
172            _keymap[82                    ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
173            _keymap[65                    ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
174
175        }
176       
177        ~OSXKeyboardMap() {
178        }
179       
180        unsigned int remapKey(unsigned int key, unsigned int rawkey)
181        {
182            KeyMap::iterator itr = _keymap.find(rawkey);
183            if (itr == _keymap.end()) return key;
184            else return itr->second;
185        }
186    private:
187        typedef std::map<unsigned int, osgGA::GUIEventAdapter::KeySymbol> KeyMap;
188        KeyMap _keymap;
189};
190
191/** remaps a native os x keycode to a GUIEventAdapter-keycode */
192static unsigned int remapOSXKey(unsigned int key, unsigned int rawkey)
193{
194    static OSXKeyboardMap s_OSXKeyboardMap;
195    return s_OSXKeyboardMap.remapKey(key,rawkey);
196}
197
198
199
200
201#pragma mark * * * MenubarController * * *
202
203/** the MenubarController class checks all open windows if they intersect with the menubar / dock and hide the menubar/dock if necessary */
204class MenubarController : public osg::Referenced
205{
206
207    public:
208        MenubarController() :
209            osg::Referenced(),
210            _list(),
211            _menubarShown(false)
212        {
213            // the following code will query the system for the available ect on the main-display (typically the displaying showing the menubar + the dock
214
215            GDHandle mainScreenDevice;
216           
217            DMGetGDeviceByDisplayID((DisplayIDType) CGMainDisplayID(), &mainScreenDevice, true);
218            GetAvailableWindowPositioningBounds (mainScreenDevice, &_availRect);
219           
220            // now we need the rect of the main-display including the menubar and the dock
221            _mainScreenBounds = CGDisplayBounds( CGMainDisplayID() );
222           
223            // hide the menubar initially
224            SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
225        }
226       
227        static MenubarController* instance();
228       
229        void attachWindow(GraphicsWindowCarbon* win);
230        void update();
231        void detachWindow(GraphicsWindowCarbon* win);
232       
233    private:
234        typedef std::list< osg::observer_ptr< GraphicsWindowCarbon > > WindowList;
235        WindowList    _list;
236        bool        _menubarShown;
237        Rect        _availRect;
238        CGRect        _mainScreenBounds;
239       
240};
241
242
243MenubarController* MenubarController::instance()
244{
245    static osg::ref_ptr<MenubarController> s_menubar_controller = new MenubarController();
246    return s_menubar_controller.get();
247}
248
249
250void MenubarController::attachWindow(GraphicsWindowCarbon* win)
251{
252    _list.push_back(win);
253    update();
254}
255
256
257void MenubarController::detachWindow(GraphicsWindowCarbon* win)
258{
259    for(WindowList::iterator i = _list.begin(); i != _list.end(); ) {
260        if ((*i).get() == win)
261            i = _list.erase(i);
262        else 
263            ++i;
264    }
265    update();
266}
267
268// iterate through all open windows and check, if they intersect the area occupied by the menubar/dock, and if so, hide the menubar/dock
269
270void MenubarController::update()
271{
272    OSErr error(noErr);
273    unsigned int windowsCoveringMenubarArea = 0;   
274    unsigned int windowsIntersectingMainScreen = 0;
275    for(WindowList::iterator i = _list.begin(); i != _list.end(); ) {
276        if ((*i).valid()) {
277            GraphicsWindowCarbon* w = (*i).get();
278            Rect windowBounds;
279            error = GetWindowBounds(w->getNativeWindowRef(), kWindowStructureRgn, &windowBounds);
280           
281            bool intersect = !( (_mainScreenBounds.origin.x > windowBounds.right) ||
282                                (_mainScreenBounds.origin.x + _mainScreenBounds.size.width < windowBounds.left) ||
283                                (_mainScreenBounds.origin.y > windowBounds.bottom) ||
284                                (_mainScreenBounds.origin.y + _mainScreenBounds.size.height < windowBounds.top));
285            if (intersect && !error)
286            {
287                ++windowsIntersectingMainScreen;
288               
289                // the window intersects the main-screen, does it intersect with the menubar/dock?
290                if (((_availRect.top > _mainScreenBounds.origin.y) && (_availRect.top > windowBounds.top)) ||
291                    ((_availRect.left > _mainScreenBounds.origin.x) && (_availRect.left > windowBounds.left)) ||
292                    ((_availRect.right < _mainScreenBounds.origin.x + _mainScreenBounds.size.width) && (_availRect.right < windowBounds.right)) ||
293                    ((_availRect.bottom < _mainScreenBounds.origin.y + _mainScreenBounds.size.height) && (_availRect.bottom < windowBounds.bottom) ))
294                {
295                    ++windowsCoveringMenubarArea;
296                }
297            }
298           
299            ++i;
300        }
301        else
302            i= _list.erase(i);
303    }
304   
305    // see http://developer.apple.com/technotes/tn2002/tn2062.html for hiding the dock+menubar
306       
307    if (windowsCoveringMenubarArea && _menubarShown)
308        error = SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
309   
310    if (!windowsCoveringMenubarArea && !_menubarShown)
311        error = SetSystemUIMode(kUIModeNormal, 0);
312        _menubarShown = !windowsCoveringMenubarArea;
313   
314    // osg::notify(osg::DEBUG_INFO) << "MenubarController:: " << windowsCoveringMenubarArea << " windows covering the menubar/dock area, " << windowsIntersectingMainScreen << " intersecting mainscreen" << std::endl;
315}
316
317
318#pragma mark * * * OSXWindowingSystemInterface * * *
319
320struct OSXCarbonWindowingSystemInterface : public osg::GraphicsContext::WindowingSystemInterface
321{
322   
323    /** ctor, get a list of all attached displays */
324    OSXCarbonWindowingSystemInterface() :
325        _displayCount(0),
326        _displayIds(NULL)
327    {
328        ProcessSerialNumber sn = { 0, kCurrentProcess };
329        TransformProcessType(&sn,kProcessTransformToForegroundApplication);
330        SetFrontProcess(&sn);
331       
332        if( CGGetActiveDisplayList( 0, NULL, &_displayCount ) != CGDisplayNoErr )
333            osg::notify(osg::WARN) << "OSXCarbonWindowingSystemInterface: could not get # of screens" << std::endl;
334           
335        _displayIds = new CGDirectDisplayID[_displayCount];
336        if( CGGetActiveDisplayList( _displayCount, _displayIds, &_displayCount ) != CGDisplayNoErr )
337            osg::notify(osg::WARN) << "OSXCarbonWindowingSystemInterface: CGGetActiveDisplayList failed" << std::endl;
338       
339        // register application event handler and AppleEventHandler to get quit-events:
340        static const EventTypeSpec menueventSpec = {kEventClassCommand, kEventCommandProcess};
341        OSErr status = InstallEventHandler(GetApplicationEventTarget(), NewEventHandlerUPP(ApplicationEventHandler), 1, &menueventSpec, 0, NULL);
342        status = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false);
343    }
344   
345    /** dtor */
346    ~OSXCarbonWindowingSystemInterface() {
347        if (_displayIds)
348            delete[] _displayIds;
349        _displayIds = NULL;
350    }
351   
352    /** @return a CGDirectDisplayID for a ScreenIdentifier */
353    inline CGDirectDisplayID getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si) {
354        if (si.screenNum < _displayCount)
355            return _displayIds[si.screenNum];
356        else {
357            osg::notify(osg::WARN) << "GraphicsWindowCarbon :: invalid screen # " << si.screenNum << ", returning main-screen instead" << std::endl;
358            return _displayIds[0];
359        }
360    }
361
362    /** @return count of attached screens */
363    virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si)
364    {
365        return _displayCount;
366    }
367
368    /** returns the resolution of a specific display */
369    virtual void getScreenResolution(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height)
370    {
371        CGDirectDisplayID id = getDisplayID(si);
372        width = CGDisplayPixelsWide(id);
373        height = CGDisplayPixelsHigh(id);
374    }
375   
376    /** return the top left coord of a specific screen in global screen space */
377    void getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y) {
378        CGRect bounds = CGDisplayBounds( getDisplayID(si) );
379        x = static_cast<int>(bounds.origin.x);
380        y = static_cast<int>(bounds.origin.y);
381       
382        // osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl;
383    }
384   
385    /** helper method to get a value out of a CFDictionary */
386    static double getDictDouble (CFDictionaryRef refDict, CFStringRef key)
387    {
388       double double_value;
389       CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key);
390       if (!number_value) // if can't get a number for the dictionary
391           return -1;  // fail
392       if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it
393            return -1; // fail
394        return double_value; // otherwise return the long value
395    }
396
397   
398    /** implementation of setScreenResolution */
399    virtual bool setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height)
400    {
401        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
402       
403        // add next line and on following line replace hard coded depth and refresh rate
404        CGRefreshRate refresh =  getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); 
405        CFDictionaryRef display_mode_values =
406            CGDisplayBestModeForParametersAndRefreshRate(
407                            displayID,
408                            CGDisplayBitsPerPixel(displayID),
409                            width, height, 
410                            refresh, 
411                            NULL);
412
413                                         
414        CGDisplaySwitchToMode(displayID, display_mode_values);   
415        return true;
416    }
417   
418    /** implementation of setScreenRefreshRate */
419    virtual bool setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) {
420       
421        boolean_t  success(false);
422        unsigned width, height;
423        getScreenResolution(screenIdentifier, width, height);
424       
425        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
426       
427        // add next line and on following line replace hard coded depth and refresh rate
428        CFDictionaryRef display_mode_values =
429            CGDisplayBestModeForParametersAndRefreshRate(
430                            displayID,
431                            CGDisplayBitsPerPixel(displayID),
432                            width, height, 
433                            refreshRate, 
434                            &success);
435
436                                         
437        if (success)
438            CGDisplaySwitchToMode(displayID, display_mode_values);   
439           
440        return (success != 0);
441    }
442
443       
444   
445    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
446    {
447        if (traits->pbuffer)
448        {
449            osg::ref_ptr<osgViewer::PixelBufferCarbon> pbuffer = new PixelBufferCarbon(traits);
450            if (pbuffer->valid()) return pbuffer.release();
451            else return 0;
452        }
453        else
454        {
455            osg::ref_ptr<osgViewer::GraphicsWindowCarbon> window = new GraphicsWindowCarbon(traits);
456            if (window->valid()) return window.release();
457            else return 0;
458        }
459    }
460   
461   
462   
463    private:
464        CGDisplayCount        _displayCount;
465        CGDirectDisplayID*    _displayIds;
466};
467
468}
469
470
471#pragma mark * * * GraphicsWindowCarbon * * *
472
473
474
475
476void GraphicsWindowCarbon::init()
477{
478    _windowTitleHeight = 0;
479    _closeRequested = false;
480    _ownsWindow = false;
481    _context = NULL;
482    _window = NULL;
483    _pixelFormat = PixelBufferCarbon::createPixelFormat(_traits.get());
484    if (!_pixelFormat)
485        osg::notify(osg::WARN) << "GraphicsWindowCarbon::init could not create a valid pixelformat" << std::endl;
486    _valid = (_pixelFormat != NULL);
487    _initialized = true;
488}
489
490bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag)
491{
492    _useWindowDecoration = flag;
493
494    if (_realized)
495    {
496        OSErr err = noErr;
497        Rect bounds;
498        GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
499
500        if (_useWindowDecoration)
501        {
502            err = ChangeWindowAttributes(getNativeWindowRef(),  kWindowStandardDocumentAttributes,  kWindowNoTitleBarAttribute | kWindowNoShadowAttribute);
503            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
504        }
505        else
506        {
507            err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes);
508            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);   
509        }
510
511        if (err != noErr)
512        {
513            osg::notify(osg::WARN) << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl;
514            return false;
515        }
516       
517        // update titlebar-height
518        Rect titleRect;
519        GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
520        _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
521       
522        // sth: I don't know why I have to reattach the context to the window here, If I don't do this  I get blank areas, where the titlebar was.
523        // InvalWindowRect doesn't help here :-/
524       
525        aglSetDrawable(_context, 0);
526        aglSetDrawable(_context, GetWindowPort(_window));
527               
528        MenubarController::instance()->update();
529    }
530
531    return true;
532}
533
534
535WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) {
536    WindowAttributes attr;
537   
538    if (useWindowDecoration)
539    {
540        if (supportsResize)
541            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute);
542        else
543            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute;
544    }
545    else 
546    {
547        attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
548        if (supportsResize)
549            attr |= kWindowResizableAttribute;
550    }
551    return attr;
552}
553
554void GraphicsWindowCarbon::installEventHandler() {
555
556    // register window event handler to receive resize-events
557    EventTypeSpec   windEventList[] = {
558        { kEventClassWindow, kEventWindowBoundsChanged},
559        { kEventClassWindow, kEventWindowClosed},
560       
561        {kEventClassMouse, kEventMouseDown},
562        {kEventClassMouse, kEventMouseUp},
563        {kEventClassMouse, kEventMouseMoved},
564        {kEventClassMouse, kEventMouseDragged},
565        {kEventClassMouse, kEventMouseWheelMoved},
566
567        {kEventClassKeyboard, kEventRawKeyDown},
568        {kEventClassKeyboard, kEventRawKeyRepeat},
569        {kEventClassKeyboard, kEventRawKeyUp},
570        {kEventClassKeyboard, kEventRawKeyModifiersChanged},
571        {kEventClassKeyboard, kEventHotKeyPressed},
572        {kEventClassKeyboard, kEventHotKeyReleased},
573    };
574   
575
576    InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler),  GetEventTypeCount(windEventList), windEventList, this, NULL);
577}
578
579
580bool GraphicsWindowCarbon::realizeImplementation()
581{
582   
583    if (!_initialized) init();
584    if (!_initialized) return false;
585    if (!_traits) return false;
586   
587    setWindowDecoration(_traits->windowDecoration);
588   
589    // move the window to the right screen
590
591    OSXCarbonWindowingSystemInterface* wsi = dynamic_cast<OSXCarbonWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
592    int screenLeft(0), screenTop(0);
593    if (wsi) {
594       
595        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
596        _traits->y += screenTop;
597        _traits->x += screenLeft;
598    }
599   
600    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
601    _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true;
602   
603    if (_ownsWindow) {
604       
605        // create the window
606        Rect bounds = {_traits->y, _traits->x, _traits->y + _traits->height, _traits->x + _traits->width};
607        OSStatus err = 0;
608        WindowAttributes attr = computeWindowAttributes(_useWindowDecoration, _traits->supportsResize);
609       
610        err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window);
611
612        if (err) {
613            osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation() failed creating a window: " << err << std::endl;
614            return false;
615        } else {
616            osg::notify(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation() - window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl;
617        }
618    }
619    else {
620        _window = windowData->getNativeWindowRef();
621    }
622   
623    Rect titleRect;
624    GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
625    _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
626   
627    if ((_ownsWindow) || (windowData && windowData->installEventHandler()))
628        installEventHandler();
629   
630    // set the window title
631    if (!_traits->windowName.empty()) {
632        CFStringRef windowtitle = CFStringCreateWithBytes( kCFAllocatorDefault, (const UInt8*)(_traits->windowName.c_str()), _traits->windowName.length(),kCFStringEncodingUTF8, false );
633        SetWindowTitleWithCFString( _window, windowtitle );
634    }
635   
636    // create the context
637    AGLContext sharedContextCarbon = NULL;
638   
639    GraphicsWindowCarbon* graphicsWindowCarbon = dynamic_cast<GraphicsWindowCarbon*>(_traits->sharedContext);
640    if (graphicsWindowCarbon)
641    {
642        sharedContextCarbon = graphicsWindowCarbon->getAGLContext();
643    }
644    else
645    {
646        PixelBufferCarbon* pixelbuffer = dynamic_cast<PixelBufferCarbon*>(_traits->sharedContext);
647        if (pixelbuffer) {
648            sharedContextCarbon = pixelbuffer->getAGLContext();
649        }
650    }
651    _context = aglCreateContext (_pixelFormat, sharedContextCarbon);
652
653
654    if (!_context) {
655        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation failed creating a context: " << aglGetError() << std::endl;
656        return false;
657    }
658       
659    makeCurrent();
660
661    if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) {
662        // enable Multi-threaded OpenGL Execution:
663        CGLError cgerr = kCGLNoError;
664        CGLContextObj ctx = CGLGetCurrentContext();
665
666#if 0
667        cgerr =  CGLEnable( ctx, kCGLCEMPEngine);
668#else
669        // the above use of kCGLCEMPEngine is not backwards compatible
670        // so we'll use the raw value of it to keep things compiling on older
671        // versions of OSX.
672        cgerr =  CGLEnable( ctx, static_cast <CGLContextEnable>(313) );
673#endif   
674        if (cgerr != kCGLNoError )
675        {
676            osg::notify(osg::INFO) << "GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available" << std::endl;
677        }
678    }
679    aglSetDrawable(_context, GetWindowPort(_window));
680    ShowWindow(_window);
681   
682    //enable vsync
683    if (_traits->vsync) {
684        GLint swap = 1;
685        aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap);
686    }
687
688    MenubarController::instance()->attachWindow(this);
689   
690    _realized = true;
691    return _realized;
692}
693
694
695
696bool GraphicsWindowCarbon::makeCurrentImplementation()
697{
698       
699    return (aglSetCurrentContext(_context) == GL_TRUE);
700}
701
702bool GraphicsWindowCarbon::releaseContextImplementation()
703{
704    if (!_realized)
705    {
706        osg::notify(osg::NOTICE)<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
707        return false;
708    }
709
710    // osg::notify(osg::NOTICE)<<"makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
711    // osg::notify(osg::NOTICE)<<"   glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
712    return (aglSetCurrentContext(NULL) == GL_TRUE);
713}
714
715
716
717void GraphicsWindowCarbon::closeImplementation()
718{
719    _valid = false;
720    _realized = false;
721   
722    MenubarController::instance()->detachWindow(this);
723   
724    if (_pixelFormat)
725    {
726        aglDestroyPixelFormat(_pixelFormat);
727        _pixelFormat = NULL;
728    }
729   
730    if (_context)
731    {
732        aglSetDrawable(_context, NULL);
733        aglSetCurrentContext(NULL);
734        aglDestroyContext(_context);
735        _context = NULL;
736    }
737   
738    if (_ownsWindow && _window) DisposeWindow(_window);
739    _window = NULL;
740}
741
742
743
744void GraphicsWindowCarbon::swapBuffersImplementation()
745{
746    aglSwapBuffers(_context);
747}
748
749
750
751void GraphicsWindowCarbon::resizedImplementation(int x, int y, int width, int height)
752{
753    GraphicsContext::resizedImplementation(x, y, width, height);
754
755    aglUpdateContext(_context);
756    MenubarController::instance()->update();
757}
758
759
760
761bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent)
762{
763
764    static unsigned int lastEmulatedMouseButton = 0;
765    // mouse down event   
766    Point wheresMyMouse;
767    GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
768   
769    wheresMyMouse.v -= _windowTitleHeight;
770    if (_useWindowDecoration && (wheresMyMouse.v < 0))
771        return false;
772   
773    Point wheresMyMouseGlobal;
774    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal);
775   
776    EventMouseButton mouseButton = 0;
777    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
778   
779    UInt32 modifierKeys;
780    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
781   
782   
783    WindowRef win;
784    int fwres = FindWindow(wheresMyMouseGlobal, &win);
785    if ((fwres != inContent) && (fwres > 0) && (mouseButton >= 1))
786    {
787        return false;
788    }
789    else
790    {
791   
792        // swap right and middle buttons so that middle button is 2, right button is 3.
793        if (mouseButton==3) mouseButton = 2;
794        else if (mouseButton==2) mouseButton = 3;
795       
796        // check tablet pointer device and map it to a musebutton
797        TabletProximityRec    theTabletRecord;    // The Tablet Proximity Record
798        // Extract the Tablet Proximity reccord from the event.
799        if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec,
800                                      typeTabletProximityRec, NULL,
801                                      sizeof(TabletProximityRec),
802                                      NULL, (void *)&theTabletRecord))
803        {           
804            osgGA::GUIEventAdapter::TabletPointerType pointerType;
805            switch(theTabletRecord.pointerType)
806            {
807                case 1: // pen
808                    pointerType = osgGA::GUIEventAdapter::PEN;
809                    break;
810                   
811                case 2: // puck
812                    pointerType = osgGA::GUIEventAdapter::PUCK;
813                    break;
814                   
815                case 3: //eraser
816                    pointerType = osgGA::GUIEventAdapter::ERASER;
817                    break;
818
819                default:
820                   pointerType = osgGA::GUIEventAdapter::UNKNOWN;
821                   break;
822            }
823           
824            getEventQueue()->penProximity(pointerType, (theTabletRecord.enterProximity != 0));
825        }
826
827        switch(GetEventKind(theEvent))
828        {
829            case kEventMouseDown:
830                {
831                    float mx =wheresMyMouse.h;
832                    float my =wheresMyMouse.v;
833                    transformMouseXY(mx, my);
834                   
835                    lastEmulatedMouseButton = 0;
836                   
837                    if (mouseButton == 1)
838                    {
839                        if( modifierKeys & cmdKey )
840                        {
841                            mouseButton = lastEmulatedMouseButton = 3;
842                        }
843                        else if( modifierKeys & optionKey )
844                        {
845                            mouseButton = lastEmulatedMouseButton = 2;
846                        }
847                    }
848                   
849                    getEventQueue()->mouseButtonPress(mx, my, mouseButton);
850                }
851                break;
852            case kEventMouseUp:
853                {
854                    float mx =wheresMyMouse.h;
855                    float my =wheresMyMouse.v;
856                    transformMouseXY(mx, my);
857                    if (lastEmulatedMouseButton > 0) {
858                        getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton);
859                        lastEmulatedMouseButton = 0;
860                    }
861                    else {
862                        getEventQueue()->mouseButtonRelease(mx, my, mouseButton);
863                    }
864                }
865                break;
866               
867            case kEventMouseDragged:
868                {
869                    // get pressure from the pen, only when mouse/pen is dragged
870                    TabletPointRec    theTabletRecord;
871                    if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
872                                    sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) {
873                   
874                        getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f);
875           
876                    }
877                   
878                    float mx =wheresMyMouse.h;
879                    float my =wheresMyMouse.v;
880                    transformMouseXY(mx, my);
881                    getEventQueue()->mouseMotion(mx, my);
882                }
883                break;
884               
885            case kEventMouseMoved:
886                {
887                    float mx = wheresMyMouse.h;
888                    float my = wheresMyMouse.v;
889                    transformMouseXY(mx, my);
890                    getEventQueue()->mouseMotion(mx, my);
891                }
892                break;
893               
894            // mouse with scroll-wheels
895            case kEventMouseWheelMoved:
896                {
897                    EventMouseWheelAxis axis;
898                    SInt32 delta;
899                    if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) {
900                        if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) {
901                            switch (axis) {
902                                case kEventMouseWheelAxisX:
903                                    getEventQueue()->mouseScroll( (delta > 0) ? osgGA::GUIEventAdapter::SCROLL_RIGHT : osgGA::GUIEventAdapter::SCROLL_LEFT);
904                                    break;
905                                case kEventMouseWheelAxisY:
906                                    getEventQueue()->mouseScroll( (delta < 0) ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP);
907                                    break;
908                            }
909                        }
910                    }
911                }
912                break;
913           
914            // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html )
915            case 11:
916                {
917                    enum
918                        {
919                        kEventParamMouseWheelSmoothVerticalDelta       = 'saxy', // typeSInt32
920                        kEventParamMouseWheelSmoothHorizontalDelta     = 'saxx' // typeSInt32
921                        };
922                   
923                    SInt32 scroll_delta_x = 0;
924                    SInt32 scroll_delta_y = 0;
925                    OSErr err = noErr;
926                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y );
927                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x );
928                   
929                    if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) {
930                        getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y);
931                    }
932                }
933                break;
934           
935            default:
936                return false;
937        }
938    }
939   
940    return true;
941}
942
943
944
945bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent)
946{
947   
948   
949    OSStatus status;
950
951    // Key modifiers, Numlock not supported...
952
953    UInt32 modifierKeys;
954    unsigned int modifierMask = 0;
955    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
956   
957   
958    if( modifierKeys & shiftKey )
959    {
960        modifierMask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
961    }
962    if( modifierKeys & alphaLock )
963    {
964        modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
965    }
966    if( modifierKeys & controlKey )
967    {
968        modifierMask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
969    }
970    if( modifierKeys & optionKey )
971    {
972        modifierMask |= osgGA::GUIEventAdapter::MODKEY_ALT;
973    }
974   
975    // we map the command-key to the META-key
976    if( modifierKeys & cmdKey )
977    {
978        modifierMask |= osgGA::GUIEventAdapter::MODKEY_META;
979    }
980   
981   
982    UInt32 rawkey;
983    GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey);
984   
985    // std::cout << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
986           
987    UInt32 dataSize;
988    /* jbw check return status so that we don't allocate a huge array */
989    status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL );
990    if (status != noErr) return false;
991    if (dataSize<=1) return false;
992   
993    UniChar* uniChars = new UniChar[dataSize+1];
994    GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars );
995   
996    unsigned int keychar = remapOSXKey(static_cast<unsigned long>(uniChars[0]), rawkey);
997   
998    switch(GetEventKind(theEvent))
999    {
1000        case kEventRawKeyDown:
1001        case kEventRawKeyRepeat:
1002        {
1003            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
1004            getEventQueue()->keyPress(keychar);
1005            break;
1006        }
1007       
1008        case kEventRawKeyUp:
1009        {                 
1010            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
1011            getEventQueue()->keyRelease(keychar);
1012            break;
1013        }
1014       
1015        default:
1016             break;
1017   
1018    }
1019
1020    delete[] uniChars;
1021
1022    return true;
1023}
1024
1025
1026
1027void GraphicsWindowCarbon::checkEvents()
1028{
1029    if (!_realized) return;
1030   
1031    EventRef theEvent;
1032    EventTargetRef theTarget = GetEventDispatcherTarget();
1033    while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr)
1034    {
1035        switch(GetEventClass(theEvent))
1036        {
1037            case kEventClassMouse:
1038                    {
1039                    // handle the menubar
1040                    Point wheresMyMouse;
1041                    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
1042                   
1043                    EventMouseButton mouseButton = 0;
1044                    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
1045                   
1046                    WindowRef win;
1047                    int fwres = FindWindow(wheresMyMouse, &win);
1048
1049                    if ((fwres == inMenuBar) && (mouseButton >= 1)) {
1050                        MenuSelect(wheresMyMouse);
1051                        HiliteMenu(0);
1052                        return;
1053                    }
1054                    break;
1055                }
1056
1057            case kEventClassApplication:
1058                switch (GetEventKind(theEvent)) {
1059                    case kEventAppQuit:
1060                        getEventQueue()->quitApplication();
1061                        break;
1062                }
1063                break;
1064           
1065            case kEventClassAppleEvent:
1066                {
1067                    EventRecord eventRecord;
1068                    ConvertEventRefToEventRecord(theEvent, &eventRecord);
1069                    AEProcessAppleEvent(&eventRecord);
1070                    return;
1071                }
1072                break;
1073
1074        }
1075        SendEventToEventTarget (theEvent, theTarget);
1076        ReleaseEvent(theEvent);       
1077    } 
1078    if (_closeRequested)
1079        close(true);
1080       
1081    if (s_quit_requested) {
1082        getEventQueue()->quitApplication();
1083        s_quit_requested = false;
1084    }
1085           
1086}
1087
1088
1089bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height)
1090{
1091    Rect bounds = {y, x, y + height, x + width};
1092    SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
1093    aglUpdateContext(_context);
1094    MenubarController::instance()->update();
1095    return true;
1096}
1097
1098void GraphicsWindowCarbon::grabFocus()
1099{
1100    SelectWindow(_window);
1101}
1102
1103
1104
1105void GraphicsWindowCarbon::grabFocusIfPointerInWindow()
1106{
1107   // TODO: implement
1108   osg::notify(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow" << std::endl;
1109}
1110
1111
1112
1113void GraphicsWindowCarbon::transformMouseXY(float& x, float& y)
1114{
1115    if (getEventQueue()->getUseFixedMouseInputRange())
1116    {
1117        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1118        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1119        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1120    }
1121}
1122
1123
1124
1125
1126
1127
1128struct RegisterWindowingSystemInterfaceProxy
1129{
1130    RegisterWindowingSystemInterfaceProxy()
1131    {
1132        osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::OSXCarbonWindowingSystemInterface());
1133    }
1134
1135    ~RegisterWindowingSystemInterfaceProxy()
1136    {
1137        osg::GraphicsContext::setWindowingSystemInterface(0);
1138    }
1139};
1140
1141RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
1142
1143// declare C entry point for static compilation.
1144extern "C" void graphicswindow_Carbon(void)
1145{
1146    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::OSXCarbonWindowingSystemInterface());
1147}
1148
1149#endif
Note: See TracBrowser for help on using the browser.