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

Revision 9894, 39.6 kB (checked in by robert, 4 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
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#if defined (__APPLE__) && (!__LP64__)
15
16#include <osg/observer_ptr>
17
18#include <osgViewer/api/Carbon/PixelBufferCarbon>
19#include <osgViewer/api/Carbon/GraphicsWindowCarbon>
20
21#include <osg/DeleteHandler>
22
23#include <Carbon/Carbon.h>
24#include <OpenGL/OpenGL.h>
25
26#include <iostream>
27
28#include "DarwinUtils.h"
29
30using namespace osgViewer;
31using namespace osgDarwin;
32
33
34// Carbon-Eventhandler to handle the click in the close-widget and the resize of windows
35
36static pascal OSStatus GraphicsWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void* userData)
37{
38    WindowRef           window;
39    Rect                bounds;
40    OSStatus            result = eventNotHandledErr; /* report failure by default */
41   
42    osg::notify(osg::INFO) << "GraphicsWindowEventHandler" << std::endl;
43
44    GraphicsWindowCarbon* w = (GraphicsWindowCarbon*)userData;
45    if (!w)
46        return result;
47   
48    GetEventParameter(event, kEventParamDirectObject, typeWindowRef, NULL,
49                         sizeof(window), NULL, &window);
50                         
51    switch(GetEventClass(event))
52    {
53        case kEventClassTablet:
54        case kEventClassMouse:
55            if (w->handleMouseEvent(event))
56                result = noErr;
57            break;
58               
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                       
72                        w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
73                        w->requestRedraw();
74                        result = noErr;
75                        break;
76                           
77                    case kEventWindowBoundsChanged:
78                        InvalWindowRect(window, GetWindowPortBounds(window, &bounds));
79                        GetWindowBounds(window, kWindowContentRgn, &bounds);
80                        w->adaptResize(bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top);
81                        result = noErr;
82                        break;
83                   
84                    case kEventWindowClose:
85                        w->requestClose();
86                        result = noErr;
87                        break;
88         
89                    default:
90                        break;
91                }
92            }
93        default:
94            //std::cout << "unknown: " << GetEventClass(event) << std::endl;
95            break;
96    }
97   
98    //if (result == eventNotHandledErr)
99    //    result = CallNextEventHandler (nextHandler, event);
100       
101    return result;
102}
103
104
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
140class CarbonKeyboardMap {
141
142    public:
143        CarbonKeyboardMap()
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       
192        ~CarbonKeyboardMap() {
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 */
207static unsigned int remapCarbonKey(unsigned int key, unsigned int rawkey)
208{
209    static CarbonKeyboardMap s_CarbonKeyboardMap;
210    return s_CarbonKeyboardMap.remapKey(key,rawkey);
211}
212
213
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)
219    {
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;
226    }
227       
228    osgViewer::GraphicsWindow* getWindow()  { return _win.get(); }
229private:
230    osg::observer_ptr<GraphicsWindowCarbon> _win;
231};
232
233
234
235void GraphicsWindowCarbon::init()
236{
237    if (_initialized) return;
238
239    // getEventQueue()->setCurrentEventState(osgGA::GUIEventAdapter::getAccumulatedEventState().get());
240   
241    _lastModifierKeys = 0;
242    _windowTitleHeight = 0;
243    _closeRequested = false;
244    _ownsWindow = false;
245    _context = NULL;
246    _window = NULL;
247    _pixelFormat = PixelBufferCarbon::createPixelFormat(_traits.get());
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
254bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag)
255{
256    _useWindowDecoration = flag;
257
258    if (_realized)
259    {
260        OSErr err = noErr;
261        Rect bounds;
262        GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
263
264        if (_useWindowDecoration)
265        {
266            err = ChangeWindowAttributes(getNativeWindowRef(),  kWindowStandardDocumentAttributes,  kWindowNoTitleBarAttribute | kWindowNoShadowAttribute);
267            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
268        }
269        else
270        {
271            err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes);
272            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);   
273        }
274
275        if (err != noErr)
276        {
277            osg::notify(osg::WARN) << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl;
278            return false;
279        }
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();
293    }
294
295    return true;
296}
297
298
299WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) {
300    WindowAttributes attr;
301   
302    if (useWindowDecoration)
303    {
304        if (supportsResize)
305            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute);
306        else
307            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute;
308    }
309    else 
310    {
311        attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
312        if (supportsResize)
313            attr |= kWindowResizableAttribute;
314    }
315    return attr;
316}
317
318void GraphicsWindowCarbon::installEventHandler() {
319
320    // register window event handler to receive resize-events
321    EventTypeSpec   windEventList[] = {
322        { kEventClassWindow, kEventWindowBoundsChanged},
323        { kEventClassWindow, kEventWindowClose},
324       
325        {kEventClassMouse, kEventMouseDown},
326        {kEventClassMouse, kEventMouseUp},
327        {kEventClassMouse, kEventMouseMoved},
328        {kEventClassMouse, kEventMouseDragged},
329        {kEventClassMouse, kEventMouseWheelMoved},
330        {kEventClassMouse, 11 /* kEventMouseScroll */},
331
332        {kEventClassKeyboard, kEventRawKeyDown},
333        {kEventClassKeyboard, kEventRawKeyRepeat},
334        {kEventClassKeyboard, kEventRawKeyUp},
335        {kEventClassKeyboard, kEventRawKeyModifiersChanged},
336        {kEventClassKeyboard, kEventHotKeyPressed},
337        {kEventClassKeyboard, kEventHotKeyReleased},
338    };
339   
340    InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler),  GetEventTypeCount(windEventList), windEventList, this, NULL);
341 }
342
343
344bool GraphicsWindowCarbon::realizeImplementation()
345{
346   
347    if (!_initialized) init();
348    if (!_initialized) return false;
349    if (!_traits) return false;
350   
351    osg::notify(osg::INFO) << "GraphicsWindowCarbon:: realizeIMplementation" << std::endl;
352   
353    setWindowDecoration(_traits->windowDecoration);
354    useCursor(_traits->useCursor);
355
356    // move the window to the right screen
357    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
358    int screenLeft(0), screenTop(0);
359    if (wsi)
360    {
361        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
362    }
363   
364    WindowData *windowData = ( _traits.get() && _traits->inheritedWindowData.get() ) ? static_cast<osgViewer::GraphicsWindowCarbon::WindowData*>(_traits->inheritedWindowData.get()) : 0;
365     
366    _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true;
367   
368    if (_ownsWindow) {
369       
370        // create the window
371        Rect bounds = {_traits->y + screenTop, _traits->x + screenLeft, _traits->y + _traits->height + screenTop, _traits->x + _traits->width + screenLeft};
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 {
385         _window = windowData->getNativeWindowRef();
386    }
387   
388    Rect titleRect;
389    GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
390    _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
391   
392    if ((_ownsWindow) || (windowData && windowData->installEventHandler()))
393        installEventHandler();
394   
395    // set the window title
396    setWindowName(_traits->windowName);
397   
398    // create the context
399    AGLContext sharedContextCarbon = NULL;
400   
401    GraphicsWindowCarbon* graphicsWindowCarbon = dynamic_cast<GraphicsWindowCarbon*>(_traits->sharedContext);
402    if (graphicsWindowCarbon)
403    {
404        sharedContextCarbon = graphicsWindowCarbon->getAGLContext();
405    }
406    else
407    {
408        PixelBufferCarbon* pixelbuffer = dynamic_cast<PixelBufferCarbon*>(_traits->sharedContext);
409        if (pixelbuffer) {
410            sharedContextCarbon = pixelbuffer->getAGLContext();
411        }
412    }
413    _context = aglCreateContext (_pixelFormat, sharedContextCarbon);
414
415
416    if (!_context) {
417        osg::notify(osg::WARN) << "GraphicsWindowCarbon::realizeImplementation failed creating a context: " << aglGetError() << std::endl;
418        return false;
419    }
420
421     
422    if ( windowData && windowData->getAGLDrawable() ) {
423        aglSetDrawable(_context, (AGLDrawable)*(windowData->getAGLDrawable()) );
424               
425    } else {
426        aglSetDrawable(_context, GetWindowPort(_window));
427        ShowWindow(_window);
428        MenubarController::instance()->attachWindow( new CarbonWindowAdapter(this) );
429    }
430   
431    makeCurrent();
432
433    if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) {
434        // enable Multi-threaded OpenGL Execution:
435        CGLError cgerr = kCGLNoError;
436        CGLContextObj ctx = CGLGetCurrentContext();
437
438#if 0
439        cgerr =  CGLEnable( ctx, kCGLCEMPEngine);
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   
446        if (cgerr != kCGLNoError )
447        {
448            osg::notify(osg::INFO) << "GraphicsWindowCarbon:: Multi-threaded OpenGL Execution not available" << std::endl;
449        }
450    }
451   
452    InitCursor();
453   
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{
489    // osg::notify(osg::INFO) << "GraphicsWindowCarbon::closeImplementation" << std::endl;
490    _valid = false;
491    _realized = false;
492   
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);
496   
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   
511    if (_ownsWindow && _window) DisposeWindow(_window);
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{
526    GraphicsContext::resizedImplementation(x, y, width, height);
527
528    aglUpdateContext(_context);
529    MenubarController::instance()->update();
530   
531    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
532}
533
534
535
536bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent)
537{
538
539    static unsigned int lastEmulatedMouseButton = 0;
540    // mouse down event   
541    Point wheresMyMouse;
542    GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
543   
544    wheresMyMouse.v -= _windowTitleHeight;
545    if (_useWindowDecoration && (wheresMyMouse.v < 0))
546        return false;
547   
548    Point wheresMyMouseGlobal;
549    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal);
550   
551    EventMouseButton mouseButton = 0;
552    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
553   
554    UInt32 modifierKeys;
555    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
556   
557   
558    WindowRef win;
559    int fwres = FindWindow(wheresMyMouseGlobal, &win);
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))
562    {
563        return false;
564    }
565    else
566    {
567        UInt32 clickCount;
568        GetEventParameter(theEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
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
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           
618        switch(GetEventKind(theEvent))
619        {
620            case kEventMouseDown:
621                {
622                    float mx =wheresMyMouse.h;
623                    float my =wheresMyMouse.v;
624                    transformMouseXY(mx, my);
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                   
640                    if (clickCount > 1)
641                        getEventQueue()->mouseDoubleButtonPress(mx,my, mouseButton);
642                    else
643                        getEventQueue()->mouseButtonPress(mx, my, mouseButton);
644                }
645                break;
646            case kEventMouseUp:
647                {
648                    float mx =wheresMyMouse.h;
649                    float my =wheresMyMouse.v;
650                    transformMouseXY(mx, my);
651                    if (lastEmulatedMouseButton > 0) {
652                        getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton);
653                        lastEmulatedMouseButton = 0;
654                    }
655                    else {
656                        getEventQueue()->mouseButtonRelease(mx, my, mouseButton);
657                    }
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
714                        kEventParamMouseWheelSmoothHorizontalDelta     = 'saxx' // typeSInt32
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:
730                return false;
731        }
732    }
733   
734    return true;
735}
736
737
738
739bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent)
740{
741    handleModifierKeys(theEvent);
742       
743    OSStatus status;
744   
745    UInt32 rawkey;
746    GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey);
747   
748    // osg::notify(osg::INFO) << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
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 );
753    if (status != noErr) return false;
754    if (dataSize<=1) return false;
755   
756    UniChar* uniChars = new UniChar[dataSize+1];
757    GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars );
758   
759    unsigned int keychar = remapCarbonKey(static_cast<unsigned long>(uniChars[0]), rawkey);
760   
761    switch(GetEventKind(theEvent))
762    {
763        case kEventRawKeyDown:
764        case kEventRawKeyRepeat:
765        {
766            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
767            osg::notify(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl;
768            getEventQueue()->keyPress(keychar);
769            break;
770        }
771       
772        case kEventRawKeyUp:
773        {                 
774            osg::notify(osg::INFO) << "GraphicsWindowCarbon::keyPress" << std::endl;
775            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
776            getEventQueue()->keyRelease(keychar);
777            break;
778        }
779       
780        default:
781             break;
782   
783    }
784
785    delete[] uniChars;
786
787    return true;
788}
789
790void GraphicsWindowCarbon::handleModifierKey(UInt32 modifierKey, UInt32 modifierMask, osgGA::GUIEventAdapter::KeySymbol keySymbol) {
791
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}
802
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
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        {
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
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)
888        getEventQueue()->closeWindow();
889       
890    if (s_quit_requested) {
891        getEventQueue()->quitApplication();
892        s_quit_requested = false;
893    }
894           
895}
896
897
898bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height)
899{
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};
908    SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
909    aglUpdateContext(_context);
910    MenubarController::instance()->update();
911    return true;
912}
913
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
937void GraphicsWindowCarbon::grabFocus()
938{
939    SelectWindow(_window);
940}
941
942
943
944void GraphicsWindowCarbon::grabFocusIfPointerInWindow()
945{
946   // TODO: implement
947   osg::notify(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow" << std::endl;
948}
949
950
951void GraphicsWindowCarbon::useCursor(bool cursorOn)
952{
953
954    if (_traits.valid())
955        _traits->useCursor = cursorOn;
956    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
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
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}
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
1028void GraphicsWindowCarbon::requestWarpPointer(float x,float y)
1029{
1030
1031    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
1032    if (wsi == NULL) {
1033        osg::notify(osg::WARN) << "GraphicsWindowCarbon::useCursor :: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1034        return;
1035    }
1036
1037    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1038
1039    CGPoint point;
1040    point.x = x + _traits->x;
1041    point.y = y + _traits->y;
1042    CGDisplayMoveCursorToPoint(displayId, point);
1043
1044    getEventQueue()->mouseWarped(x,y);
1045}
1046
1047
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
1058class CarbonWindowingSystemInterface : public  DarwinWindowingSystemInterface {
1059public:
1060    CarbonWindowingSystemInterface()
1061    :    DarwinWindowingSystemInterface()
1062    {
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);
1067    }
1068   
1069    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1070    {
1071        return createGraphicsContextImplementation<PixelBufferCarbon, GraphicsWindowCarbon>(traits);
1072    }
1073};
1074
1075
1076}
1077
1078#ifdef USE_DARWIN_CARBON_IMPLEMENTATION
1079RegisterWindowingSystemInterfaceProxy<CarbonWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1080#endif
1081
1082
1083// declare C entry point for static compilation.
1084extern "C" void graphicswindow_Carbon(void)
1085{
1086    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CarbonWindowingSystemInterface());
1087}
1088
1089#endif
Note: See TracBrowser for help on using the browser.