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

Revision 7066, 41.8 kB (checked in by robert, 7 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.