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

Revision 7074, 42.2 kB (checked in by robert, 7 years ago)

Added include/osg/GLObjects + .cpp which provide osg::flush*DeletedGLObjects() methods.

Added and cleaned up DeleteHandler? calls in osgViewer to help avoid crashes on exit.

Changed DatabasePager? across to dynamically checcking osg::getCompileContext(..)

Updated wrappers.

  • 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    {
348        if (osg::Referenced::getDeleteHandler())
349        {
350            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
351            osg::Referenced::getDeleteHandler()->flushAll();
352        }
353
354        if (_displayIds) delete[] _displayIds;
355        _displayIds = NULL;
356    }
357   
358    /** @return a CGDirectDisplayID for a ScreenIdentifier */
359    inline CGDirectDisplayID getDisplayID(const osg::GraphicsContext::ScreenIdentifier& si) {
360        if (si.screenNum < _displayCount)
361            return _displayIds[si.screenNum];
362        else {
363            osg::notify(osg::WARN) << "GraphicsWindowCarbon :: invalid screen # " << si.screenNum << ", returning main-screen instead" << std::endl;
364            return _displayIds[0];
365        }
366    }
367
368    /** @return count of attached screens */
369    virtual unsigned int getNumScreens(const osg::GraphicsContext::ScreenIdentifier& si)
370    {
371        return _displayCount;
372    }
373
374    /** returns the resolution of a specific display */
375    virtual void getScreenResolution(const osg::GraphicsContext::ScreenIdentifier& si, unsigned int& width, unsigned int& height)
376    {
377        CGDirectDisplayID id = getDisplayID(si);
378        width = CGDisplayPixelsWide(id);
379        height = CGDisplayPixelsHigh(id);
380    }
381   
382    /** return the top left coord of a specific screen in global screen space */
383    void getScreenTopLeft(const osg::GraphicsContext::ScreenIdentifier& si, int& x, int& y) {
384        CGRect bounds = CGDisplayBounds( getDisplayID(si) );
385        x = static_cast<int>(bounds.origin.x);
386        y = static_cast<int>(bounds.origin.y);
387       
388        // osg::notify(osg::DEBUG_INFO) << "topleft of screen " << si.screenNum <<" " << bounds.origin.x << "/" << bounds.origin.y << std::endl;
389    }
390   
391    /** helper method to get a value out of a CFDictionary */
392    static double getDictDouble (CFDictionaryRef refDict, CFStringRef key)
393    {
394       double double_value;
395       CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key);
396       if (!number_value) // if can't get a number for the dictionary
397           return -1;  // fail
398       if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it
399            return -1; // fail
400        return double_value; // otherwise return the long value
401    }
402
403   
404    /** implementation of setScreenResolution */
405    virtual bool setScreenResolution(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, unsigned int width, unsigned int height)
406    {
407        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
408       
409        // add next line and on following line replace hard coded depth and refresh rate
410        CGRefreshRate refresh =  getDictDouble (CGDisplayCurrentMode(displayID), kCGDisplayRefreshRate); 
411        CFDictionaryRef display_mode_values =
412            CGDisplayBestModeForParametersAndRefreshRate(
413                            displayID,
414                            CGDisplayBitsPerPixel(displayID),
415                            width, height, 
416                            refresh, 
417                            NULL);
418
419                                         
420        CGDisplaySwitchToMode(displayID, display_mode_values);   
421        return true;
422    }
423   
424    /** implementation of setScreenRefreshRate */
425    virtual bool setScreenRefreshRate(const osg::GraphicsContext::ScreenIdentifier& screenIdentifier, double refreshRate) {
426       
427        boolean_t  success(false);
428        unsigned width, height;
429        getScreenResolution(screenIdentifier, width, height);
430       
431        CGDirectDisplayID displayID = getDisplayID(screenIdentifier);
432       
433        // add next line and on following line replace hard coded depth and refresh rate
434        CFDictionaryRef display_mode_values =
435            CGDisplayBestModeForParametersAndRefreshRate(
436                            displayID,
437                            CGDisplayBitsPerPixel(displayID),
438                            width, height, 
439                            refreshRate, 
440                            &success);
441
442                                         
443        if (success)
444            CGDisplaySwitchToMode(displayID, display_mode_values);   
445           
446        return (success != 0);
447    }
448
449       
450   
451    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
452    {
453        if (traits->pbuffer)
454        {
455            osg::ref_ptr<osgViewer::PixelBufferCarbon> pbuffer = new PixelBufferCarbon(traits);
456            if (pbuffer->valid()) return pbuffer.release();
457            else return 0;
458        }
459        else
460        {
461            osg::ref_ptr<osgViewer::GraphicsWindowCarbon> window = new GraphicsWindowCarbon(traits);
462            if (window->valid()) return window.release();
463            else return 0;
464        }
465    }
466   
467   
468   
469    private:
470        CGDisplayCount        _displayCount;
471        CGDirectDisplayID*    _displayIds;
472};
473
474}
475
476
477#pragma mark * * * GraphicsWindowCarbon * * *
478
479
480
481
482void GraphicsWindowCarbon::init()
483{
484    _windowTitleHeight = 0;
485    _closeRequested = false;
486    _ownsWindow = false;
487    _context = NULL;
488    _window = NULL;
489    _pixelFormat = PixelBufferCarbon::createPixelFormat(_traits.get());
490    if (!_pixelFormat)
491        osg::notify(osg::WARN) << "GraphicsWindowCarbon::init could not create a valid pixelformat" << std::endl;
492    _valid = (_pixelFormat != NULL);
493    _initialized = true;
494}
495
496bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag)
497{
498    _useWindowDecoration = flag;
499
500    if (_realized)
501    {
502        OSErr err = noErr;
503        Rect bounds;
504        GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
505
506        if (_useWindowDecoration)
507        {
508            err = ChangeWindowAttributes(getNativeWindowRef(),  kWindowStandardDocumentAttributes,  kWindowNoTitleBarAttribute | kWindowNoShadowAttribute);
509            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
510        }
511        else
512        {
513            err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes);
514            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);   
515        }
516
517        if (err != noErr)
518        {
519            osg::notify(osg::WARN) << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl;
520            return false;
521        }
522       
523        // update titlebar-height
524        Rect titleRect;
525        GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
526        _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
527       
528        // 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.
529        // InvalWindowRect doesn't help here :-/
530       
531        aglSetDrawable(_context, 0);
532        aglSetDrawable(_context, GetWindowPort(_window));
533               
534        MenubarController::instance()->update();
535    }
536
537    return true;
538}
539
540
541WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) {
542    WindowAttributes attr;
543   
544    if (useWindowDecoration)
545    {
546        if (supportsResize)
547            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute);
548        else
549            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute;
550    }
551    else 
552    {
553        attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
554        if (supportsResize)
555            attr |= kWindowResizableAttribute;
556    }
557    return attr;
558}
559
560void GraphicsWindowCarbon::installEventHandler() {
561
562    // register window event handler to receive resize-events
563    EventTypeSpec   windEventList[] = {
564        { kEventClassWindow, kEventWindowBoundsChanged},
565        { kEventClassWindow, kEventWindowClosed},
566       
567        {kEventClassMouse, kEventMouseDown},
568        {kEventClassMouse, kEventMouseUp},
569        {kEventClassMouse, kEventMouseMoved},
570        {kEventClassMouse, kEventMouseDragged},
571        {kEventClassMouse, kEventMouseWheelMoved},
572
573        {kEventClassKeyboard, kEventRawKeyDown},
574        {kEventClassKeyboard, kEventRawKeyRepeat},
575        {kEventClassKeyboard, kEventRawKeyUp},
576        {kEventClassKeyboard, kEventRawKeyModifiersChanged},
577        {kEventClassKeyboard, kEventHotKeyPressed},
578        {kEventClassKeyboard, kEventHotKeyReleased},
579    };
580   
581
582    InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler),  GetEventTypeCount(windEventList), windEventList, this, NULL);
583}
584
585
586bool GraphicsWindowCarbon::realizeImplementation()
587{
588   
589    if (!_initialized) init();
590    if (!_initialized) return false;
591    if (!_traits) return false;
592   
593    setWindowDecoration(_traits->windowDecoration);
594   
595    // move the window to the right screen
596
597    OSXCarbonWindowingSystemInterface* wsi = dynamic_cast<OSXCarbonWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
598    int screenLeft(0), screenTop(0);
599    if (wsi) {
600       
601        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
602        _traits->y += screenTop;
603        _traits->x += screenLeft;
604    }
605   
606    WindowData *windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
607    _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true;
608   
609    if (_ownsWindow) {
610       
611        // create the window
612        Rect bounds = {_traits->y, _traits->x, _traits->y + _traits->height, _traits->x + _traits->width};
613        OSStatus err = 0;
614        WindowAttributes attr = computeWindowAttributes(_useWindowDecoration, _traits->supportsResize);
615       
616        err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window);
617
618        if (err) {
619            osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation() failed creating a window: " << err << std::endl;
620            return false;
621        } else {
622            osg::notify(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation() - window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl;
623        }
624    }
625    else {
626        _window = windowData->getNativeWindowRef();
627    }
628   
629    Rect titleRect;
630    GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
631    _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
632   
633    if ((_ownsWindow) || (windowData && windowData->installEventHandler()))
634        installEventHandler();
635   
636    // set the window title
637    if (!_traits->windowName.empty()) {
638        CFStringRef windowtitle = CFStringCreateWithBytes( kCFAllocatorDefault, (const UInt8*)(_traits->windowName.c_str()), _traits->windowName.length(),kCFStringEncodingUTF8, false );
639        SetWindowTitleWithCFString( _window, windowtitle );
640    }
641   
642    // create the context
643    AGLContext sharedContextCarbon = NULL;
644   
645    GraphicsWindowCarbon* graphicsWindowCarbon = dynamic_cast<GraphicsWindowCarbon*>(_traits->sharedContext);
646    if (graphicsWindowCarbon)
647    {
648        sharedContextCarbon = graphicsWindowCarbon->getAGLContext();
649    }
650    else
651    {
652        PixelBufferCarbon* pixelbuffer = dynamic_cast<PixelBufferCarbon*>(_traits->sharedContext);
653        if (pixelbuffer) {
654            sharedContextCarbon = pixelbuffer->getAGLContext();
655        }
656    }
657    _context = aglCreateContext (_pixelFormat, sharedContextCarbon);
658
659
660    if (!_context) {
661        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation failed creating a context: " << aglGetError() << std::endl;
662        return false;
663    }
664       
665    makeCurrent();
666
667    if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) {
668        // enable Multi-threaded OpenGL Execution:
669        CGLError cgerr = kCGLNoError;
670        CGLContextObj ctx = CGLGetCurrentContext();
671
672#if 0
673        cgerr =  CGLEnable( ctx, kCGLCEMPEngine);
674#else
675        // the above use of kCGLCEMPEngine is not backwards compatible
676        // so we'll use the raw value of it to keep things compiling on older
677        // versions of OSX.
678        cgerr =  CGLEnable( ctx, static_cast <CGLContextEnable>(313) );
679#endif   
680        if (cgerr != kCGLNoError )
681        {
682            osg::notify(osg::INFO) << "GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available" << std::endl;
683        }
684    }
685    aglSetDrawable(_context, GetWindowPort(_window));
686    ShowWindow(_window);
687   
688    //enable vsync
689    if (_traits->vsync) {
690        GLint swap = 1;
691        aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap);
692    }
693
694    MenubarController::instance()->attachWindow(this);
695   
696    _realized = true;
697    return _realized;
698}
699
700
701
702bool GraphicsWindowCarbon::makeCurrentImplementation()
703{
704       
705    return (aglSetCurrentContext(_context) == GL_TRUE);
706}
707
708bool GraphicsWindowCarbon::releaseContextImplementation()
709{
710    if (!_realized)
711    {
712        osg::notify(osg::NOTICE)<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
713        return false;
714    }
715
716    // osg::notify(osg::NOTICE)<<"makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
717    // osg::notify(osg::NOTICE)<<"   glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
718    return (aglSetCurrentContext(NULL) == GL_TRUE);
719}
720
721
722
723void GraphicsWindowCarbon::closeImplementation()
724{
725    _valid = false;
726    _realized = false;
727   
728    MenubarController::instance()->detachWindow(this);
729   
730    if (_pixelFormat)
731    {
732        aglDestroyPixelFormat(_pixelFormat);
733        _pixelFormat = NULL;
734    }
735   
736    if (_context)
737    {
738        aglSetDrawable(_context, NULL);
739        aglSetCurrentContext(NULL);
740        aglDestroyContext(_context);
741        _context = NULL;
742    }
743   
744    if (_ownsWindow && _window) DisposeWindow(_window);
745    _window = NULL;
746}
747
748
749
750void GraphicsWindowCarbon::swapBuffersImplementation()
751{
752    aglSwapBuffers(_context);
753}
754
755
756
757void GraphicsWindowCarbon::resizedImplementation(int x, int y, int width, int height)
758{
759    GraphicsContext::resizedImplementation(x, y, width, height);
760
761    aglUpdateContext(_context);
762    MenubarController::instance()->update();
763}
764
765
766
767bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent)
768{
769
770    static unsigned int lastEmulatedMouseButton = 0;
771    // mouse down event   
772    Point wheresMyMouse;
773    GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
774   
775    wheresMyMouse.v -= _windowTitleHeight;
776    if (_useWindowDecoration && (wheresMyMouse.v < 0))
777        return false;
778   
779    Point wheresMyMouseGlobal;
780    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal);
781   
782    EventMouseButton mouseButton = 0;
783    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
784   
785    UInt32 modifierKeys;
786    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
787   
788   
789    WindowRef win;
790    int fwres = FindWindow(wheresMyMouseGlobal, &win);
791    if ((fwres != inContent) && (fwres > 0) && (mouseButton >= 1))
792    {
793        return false;
794    }
795    else
796    {
797   
798        // swap right and middle buttons so that middle button is 2, right button is 3.
799        if (mouseButton==3) mouseButton = 2;
800        else if (mouseButton==2) mouseButton = 3;
801       
802        // check tablet pointer device and map it to a musebutton
803        TabletProximityRec    theTabletRecord;    // The Tablet Proximity Record
804        // Extract the Tablet Proximity reccord from the event.
805        if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec,
806                                      typeTabletProximityRec, NULL,
807                                      sizeof(TabletProximityRec),
808                                      NULL, (void *)&theTabletRecord))
809        {           
810            osgGA::GUIEventAdapter::TabletPointerType pointerType;
811            switch(theTabletRecord.pointerType)
812            {
813                case 1: // pen
814                    pointerType = osgGA::GUIEventAdapter::PEN;
815                    break;
816                   
817                case 2: // puck
818                    pointerType = osgGA::GUIEventAdapter::PUCK;
819                    break;
820                   
821                case 3: //eraser
822                    pointerType = osgGA::GUIEventAdapter::ERASER;
823                    break;
824
825                default:
826                   pointerType = osgGA::GUIEventAdapter::UNKNOWN;
827                   break;
828            }
829           
830            getEventQueue()->penProximity(pointerType, (theTabletRecord.enterProximity != 0));
831        }
832
833        switch(GetEventKind(theEvent))
834        {
835            case kEventMouseDown:
836                {
837                    float mx =wheresMyMouse.h;
838                    float my =wheresMyMouse.v;
839                    transformMouseXY(mx, my);
840                   
841                    lastEmulatedMouseButton = 0;
842                   
843                    if (mouseButton == 1)
844                    {
845                        if( modifierKeys & cmdKey )
846                        {
847                            mouseButton = lastEmulatedMouseButton = 3;
848                        }
849                        else if( modifierKeys & optionKey )
850                        {
851                            mouseButton = lastEmulatedMouseButton = 2;
852                        }
853                    }
854                   
855                    getEventQueue()->mouseButtonPress(mx, my, mouseButton);
856                }
857                break;
858            case kEventMouseUp:
859                {
860                    float mx =wheresMyMouse.h;
861                    float my =wheresMyMouse.v;
862                    transformMouseXY(mx, my);
863                    if (lastEmulatedMouseButton > 0) {
864                        getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton);
865                        lastEmulatedMouseButton = 0;
866                    }
867                    else {
868                        getEventQueue()->mouseButtonRelease(mx, my, mouseButton);
869                    }
870                }
871                break;
872               
873            case kEventMouseDragged:
874                {
875                    // get pressure from the pen, only when mouse/pen is dragged
876                    TabletPointRec    theTabletRecord;
877                    if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
878                                    sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) {
879                   
880                        getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f);
881           
882                    }
883                   
884                    float mx =wheresMyMouse.h;
885                    float my =wheresMyMouse.v;
886                    transformMouseXY(mx, my);
887                    getEventQueue()->mouseMotion(mx, my);
888                }
889                break;
890               
891            case kEventMouseMoved:
892                {
893                    float mx = wheresMyMouse.h;
894                    float my = wheresMyMouse.v;
895                    transformMouseXY(mx, my);
896                    getEventQueue()->mouseMotion(mx, my);
897                }
898                break;
899               
900            // mouse with scroll-wheels
901            case kEventMouseWheelMoved:
902                {
903                    EventMouseWheelAxis axis;
904                    SInt32 delta;
905                    if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) {
906                        if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) {
907                            switch (axis) {
908                                case kEventMouseWheelAxisX:
909                                    getEventQueue()->mouseScroll( (delta > 0) ? osgGA::GUIEventAdapter::SCROLL_RIGHT : osgGA::GUIEventAdapter::SCROLL_LEFT);
910                                    break;
911                                case kEventMouseWheelAxisY:
912                                    getEventQueue()->mouseScroll( (delta < 0) ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP);
913                                    break;
914                            }
915                        }
916                    }
917                }
918                break;
919           
920            // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html )
921            case 11:
922                {
923                    enum
924                        {
925                        kEventParamMouseWheelSmoothVerticalDelta       = 'saxy', // typeSInt32
926                        kEventParamMouseWheelSmoothHorizontalDelta     = 'saxx' // typeSInt32
927                        };
928                   
929                    SInt32 scroll_delta_x = 0;
930                    SInt32 scroll_delta_y = 0;
931                    OSErr err = noErr;
932                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y );
933                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x );
934                   
935                    if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) {
936                        getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y);
937                    }
938                }
939                break;
940           
941            default:
942                return false;
943        }
944    }
945   
946    return true;
947}
948
949
950
951bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent)
952{
953   
954   
955    OSStatus status;
956
957    // Key modifiers, Numlock not supported...
958
959    UInt32 modifierKeys;
960    unsigned int modifierMask = 0;
961    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
962   
963   
964    if( modifierKeys & shiftKey )
965    {
966        modifierMask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
967    }
968    if( modifierKeys & alphaLock )
969    {
970        modifierMask |= osgGA::GUIEventAdapter::MODKEY_CAPS_LOCK;
971    }
972    if( modifierKeys & controlKey )
973    {
974        modifierMask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
975    }
976    if( modifierKeys & optionKey )
977    {
978        modifierMask |= osgGA::GUIEventAdapter::MODKEY_ALT;
979    }
980   
981    // we map the command-key to the META-key
982    if( modifierKeys & cmdKey )
983    {
984        modifierMask |= osgGA::GUIEventAdapter::MODKEY_META;
985    }
986   
987   
988    UInt32 rawkey;
989    GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey);
990   
991    // std::cout << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
992           
993    UInt32 dataSize;
994    /* jbw check return status so that we don't allocate a huge array */
995    status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL );
996    if (status != noErr) return false;
997    if (dataSize<=1) return false;
998   
999    UniChar* uniChars = new UniChar[dataSize+1];
1000    GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars );
1001   
1002    unsigned int keychar = remapOSXKey(static_cast<unsigned long>(uniChars[0]), rawkey);
1003   
1004    switch(GetEventKind(theEvent))
1005    {
1006        case kEventRawKeyDown:
1007        case kEventRawKeyRepeat:
1008        {
1009            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
1010            getEventQueue()->keyPress(keychar);
1011            break;
1012        }
1013       
1014        case kEventRawKeyUp:
1015        {                 
1016            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
1017            getEventQueue()->keyRelease(keychar);
1018            break;
1019        }
1020       
1021        default:
1022             break;
1023   
1024    }
1025
1026    delete[] uniChars;
1027
1028    return true;
1029}
1030
1031
1032
1033void GraphicsWindowCarbon::checkEvents()
1034{
1035    if (!_realized) return;
1036   
1037    EventRef theEvent;
1038    EventTargetRef theTarget = GetEventDispatcherTarget();
1039    while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr)
1040    {
1041        switch(GetEventClass(theEvent))
1042        {
1043            case kEventClassMouse:
1044                    {
1045                    // handle the menubar
1046                    Point wheresMyMouse;
1047                    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
1048                   
1049                    EventMouseButton mouseButton = 0;
1050                    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
1051                   
1052                    WindowRef win;
1053                    int fwres = FindWindow(wheresMyMouse, &win);
1054
1055                    if ((fwres == inMenuBar) && (mouseButton >= 1)) {
1056                        MenuSelect(wheresMyMouse);
1057                        HiliteMenu(0);
1058                        return;
1059                    }
1060                    break;
1061                }
1062
1063            case kEventClassApplication:
1064                switch (GetEventKind(theEvent)) {
1065                    case kEventAppQuit:
1066                        getEventQueue()->quitApplication();
1067                        break;
1068                }
1069                break;
1070           
1071            case kEventClassAppleEvent:
1072                {
1073                    EventRecord eventRecord;
1074                    ConvertEventRefToEventRecord(theEvent, &eventRecord);
1075                    AEProcessAppleEvent(&eventRecord);
1076                    return;
1077                }
1078                break;
1079
1080        }
1081        SendEventToEventTarget (theEvent, theTarget);
1082        ReleaseEvent(theEvent);       
1083    } 
1084    if (_closeRequested)
1085        close(true);
1086       
1087    if (s_quit_requested) {
1088        getEventQueue()->quitApplication();
1089        s_quit_requested = false;
1090    }
1091           
1092}
1093
1094
1095bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height)
1096{
1097    Rect bounds = {y, x, y + height, x + width};
1098    SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
1099    aglUpdateContext(_context);
1100    MenubarController::instance()->update();
1101    return true;
1102}
1103
1104void GraphicsWindowCarbon::grabFocus()
1105{
1106    SelectWindow(_window);
1107}
1108
1109
1110
1111void GraphicsWindowCarbon::grabFocusIfPointerInWindow()
1112{
1113   // TODO: implement
1114   osg::notify(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow" << std::endl;
1115}
1116
1117
1118
1119void GraphicsWindowCarbon::transformMouseXY(float& x, float& y)
1120{
1121    if (getEventQueue()->getUseFixedMouseInputRange())
1122    {
1123        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1124        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1125        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1126    }
1127}
1128
1129
1130
1131
1132
1133
1134struct RegisterWindowingSystemInterfaceProxy
1135{
1136    RegisterWindowingSystemInterfaceProxy()
1137    {
1138        osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::OSXCarbonWindowingSystemInterface());
1139    }
1140
1141    ~RegisterWindowingSystemInterfaceProxy()
1142    {
1143        if (osg::Referenced::getDeleteHandler())
1144        {
1145            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
1146            osg::Referenced::getDeleteHandler()->flushAll();
1147        }
1148
1149        osg::GraphicsContext::setWindowingSystemInterface(0);
1150    }
1151};
1152
1153RegisterWindowingSystemInterfaceProxy createWindowingSystemInterfaceProxy;
1154
1155// declare C entry point for static compilation.
1156extern "C" void graphicswindow_Carbon(void)
1157{
1158    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::OSXCarbonWindowingSystemInterface());
1159}
1160
1161#endif
Note: See TracBrowser for help on using the browser.