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

Revision 9894, 39.6 kB (checked in by robert, 5 years ago)

From Stephan Huber, "refactored the code and moved
some stuff out into DarwinUtils?.h/.mm so both implementations can share
some of the code. There's even a bugfix for GraphicsWindowCarbon?, which
fixes some issues with multiple windows on different screens."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[5948]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
[9894]14#if defined (__APPLE__) && (!__LP64__)
15
[5978]16#include <osg/observer_ptr>
[7079]17
[7039]18#include <osgViewer/api/Carbon/PixelBufferCarbon>
[6464]19#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
[7079]20
21#include <osg/DeleteHandler>
22
[5948]23#include <Carbon/Carbon.h>
24#include <OpenGL/OpenGL.h>
[7866]25
26#include <iostream>
[8017]27
[9894]28#include "DarwinUtils.h"
29
[5948]30using namespace osgViewer;
[9894]31using namespace osgDarwin;
[5948]32
33
34// Carbon-Eventhandler to handle the click in the close-widget and the resize of windows
35
[5978]36static pascal OSStatus GraphicsWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void* userData)
[5948]37{
38    WindowRef           window;
39    Rect                bounds;
40    OSStatus            result = eventNotHandledErr; /* report failure by default */
41   
[7866]42    osg::notify(osg::INFO) << "GraphicsWindowEventHandler" << std::endl;
[5948]43
44    GraphicsWindowCarbon* w = (GraphicsWindowCarbon*)userData;
45    if (!w)
46        return result;
47   
48    GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL,
49                         sizeof(window), NULL, &window);
[5978]50                         
51    switch(GetEventClass(event))
52    {
53        case kEventClassTablet:
54        case kEventClassMouse:
55            if (w->handleMouseEvent(event))
[5948]56                result = noErr;
[5978]57            break;
[7884]58               
[5978]59        case kEventClassKeyboard:
60            if (w->handleKeyboardEvent(event))
61                result = noErr;
62            break;
63           
64        case kEventClassWindow: {
65       
66            switch (GetEventKind(event))
67                {
68                    case kEventWindowBoundsChanging:
69                        // left the code for live-resizing, but it is not used, because of window-refreshing issues...
70                        GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &bounds );
71                       
[9894]72                        w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
[5978]73                        w->requestRedraw();
74                        result = noErr;
75                        break;
76                           
77                    case kEventWindowBoundsChanged:
78                        InvalWindowRect(window, GetWindowPortBounds(window, &bounds));
79                        GetWindowBounds(window, kWindowContentRgn, &bounds);
[9894]80                        w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
[5978]81                        result = noErr;
82                        break;
[5948]83                   
[7165]84                    case kEventWindowClose:
[5978]85                        w->requestClose();
[7165]86                        result = noErr;
[5978]87                        break;
88         
89                    default:
90                        break;
91                }
92            }
93        default:
[7884]94            //std::cout << "unknown: " << GetEventClass(event) << std::endl;
[5978]95            break;
96    }
[7165]97   
[7866]98    //if (result == eventNotHandledErr)
99    //    result = CallNextEventHandler (nextHandler, event);
[7165]100       
[5948]101    return result;
102}
103
[8017]104
[5948]105static bool s_quit_requested = false;
106
107// Application eventhandler -- listens for a quit-event
108static pascal OSStatus ApplicationEventHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData)
109{
110   
111    HICommand commandStruct;
112
113    OSErr  err = eventNotHandledErr;
114
115    GetEventParameter (inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &commandStruct);
116
117    switch(commandStruct.commandID) {
118        case kHICommandQuit:
119            s_quit_requested = true;
120            err = noErr;
121            break;
122                   
123    }
124   
125    return err;
126}
127
128// AppleEventHandler, listens to the Quit-AppleEvent
129static pascal OSErr QuitAppleEventHandler(const AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon ) {
130    s_quit_requested = true;
131    return (noErr);
132}
133
134
135namespace osgViewer
136{
137
138// small helper class which maps the raw key codes to osgGA::GUIEventAdapter::Keys
139
[9894]140class CarbonKeyboardMap {
[5948]141
142    public:
[9894]143        CarbonKeyboardMap()
[5948]144        {
145            _keymap[53                ] =  osgGA::GUIEventAdapter::KEY_Escape;
146            _keymap[115                ] =  osgGA::GUIEventAdapter::KEY_Home;
147            _keymap[76                ] =  osgGA::GUIEventAdapter::KEY_KP_Enter;
148            _keymap[119                ] =  osgGA::GUIEventAdapter::KEY_End;
149            _keymap[36                ] =  osgGA::GUIEventAdapter::KEY_Return;
150            _keymap[116                ] =  osgGA::GUIEventAdapter::KEY_Page_Up;
151            _keymap[121                ] = osgGA::GUIEventAdapter::KEY_Page_Down;
152            _keymap[123                ] = osgGA::GUIEventAdapter::KEY_Left;
153            _keymap[124                ] = osgGA::GUIEventAdapter::KEY_Right;
154            _keymap[126                ] = osgGA::GUIEventAdapter::KEY_Up;
155            _keymap[125                ] = osgGA::GUIEventAdapter::KEY_Down;
156            _keymap[51                ] = osgGA::GUIEventAdapter::KEY_BackSpace;
157            _keymap[48                ] = osgGA::GUIEventAdapter::KEY_Tab;
158            _keymap[49                ] = osgGA::GUIEventAdapter::KEY_Space;
159            _keymap[117                ] = osgGA::GUIEventAdapter::KEY_Delete;
160           
161            _keymap[122                    ] = osgGA::GUIEventAdapter::KEY_F1;
162            _keymap[120                    ] = osgGA::GUIEventAdapter::KEY_F2;
163            _keymap[99                    ] = osgGA::GUIEventAdapter::KEY_F3;
164            _keymap[118                    ] = osgGA::GUIEventAdapter::KEY_F4;
165            _keymap[96                    ] = osgGA::GUIEventAdapter::KEY_F5;
166            _keymap[97                    ] = osgGA::GUIEventAdapter::KEY_F6;
167            _keymap[98                    ] = osgGA::GUIEventAdapter::KEY_F7;
168            _keymap[100                    ] = osgGA::GUIEventAdapter::KEY_F8;
169            _keymap[101                    ] = osgGA::GUIEventAdapter::KEY_F9;
170            _keymap[109                    ] = osgGA::GUIEventAdapter::KEY_F10;
171            _keymap[103                    ] = osgGA::GUIEventAdapter::KEY_F11;
172            _keymap[111                    ] = osgGA::GUIEventAdapter::KEY_F12;
173           
174            _keymap[75                    ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
175            _keymap[67                    ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
176            _keymap[78                    ] = osgGA::GUIEventAdapter::KEY_KP_Subtract;
177            _keymap[69                    ] = osgGA::GUIEventAdapter::KEY_KP_Add;
178            _keymap[89                    ] = osgGA::GUIEventAdapter::KEY_KP_Home;
179            _keymap[91                    ] = osgGA::GUIEventAdapter::KEY_KP_Up;
180            _keymap[92                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
181            _keymap[86                    ] = osgGA::GUIEventAdapter::KEY_KP_Left;
182            _keymap[87                    ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
183            _keymap[88                    ] = osgGA::GUIEventAdapter::KEY_KP_Right;
184            _keymap[83                    ] = osgGA::GUIEventAdapter::KEY_KP_End;
185            _keymap[84                    ] = osgGA::GUIEventAdapter::KEY_KP_Down;
186            _keymap[85                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
187            _keymap[82                    ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
188            _keymap[65                    ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
189
190        }
191       
[9894]192        ~CarbonKeyboardMap() {
[5948]193        }
194       
195        unsigned int remapKey(unsigned int key, unsigned int rawkey)
196        {
197            KeyMap::iterator itr = _keymap.find(rawkey);
198            if (itr == _keymap.end()) return key;
199            else return itr->second;
200        }
201    private:
202        typedef std::map<unsigned int, osgGA::GUIEventAdapter::KeySymbol> KeyMap;
203        KeyMap _keymap;
204};
205
206/** remaps a native os x keycode to a GUIEventAdapter-keycode */
[9894]207static unsigned int remapCarbonKey(unsigned int key, unsigned int rawkey)
[5948]208{
[9894]209    static CarbonKeyboardMap s_CarbonKeyboardMap;
210    return s_CarbonKeyboardMap.remapKey(key,rawkey);
[5948]211}
212
213
[9894]214class CarbonWindowAdapter : public MenubarController::WindowAdapter {
215public:
216    CarbonWindowAdapter(GraphicsWindowCarbon* win) : MenubarController::WindowAdapter(), _win(win) {}
217    virtual bool valid() {return (_win.valid() && _win->valid()); }
218    virtual void getWindowBounds(CGRect& rect)
[5978]219    {
[9894]220        Rect windowBounds;
221        OSErr error = GetWindowBounds(_win->getNativeWindowRef(), kWindowStructureRgn, &windowBounds);
222        rect.origin.x = windowBounds.left;
223        rect.origin.y = windowBounds.top;
224        rect.size.width = windowBounds.right - windowBounds.left;
225        rect.size.height = windowBounds.bottom - windowBounds.top;
[5978]226    }
227       
[9894]228    osgViewer::GraphicsWindow* getWindow()  { return _win.get(); }
229private:
230    osg::observer_ptr<GraphicsWindowCarbon> _win;
[5978]231};
232
233
234
[6404]235void GraphicsWindowCarbon::init()
[5948]236{
[7112]237    if (_initialized) return;
238
[8398]239    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
[7884]240   
241    _lastModifierKeys = 0;
[6678]242    _windowTitleHeight = 0;
[5948]243    _closeRequested = false;
[6706]244    _ownsWindow = false;
[5948]245    _context = NULL;
246    _window = NULL;
[7039]247    _pixelFormat = PixelBufferCarbon::createPixelFormat(_traits.get());
[5948]248    if (!_pixelFormat)
249        osg::notify(osg::WARN) << "GraphicsWindowCarbon::init could not create a valid pixelformat" << std::endl;
250    _valid = (_pixelFormat != NULL);
251    _initialized = true;
252}
253
[6931]254bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag)
[6706]255{
256    _useWindowDecoration = flag;
[6931]257
258    if (_realized)
259    {
[6706]260        OSErr err = noErr;
261        Rect bounds;
262        GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
[5948]263
[6931]264        if (_useWindowDecoration)
265        {
[6706]266            err = ChangeWindowAttributes(getNativeWindowRef(),  kWindowStandardDocumentAttributes,  kWindowNoTitleBarAttribute | kWindowNoShadowAttribute);
267            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
[6931]268        }
269        else
270        {
[6706]271            err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes);
[6944]272            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);   
[6706]273        }
[5948]274
[6931]275        if (err != noErr)
276        {
[6706]277            osg::notify(osg::WARN) << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl;
[6931]278            return false;
[6706]279        }
[6944]280       
281        // update titlebar-height
282        Rect titleRect;
283        GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
284        _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
285       
286        // 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.
287        // InvalWindowRect doesn't help here :-/
288       
289        aglSetDrawable(_context, 0);
290        aglSetDrawable(_context, GetWindowPort(_window));
291               
292        MenubarController::instance()->update();
[6706]293    }
[6931]294
295    return true;
[6706]296}
[5978]297
[6944]298
[6706]299WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) {
300    WindowAttributes attr;
[5978]301   
[6706]302    if (useWindowDecoration)
[5978]303    {
[6706]304        if (supportsResize)
[5948]305            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute);
306        else
307            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute;
[5978]308    }
[6220]309    else 
310    {
311        attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
[6706]312        if (supportsResize)
[5948]313            attr |= kWindowResizableAttribute;
314    }
[6706]315    return attr;
316}
[6220]317
[6706]318void GraphicsWindowCarbon::installEventHandler() {
319
[5948]320    // register window event handler to receive resize-events
[5978]321    EventTypeSpec   windEventList[] = {
322        { kEventClassWindow, kEventWindowBoundsChanged},
[7165]323        { kEventClassWindow, kEventWindowClose},
[5978]324       
325        {kEventClassMouse, kEventMouseDown},
326        {kEventClassMouse, kEventMouseUp},
327        {kEventClassMouse, kEventMouseMoved},
328        {kEventClassMouse, kEventMouseDragged},
329        {kEventClassMouse, kEventMouseWheelMoved},
[8192]330        {kEventClassMouse, 11 /* kEventMouseScroll */},
[5978]331
332        {kEventClassKeyboard, kEventRawKeyDown},
333        {kEventClassKeyboard, kEventRawKeyRepeat},
334        {kEventClassKeyboard, kEventRawKeyUp},
335        {kEventClassKeyboard, kEventRawKeyModifiersChanged},
336        {kEventClassKeyboard, kEventHotKeyPressed},
337        {kEventClassKeyboard, kEventHotKeyReleased},
338    };
[5948]339   
[5978]340    InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler),  GetEventTypeCount(windEventList), windEventList, this, NULL);
[7866]341 }
[6706]342
343
344bool GraphicsWindowCarbon::realizeImplementation()
345{
[5978]346   
[6706]347    if (!_initialized) init();
348    if (!_initialized) return false;
349    if (!_traits) return false;
350   
[7866]351    osg::notify(osg::INFO) << "GraphicsWindowCarbon:: realizeIMplementation" << std::endl;
352   
[6706]353    setWindowDecoration(_traits->windowDecoration);
[7709]354    useCursor(_traits->useCursor);
[7841]355
[6706]356    // move the window to the right screen
[9894]357    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[6706]358    int screenLeft(0), screenTop(0);
[9894]359    if (wsi)
360    {
[6706]361        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
362    }
363   
[8017]364    WindowData *windowData = ( _traits.get() && _traits->inheritedWindowData.get() ) ? static_cast<osgViewer::GraphicsWindowCarbon::WindowData*>(_traits->inheritedWindowData.get()) : 0;
[7866]365     
[6706]366    _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true;
367   
368    if (_ownsWindow) {
369       
370        // create the window
[9894]371        Rect bounds = {_traits->y + screenTop, _traits->x + screenLeft, _traits->y + _traits->height + screenTop, _traits->x + _traits->width + screenLeft};
[6706]372        OSStatus err = 0;
373        WindowAttributes attr = computeWindowAttributes(_useWindowDecoration, _traits->supportsResize);
374       
375        err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window);
376
377        if (err) {
378            osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation() failed creating a window: " << err << std::endl;
379            return false;
380        } else {
381            osg::notify(osg::INFO) << "GraphicsWindowCarbon::realizeImplementation() - window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl;
382        }
383    }
384    else {
[7866]385         _window = windowData->getNativeWindowRef();
[6706]386    }
387   
388    Rect titleRect;
389    GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
[6934]390    _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
[6706]391   
392    if ((_ownsWindow) || (windowData && windowData->installEventHandler()))
393        installEventHandler();
394   
[5948]395    // set the window title
[7709]396    setWindowName(_traits->windowName);
[5948]397   
398    // create the context
[7039]399    AGLContext sharedContextCarbon = NULL;
400   
401    GraphicsWindowCarbon* graphicsWindowCarbon = dynamic_cast<GraphicsWindowCarbon*>(_traits->sharedContext);
402    if (graphicsWindowCarbon)
[6204]403    {
[7039]404        sharedContextCarbon = graphicsWindowCarbon->getAGLContext();
[6204]405    }
406    else
407    {
[7039]408        PixelBufferCarbon* pixelbuffer = dynamic_cast<PixelBufferCarbon*>(_traits->sharedContext);
409        if (pixelbuffer) {
410            sharedContextCarbon = pixelbuffer->getAGLContext();
411        }
[6204]412    }
[7039]413    _context = aglCreateContext (_pixelFormat, sharedContextCarbon);
[6204]414
415
[5948]416    if (!_context) {
417        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation failed creating a context: " << aglGetError() << std::endl;
418        return false;
419    }
[7866]420
421     
422    if ( windowData && windowData->getAGLDrawable() ) {
[8017]423        aglSetDrawable(_context, (AGLDrawable)*(windowData->getAGLDrawable()) );
424               
[7866]425    } else {
[8017]426        aglSetDrawable(_context, GetWindowPort(_window));
427        ShowWindow(_window);
[9894]428        MenubarController::instance()->attachWindow( new CarbonWindowAdapter(this) );
[7866]429    }
430   
[5948]431    makeCurrent();
432
[6220]433    if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) {
[6106]434        // enable Multi-threaded OpenGL Execution:
435        CGLError cgerr = kCGLNoError;
436        CGLContextObj ctx = CGLGetCurrentContext();
[5948]437
[6826]438#if 0
[6106]439        cgerr =  CGLEnable( ctx, kCGLCEMPEngine);
[6826]440#else
441        // the above use of kCGLCEMPEngine is not backwards compatible
442        // so we'll use the raw value of it to keep things compiling on older
443        // versions of OSX.
444        cgerr =  CGLEnable( ctx, static_cast <CGLContextEnable>(313) );
445#endif   
[6106]446        if (cgerr != kCGLNoError )
447        {
448            osg::notify(osg::INFO) << "GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available" << std::endl;
449        }
[6220]450    }
[5948]451   
[8017]452    InitCursor();
453   
[5948]454    //enable vsync
455    if (_traits->vsync) {
456        GLint swap = 1;
457        aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap);
458    }
459
460    _realized = true;
461    return _realized;
462}
463
464
465
466bool GraphicsWindowCarbon::makeCurrentImplementation()
467{
468       
469    return (aglSetCurrentContext(_context) == GL_TRUE);
470}
471
472bool GraphicsWindowCarbon::releaseContextImplementation()
473{
474    if (!_realized)
475    {
476        osg::notify(osg::NOTICE)<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
477        return false;
478    }
479
480    // osg::notify(osg::NOTICE)<<"makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
481    // osg::notify(osg::NOTICE)<<"   glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
482    return (aglSetCurrentContext(NULL) == GL_TRUE);
483}
484
485
486
487void GraphicsWindowCarbon::closeImplementation()
488{
[7165]489    // osg::notify(osg::INFO) << "GraphicsWindowCarbon::closeImplementation" << std::endl;
[5948]490    _valid = false;
491    _realized = false;
492   
[8017]493    // there's a possibility that the MenubarController is destructed already, so prevent a crash:
494    MenubarController* mbc = MenubarController::instance();
495    if (mbc) mbc->detachWindow(this);
[5978]496   
[5948]497    if (_pixelFormat)
498    {
499        aglDestroyPixelFormat(_pixelFormat);
500        _pixelFormat = NULL;
501    }
502   
503    if (_context)
504    {
505        aglSetDrawable(_context, NULL);
506        aglSetCurrentContext(NULL);
507        aglDestroyContext(_context);
508        _context = NULL;
509    }
510   
[6706]511    if (_ownsWindow && _window) DisposeWindow(_window);
[5948]512    _window = NULL;
513}
514
515
516
517void GraphicsWindowCarbon::swapBuffersImplementation()
518{
519    aglSwapBuffers(_context);
520}
521
522
523
524void GraphicsWindowCarbon::resizedImplementation(int x, int y, int width, int height)
525{
[5978]526    GraphicsContext::resizedImplementation(x, y, width, height);
527
[5948]528    aglUpdateContext(_context);
[5978]529    MenubarController::instance()->update();
[9894]530   
531    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
[5948]532}
533
534
535
[5978]536bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent)
[5948]537{
538
[5978]539    static unsigned int lastEmulatedMouseButton = 0;
[5948]540    // mouse down event   
541    Point wheresMyMouse;
[5978]542    GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
[5948]543   
[6678]544    wheresMyMouse.v -= _windowTitleHeight;
545    if (_useWindowDecoration && (wheresMyMouse.v < 0))
546        return false;
547   
[5978]548    Point wheresMyMouseGlobal;
549    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal);
550   
[5948]551    EventMouseButton mouseButton = 0;
552    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
[5978]553   
554    UInt32 modifierKeys;
555    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
556   
557   
[5948]558    WindowRef win;
[5978]559    int fwres = FindWindow(wheresMyMouseGlobal, &win);
[8017]560    // return false when Window is inactive; For enabling click-to-active on window by delegating event to default handler
561    if (((fwres != inContent) && (fwres > 0) && (mouseButton >= 1)) || !IsWindowActive(win))
[5948]562    {
[5978]563        return false;
[5948]564    }
565    else
566    {
[7841]567        UInt32 clickCount;
568        GetEventParameter(theEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
[5948]569        // swap right and middle buttons so that middle button is 2, right button is 3.
570        if (mouseButton==3) mouseButton = 2;
571        else if (mouseButton==2) mouseButton = 3;
572       
573        // check tablet pointer device and map it to a musebutton
574        TabletProximityRec    theTabletRecord;    // The Tablet Proximity Record
575        // Extract the Tablet Proximity reccord from the event.
576        if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec,
577                                      typeTabletProximityRec, NULL,
578                                      sizeof(TabletProximityRec),
579                                      NULL, (void *)&theTabletRecord))
580        {           
581            osgGA::GUIEventAdapter::TabletPointerType pointerType;
582            switch(theTabletRecord.pointerType)
583            {
584                case 1: // pen
585                    pointerType = osgGA::GUIEventAdapter::PEN;
586                    break;
587                   
588                case 2: // puck
589                    pointerType = osgGA::GUIEventAdapter::PUCK;
590                    break;
591                   
592                case 3: //eraser
593                    pointerType = osgGA::GUIEventAdapter::ERASER;
594                    break;
595
596                default:
597                   pointerType = osgGA::GUIEventAdapter::UNKNOWN;
598                   break;
599            }
600           
601            getEventQueue()->penProximity(pointerType, (theTabletRecord.enterProximity != 0));
602        }
603
[8085]604        // get tilt and rotation from the pen
605        TabletPointRec theTabletPointRecord;
606        if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
607                sizeof(TabletPointRec), NULL, (void *)&theTabletPointRecord))
608        {
609            int penRotation = (int)theTabletPointRecord.rotation * 9 / 575; //to get angle between 0 to 360 grad
610            penRotation = -(((penRotation + 180) % 360) - 180) ;          //for same range on all plattforms we need -180 to 180
611            getEventQueue()->penOrientation (
612                    theTabletPointRecord.tiltX * 60 / 32767.0f,  //multiply with 60 to get angle between -60 to 60 grad
613                    -theTabletPointRecord.tiltY * 60 / 32767.0f,  //multiply with 60 to get angle between -60 to 60 grad
614                    penRotation
615            );
616        }
617           
[5948]618        switch(GetEventKind(theEvent))
619        {
620            case kEventMouseDown:
621                {
622                    float mx =wheresMyMouse.h;
623                    float my =wheresMyMouse.v;
624                    transformMouseXY(mx, my);
[5978]625                   
626                    lastEmulatedMouseButton = 0;
627                   
628                    if (mouseButton == 1)
629                    {
630                        if( modifierKeys & cmdKey )
631                        {
632                            mouseButton = lastEmulatedMouseButton = 3;
633                        }
634                        else if( modifierKeys & optionKey )
635                        {
636                            mouseButton = lastEmulatedMouseButton = 2;
637                        }
638                    }
639                   
[7841]640                    if (clickCount > 1)
641                        getEventQueue()->mouseDoubleButtonPress(mx,my, mouseButton);
642                    else
643                        getEventQueue()->mouseButtonPress(mx, my, mouseButton);
[5948]644                }
645                break;
646            case kEventMouseUp:
647                {
648                    float mx =wheresMyMouse.h;
649                    float my =wheresMyMouse.v;
650                    transformMouseXY(mx, my);
[5978]651                    if (lastEmulatedMouseButton > 0) {
652                        getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton);
653                        lastEmulatedMouseButton = 0;
654                    }
655                    else {
656                        getEventQueue()->mouseButtonRelease(mx, my, mouseButton);
657                    }
[5948]658                }
659                break;
660               
661            case kEventMouseDragged:
662                {
663                    // get pressure from the pen, only when mouse/pen is dragged
664                    TabletPointRec    theTabletRecord;
665                    if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
666                                    sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) {
667                   
668                        getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f);
669           
670                    }
671                   
672                    float mx =wheresMyMouse.h;
673                    float my =wheresMyMouse.v;
674                    transformMouseXY(mx, my);
675                    getEventQueue()->mouseMotion(mx, my);
676                }
677                break;
678               
679            case kEventMouseMoved:
680                {
681                    float mx = wheresMyMouse.h;
682                    float my = wheresMyMouse.v;
683                    transformMouseXY(mx, my);
684                    getEventQueue()->mouseMotion(mx, my);
685                }
686                break;
687               
688            // mouse with scroll-wheels
689            case kEventMouseWheelMoved:
690                {
691                    EventMouseWheelAxis axis;
692                    SInt32 delta;
693                    if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) {
694                        if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) {
695                            switch (axis) {
696                                case kEventMouseWheelAxisX:
697                                    getEventQueue()->mouseScroll( (delta > 0) ? osgGA::GUIEventAdapter::SCROLL_RIGHT : osgGA::GUIEventAdapter::SCROLL_LEFT);
698                                    break;
699                                case kEventMouseWheelAxisY:
700                                    getEventQueue()->mouseScroll( (delta < 0) ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP);
701                                    break;
702                            }
703                        }
704                    }
705                }
706                break;
707           
708            // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html )
709            case 11:
710                {
711                    enum
712                        {
713                        kEventParamMouseWheelSmoothVerticalDelta       = 'saxy', // typeSInt32
[6461]714                        kEventParamMouseWheelSmoothHorizontalDelta     = 'saxx' // typeSInt32
[5948]715                        };
716                   
717                    SInt32 scroll_delta_x = 0;
718                    SInt32 scroll_delta_y = 0;
719                    OSErr err = noErr;
720                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y );
721                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x );
722                   
723                    if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) {
724                        getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y);
725                    }
726                }
727                break;
728           
729            default:
[5978]730                return false;
[5948]731        }
732    }
[5978]733   
734    return true;
[5948]735}
736
737
738
[5978]739bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent)
[5948]740{
[7884]741    handleModifierKeys(theEvent);
742       
743    OSStatus status;
[5948]744   
745    UInt32 rawkey;
746    GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey);
747   
[7866]748    // osg::notify(osg::INFO) << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
[5948]749           
750    UInt32 dataSize;
751    /* jbw check return status so that we don't allocate a huge array */
752    status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL );
[5978]753    if (status != noErr) return false;
754    if (dataSize<=1) return false;
[5948]755   
756    UniChar* uniChars = new UniChar[dataSize+1];
757    GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars );
758   
[9894]759    unsigned int keychar = remapCarbonKey(static_cast<unsigned long>(uniChars[0]), rawkey);
[5948]760   
761    switch(GetEventKind(theEvent))
762    {
763        case kEventRawKeyDown:
764        case kEventRawKeyRepeat:
765        {
[7066]766            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
[7866]767            osg::notify(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl;
[5948]768            getEventQueue()->keyPress(keychar);
769            break;
770        }
771       
772        case kEventRawKeyUp:
773        {                 
[7866]774            osg::notify(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl;
[7066]775            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
[5948]776            getEventQueue()->keyRelease(keychar);
777            break;
778        }
779       
780        default:
781             break;
782   
783    }
784
785    delete[] uniChars;
786
[5978]787    return true;
[5948]788}
789
[7884]790void GraphicsWindowCarbon::handleModifierKey(UInt32 modifierKey, UInt32 modifierMask, osgGA::GUIEventAdapter::KeySymbol keySymbol) {
[5948]791
[7884]792    if ((modifierKey & modifierMask) && !(_lastModifierKeys & modifierMask))
793    {
794        getEventQueue()->keyPress(keySymbol);
795    }
796   
797    if (!(modifierKey & modifierMask) && (_lastModifierKeys & modifierMask))
798    {
799        getEventQueue()->keyRelease(keySymbol);
800    }
801}
[5948]802
[7884]803bool GraphicsWindowCarbon::handleModifierKeys(EventRef theEvent)
804{
805    UInt32 modifierKeys;
806    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
807
808    //std::cout << modifierKeys << std::endl;
809    if (_lastModifierKeys == modifierKeys)
810        return false;
811       
812    handleModifierKey(modifierKeys, shiftKey, osgGA::GUIEventAdapter::KEY_Shift_L);
813    handleModifierKey(modifierKeys, controlKey, osgGA::GUIEventAdapter::KEY_Control_L);
814    handleModifierKey(modifierKeys, optionKey, osgGA::GUIEventAdapter::KEY_Alt_L);
815    handleModifierKey(modifierKeys, cmdKey, osgGA::GUIEventAdapter::KEY_Super_L);
816   
817    // Caps lock needs some special handling, i did not find a way to get informed when the caps-lock-key gets released   
818    if ((modifierKeys & alphaLock) && !(_lastModifierKeys & alphaLock))
819    {
820        getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock);
821        getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock);
822    }
823   
824    if (!(modifierKeys & alphaLock) && (_lastModifierKeys & alphaLock))
825    {
826        getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock);
827        getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock);
828    }
829   
830    _lastModifierKeys = modifierKeys;
831    return true;
832}
833
834
835
[5948]836void GraphicsWindowCarbon::checkEvents()
837{
838    if (!_realized) return;
839   
840    EventRef theEvent;
841    EventTargetRef theTarget = GetEventDispatcherTarget();
842    while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr)
843    {
844        switch(GetEventClass(theEvent))
845        {
[5978]846            case kEventClassMouse:
847                    {
848                    // handle the menubar
849                    Point wheresMyMouse;
850                    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
851                   
852                    EventMouseButton mouseButton = 0;
853                    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
854                   
855                    WindowRef win;
856                    int fwres = FindWindow(wheresMyMouse, &win);
857
858                    if ((fwres == inMenuBar) && (mouseButton >= 1)) {
859                        MenuSelect(wheresMyMouse);
860                        HiliteMenu(0);
861                        return;
862                    }
863                    break;
864                }
865
[5948]866            case kEventClassApplication:
867                switch (GetEventKind(theEvent)) {
868                    case kEventAppQuit:
869                        getEventQueue()->quitApplication();
870                        break;
871                }
872                break;
873           
874            case kEventClassAppleEvent:
875                {
876                    EventRecord eventRecord;
877                    ConvertEventRefToEventRecord(theEvent, &eventRecord);
878                    AEProcessAppleEvent(&eventRecord);
879                    return;
880                }
881                break;
882
883        }
884        SendEventToEventTarget (theEvent, theTarget);
885        ReleaseEvent(theEvent);       
886    } 
887    if (_closeRequested)
[7165]888        getEventQueue()->closeWindow();
[5948]889       
890    if (s_quit_requested) {
891        getEventQueue()->quitApplication();
892        s_quit_requested = false;
893    }
894           
895}
896
897
[6931]898bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height)
[6495]899{
[9894]900    int screenLeft(0), screenTop(0);
901    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
902   if (wsi)
903    {
904        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
905    }
906   
907    Rect bounds = {y + screenTop, x + screenLeft, y + height + screenTop, x + width + screenLeft};
[6706]908    SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
909    aglUpdateContext(_context);
910    MenubarController::instance()->update();
[6931]911    return true;
[6495]912}
[5948]913
[9894]914
915
916void GraphicsWindowCarbon::adaptResize(int x, int y, int w, int h)
917{
918    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
919    int screenLeft(0), screenTop(0);
920    if (wsi) {
921       
922        // get the screen containing the window
923        unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h);
924       
925        // update traits
926        _traits->screenNum = screenNdx;
927       
928        // get top left of screen
929        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
930    }
931   
932    resized(x-screenLeft,y-screenTop,w,h);
933}
934
935
936
[5948]937void GraphicsWindowCarbon::grabFocus()
938{
939    SelectWindow(_window);
940}
941
942
943
944void GraphicsWindowCarbon::grabFocusIfPointerInWindow()
945{
946   // TODO: implement
[5978]947   osg::notify(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow" << std::endl;
[5948]948}
949
950
[7709]951void GraphicsWindowCarbon::useCursor(bool cursorOn)
952{
[5948]953
[7709]954    if (_traits.valid())
955        _traits->useCursor = cursorOn;
[9894]956    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[7709]957    if (wsi == NULL) {
958        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
959        return;
960    }
961   
962    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
963    CGDisplayErr err = kCGErrorSuccess;
964    switch (cursorOn)
965    {
966        case true:
967            err = CGDisplayShowCursor(displayId);
968            break;
969        case false:
970            err = CGDisplayHideCursor(displayId);
971            break;
972    }
973    if (err != kCGErrorSuccess) {
974        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor failed with " << err << std::endl;
975    }
976}
977
[8017]978// FIXME: need to implement all cursor types
979// FIXME: I used deprecated functions, but don't know if there are any substitutable newer functions...
980void GraphicsWindowCarbon::setCursor(MouseCursor mouseCursor)
981{
982    UInt32 cursor;
983    if (_currentCursor == mouseCursor)
984      return;
985    switch (mouseCursor)
986    {
987        case NoCursor:
988          HideCursor();
989          _currentCursor = mouseCursor;
990          return;
991        case RightArrowCursor:
992            cursor = kThemeArrowCursor;
993            break;
994        case CrosshairCursor:
995            cursor = kThemeCrossCursor;
996            break;
997        case TextCursor:
998            cursor = kThemeIBeamCursor;
999            break;
1000        case UpDownCursor:
1001            cursor = kThemeResizeUpDownCursor;
1002            break;
1003        case LeftRightCursor:
1004            cursor = kThemeResizeLeftRightCursor;
1005            break;
1006        default:
1007            cursor = kThemeArrowCursor;
1008            osg::notify(osg::WARN) << "GraphicsWindowCarbon::setCursor doesn't implement cursor: type = " << mouseCursor << std::endl;
1009    }
1010   
1011    _currentCursor = mouseCursor;
1012    SetThemeCursor(cursor);
1013    ShowCursor();
1014}
[7709]1015
1016
1017void GraphicsWindowCarbon::setWindowName (const std::string& name)
1018{
1019    _traits->windowName = name;
1020    if (!_traits->windowName.empty())
1021    {
1022        CFStringRef windowtitle = CFStringCreateWithBytes( kCFAllocatorDefault, (const UInt8*)(_traits->windowName.c_str()), _traits->windowName.length(),kCFStringEncodingUTF8, false );
1023        SetWindowTitleWithCFString( _window, windowtitle );
1024        CFRelease(windowtitle);
1025    }
1026}
1027
[9120]1028void GraphicsWindowCarbon::requestWarpPointer(float x,float y)
1029{
[7709]1030
[9894]1031    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
[9120]1032    if (wsi == NULL) {
1033        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1034        return;
1035    }
[7841]1036
[9120]1037    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1038
1039    CGPoint point;
[9357]1040    point.x = x + _traits->x;
1041    point.y = y + _traits->y;
[9120]1042    CGDisplayMoveCursorToPoint(displayId, point);
1043
1044    getEventQueue()->mouseWarped(x,y);
1045}
1046
1047
[5948]1048void GraphicsWindowCarbon::transformMouseXY(float& x, float& y)
1049{
1050    if (getEventQueue()->getUseFixedMouseInputRange())
1051    {
1052        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1053        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1054        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1055    }
1056}
1057
[9894]1058class CarbonWindowingSystemInterface : public  DarwinWindowingSystemInterface {
1059public:
1060    CarbonWindowingSystemInterface()
1061    :    DarwinWindowingSystemInterface()
[5948]1062    {
[9894]1063        // register application event handler and AppleEventHandler to get quit-events:
1064        static const EventTypeSpec menueventSpec = {kEventClassCommand, kEventCommandProcess};
1065        OSErr status = InstallEventHandler(GetApplicationEventTarget(), NewEventHandlerUPP(ApplicationEventHandler), 1, &menueventSpec, 0, NULL);
1066        status = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false);
[5948]1067    }
[9894]1068   
1069    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
[5948]1070    {
[9894]1071        return createGraphicsContextImplementation<PixelBufferCarbon, GraphicsWindowCarbon>(traits);
[5948]1072    }
1073};
1074
1075
[9894]1076}
1077
1078#ifdef USE_DARWIN_CARBON_IMPLEMENTATION
1079RegisterWindowingSystemInterfaceProxy<CarbonWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1080#endif
1081
1082
[6931]1083// declare C entry point for static compilation.
1084extern "C" void graphicswindow_Carbon(void)
1085{
[9894]1086    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CarbonWindowingSystemInterface());
[6931]1087}
1088
[5948]1089#endif
Note: See TracBrowser for help on using the browser.