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

Revision 13041, 38.9 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • 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_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    {
250        OSG_WARN << "GraphicsWindowCarbon::init could not create a valid pixelformat" << std::endl;
251    }
252    _valid = (_pixelFormat != NULL);
253    _initialized = true;
254}
255
256bool GraphicsWindowCarbon::setWindowDecorationImplementation(bool flag)
257{
258    _useWindowDecoration = flag;
259
260    if (_realized)
261    {
262        OSErr err = noErr;
263        Rect bounds;
264        GetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
265
266        if (_useWindowDecoration)
267        {
268            err = ChangeWindowAttributes(getNativeWindowRef(),  kWindowStandardDocumentAttributes,  kWindowNoTitleBarAttribute | kWindowNoShadowAttribute);
269            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
270        }
271        else
272        {
273            err = ChangeWindowAttributes(getNativeWindowRef(), kWindowNoTitleBarAttribute | kWindowNoShadowAttribute, kWindowStandardDocumentAttributes);
274            SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
275        }
276
277        if (err != noErr)
278        {
279            OSG_WARN << "GraphicsWindowCarbon::setWindowDecoration failed with " << err << std::endl;
280            return false;
281        }
282
283        // update titlebar-height
284        Rect titleRect;
285        GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
286        _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
287
288        // 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.
289        // InvalWindowRect doesn't help here :-/
290
291        aglSetDrawable(_context, 0);
292        aglSetDrawable(_context, GetWindowPort(_window));
293
294        MenubarController::instance()->update();
295    }
296
297    return true;
298}
299
300
301WindowAttributes GraphicsWindowCarbon::computeWindowAttributes(bool useWindowDecoration, bool supportsResize) {
302    WindowAttributes attr;
303
304    if (useWindowDecoration)
305    {
306        if (supportsResize)
307            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute);
308        else
309            attr = (kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute) & ~kWindowResizableAttribute;
310    }
311    else
312    {
313        attr = kWindowNoTitleBarAttribute | kWindowNoShadowAttribute | kWindowStandardHandlerAttribute;
314        if (supportsResize)
315            attr |= kWindowResizableAttribute;
316    }
317    return attr;
318}
319
320void GraphicsWindowCarbon::installEventHandler() {
321
322    // register window event handler to receive resize-events
323    EventTypeSpec   windEventList[] = {
324        { kEventClassWindow, kEventWindowBoundsChanged},
325        { kEventClassWindow, kEventWindowClose},
326
327        {kEventClassMouse, kEventMouseDown},
328        {kEventClassMouse, kEventMouseUp},
329        {kEventClassMouse, kEventMouseMoved},
330        {kEventClassMouse, kEventMouseDragged},
331        {kEventClassMouse, kEventMouseWheelMoved},
332        {kEventClassMouse, 11 /* kEventMouseScroll */},
333
334        {kEventClassKeyboard, kEventRawKeyDown},
335        {kEventClassKeyboard, kEventRawKeyRepeat},
336        {kEventClassKeyboard, kEventRawKeyUp},
337        {kEventClassKeyboard, kEventRawKeyModifiersChanged},
338        {kEventClassKeyboard, kEventHotKeyPressed},
339        {kEventClassKeyboard, kEventHotKeyReleased},
340    };
341
342    InstallWindowEventHandler(_window, NewEventHandlerUPP(GraphicsWindowEventHandler),  GetEventTypeCount(windEventList), windEventList, this, NULL);
343 }
344
345
346bool GraphicsWindowCarbon::realizeImplementation()
347{
348    if (!_initialized) init();
349    if (!_initialized) return false;
350    if (!_traits) return false;
351
352    OSG_INFO << "GraphicsWindowCarbon::realizeImplementation" << std::endl;
353
354    setWindowDecoration(_traits->windowDecoration);
355    useCursor(_traits->useCursor);
356
357    // move the window to the right screen
358    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
359    int screenLeft = 0, screenTop = 0;
360    if (wsi)
361    {
362        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
363    }
364
365    WindowData *windowData = ( _traits.get() && _traits->inheritedWindowData.get() ) ? static_cast<osgViewer::GraphicsWindowCarbon::WindowData*>(_traits->inheritedWindowData.get()) : 0;
366
367    _ownsWindow = (windowData) ? (windowData->getNativeWindowRef() == NULL) : true;
368
369    if (_ownsWindow) {
370
371        // create the window
372        Rect bounds = {_traits->y + screenTop, _traits->x + screenLeft, _traits->y + _traits->height + screenTop, _traits->x + _traits->width + screenLeft};
373        OSStatus err = 0;
374        WindowAttributes attr = computeWindowAttributes(_useWindowDecoration, _traits->supportsResize);
375
376        err = CreateNewWindow(kDocumentWindowClass, attr, &bounds, &_window);
377
378        if (err) {
379            OSG_WARN << "GraphicsWindowCarbon::realizeImplementation: failed to create window: " << err << std::endl;
380            return false;
381        } else {
382            OSG_INFO << "GraphicsWindowCarbon::realizeImplementation: window created with bounds(" << bounds.top << ", " << bounds.left << ", " << bounds.bottom << ", " << bounds.right << ")" << std::endl;
383        }
384    }
385    else {
386         _window = windowData->getNativeWindowRef();
387    }
388
389    Rect titleRect;
390    GetWindowBounds(_window, kWindowTitleBarRgn, &titleRect);
391    _windowTitleHeight = abs(titleRect.bottom - titleRect.top);
392
393    if ((_ownsWindow) || (windowData && windowData->installEventHandler()))
394        installEventHandler();
395
396    // set the window title
397    setWindowName(_traits->windowName);
398
399    // create the context
400    AGLContext sharedContextCarbon = NULL;
401
402    GraphicsHandleCarbon* graphicsHandleCarbon = dynamic_cast<GraphicsHandleCarbon*>(_traits->sharedContext);
403    if (graphicsHandleCarbon)
404    {
405        sharedContextCarbon = graphicsHandleCarbon->getAGLContext();
406    }
407
408    _context = aglCreateContext (_pixelFormat, sharedContextCarbon);
409    if (!_context) {
410        OSG_WARN << "GraphicsWindowCarbon::realizeImplementation: failed to create context: " << aglGetError() << std::endl;
411        return false;
412    }
413
414
415    if ( windowData && windowData->getAGLDrawable() ) {
416        aglSetDrawable(_context, (AGLDrawable)*(windowData->getAGLDrawable()) );
417
418    } else {
419        aglSetDrawable(_context, GetWindowPort(_window));
420        ShowWindow(_window);
421        MenubarController::instance()->attachWindow( new CarbonWindowAdapter(this) );
422    }
423
424    makeCurrent();
425
426    if ((_traits->useMultiThreadedOpenGLEngine) && (OpenThreads::GetNumberOfProcessors() > 1)) {
427        // enable Multi-threaded OpenGL Execution:
428        CGLError cgerr = kCGLNoError;
429        CGLContextObj ctx = CGLGetCurrentContext();
430
431#if 0
432        cgerr =  CGLEnable( ctx, kCGLCEMPEngine);
433#else
434        // the above use of kCGLCEMPEngine is not backwards compatible
435        // so we'll use the raw value of it to keep things compiling on older
436        // versions of OSX.
437        cgerr =  CGLEnable( ctx, static_cast <CGLContextEnable>(313) );
438#endif
439        if (cgerr != kCGLNoError )
440        {
441            OSG_INFO << "GraphicsWindowCarbon::realizeImplementation: multi-threaded OpenGL Execution not available" << std::endl;
442        }
443    }
444
445    InitCursor();
446
447    // enable vsync
448    if (_traits->vsync) {
449        GLint swap = 1;
450        aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap);
451    }
452    _currentVSync = _traits->vsync;
453
454    _realized = true;
455    return _realized;
456}
457
458
459
460bool GraphicsWindowCarbon::makeCurrentImplementation()
461{
462
463    return (aglSetCurrentContext(_context) == GL_TRUE);
464}
465
466bool GraphicsWindowCarbon::releaseContextImplementation()
467{
468    if (!_realized)
469    {
470        OSG_NOTICE<<"Warning: GraphicsWindow not realized, cannot do makeCurrent."<<std::endl;
471        return false;
472    }
473
474    // OSG_NOTICE<<"makeCurrentImplementation "<<this<<" "<<OpenThreads::Thread::CurrentThread()<<std::endl;
475    // OSG_NOTICE<<"   glXMakeCurrent ("<<_display<<","<<_window<<","<<_glxContext<<std::endl;
476    return (aglSetCurrentContext(NULL) == GL_TRUE);
477}
478
479
480
481void GraphicsWindowCarbon::closeImplementation()
482{
483    // OSG_INFO << "GraphicsWindowCarbon::closeImplementation" << std::endl;
484    _valid = false;
485    _realized = false;
486
487    // there's a possibility that the MenubarController is destructed already, so prevent a crash:
488    MenubarController* mbc = MenubarController::instance();
489    if (mbc) mbc->detachWindow(this);
490
491    if (_pixelFormat)
492    {
493        aglDestroyPixelFormat(_pixelFormat);
494        _pixelFormat = NULL;
495    }
496
497    if (_context)
498    {
499        aglSetDrawable(_context, NULL);
500        aglSetCurrentContext(NULL);
501        aglDestroyContext(_context);
502        _context = NULL;
503    }
504
505    if (_ownsWindow && _window) DisposeWindow(_window);
506    _window = NULL;
507}
508
509
510
511void GraphicsWindowCarbon::swapBuffersImplementation()
512{
513    // check for vsync change
514    if (_traits.valid() && _traits->vsync != _currentVSync)
515    {
516        const bool on = _traits->vsync;
517        GLint swap = (on ? 1 : 0);
518        aglSetInteger (_context, AGL_SWAP_INTERVAL, &swap);
519        OSG_NOTICE << "GraphicsWindowCarbon: VSync=" << (on ? "on" : "off") << std::endl;
520        _currentVSync = on;
521    }
522
523    aglSwapBuffers(_context);
524}
525
526
527
528void GraphicsWindowCarbon::resizedImplementation(int x, int y, int width, int height)
529{
530    GraphicsContext::resizedImplementation(x, y, width, height);
531
532    aglUpdateContext(_context);
533    MenubarController::instance()->update();
534
535    getEventQueue()->windowResize(x,y,width, height, getEventQueue()->getTime());
536}
537
538
539
540bool GraphicsWindowCarbon::handleMouseEvent(EventRef theEvent)
541{
542
543    static unsigned int lastEmulatedMouseButton = 0;
544    // mouse down event
545    Point wheresMyMouse;
546    GetEventParameter (theEvent, kEventParamWindowMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
547
548    wheresMyMouse.v -= _windowTitleHeight;
549    if (_useWindowDecoration && (wheresMyMouse.v < 0))
550        return false;
551
552    Point wheresMyMouseGlobal;
553    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouseGlobal);
554
555    EventMouseButton mouseButton = 0;
556    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
557
558    UInt32 modifierKeys;
559    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
560
561
562    WindowRef win;
563    int fwres = FindWindow(wheresMyMouseGlobal, &win);
564    // return false when Window is inactive; For enabling click-to-active on window by delegating event to default handler
565    if (((fwres != inContent) && (fwres > 0) && (mouseButton >= 1)) || !IsWindowActive(win))
566    {
567        return false;
568    }
569    else
570    {
571        UInt32 clickCount;
572        GetEventParameter(theEvent, kEventParamClickCount, typeUInt32, NULL, sizeof(clickCount), NULL, &clickCount);
573        // swap right and middle buttons so that middle button is 2, right button is 3.
574        if (mouseButton==3) mouseButton = 2;
575        else if (mouseButton==2) mouseButton = 3;
576
577        // check tablet pointer device and map it to a mouse button
578        TabletProximityRec    theTabletRecord;    // The Tablet Proximity Record
579        // Extract the Tablet Proximity reccord from the event.
580        if(noErr == GetEventParameter(theEvent, kEventParamTabletProximityRec,
581                                      typeTabletProximityRec, NULL,
582                                      sizeof(TabletProximityRec),
583                                      NULL, (void *)&theTabletRecord))
584        {
585            osgGA::GUIEventAdapter::TabletPointerType pointerType;
586            switch(theTabletRecord.pointerType)
587            {
588                case 1: // pen
589                    pointerType = osgGA::GUIEventAdapter::PEN;
590                    break;
591
592                case 2: // puck
593                    pointerType = osgGA::GUIEventAdapter::PUCK;
594                    break;
595
596                case 3: // eraser
597                    pointerType = osgGA::GUIEventAdapter::ERASER;
598                    break;
599
600                default:
601                   pointerType = osgGA::GUIEventAdapter::UNKNOWN;
602                   break;
603            }
604
605            getEventQueue()->penProximity(pointerType, (theTabletRecord.enterProximity != 0));
606        }
607
608        // get tilt and rotation from the pen
609        TabletPointRec theTabletPointRecord;
610        if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
611                sizeof(TabletPointRec), NULL, (void *)&theTabletPointRecord))
612        {
613            int penRotation = (int)theTabletPointRecord.rotation * 9 / 575; //to get angle between 0 to 360 grad
614            penRotation = -(((penRotation + 180) % 360) - 180) ;          //for same range on all plattforms we need -180 to 180
615            getEventQueue()->penOrientation (
616                    theTabletPointRecord.tiltX * 60 / 32767.0f,  //multiply with 60 to get angle between -60 to 60 grad
617                    -theTabletPointRecord.tiltY * 60 / 32767.0f,  //multiply with 60 to get angle between -60 to 60 grad
618                    penRotation
619            );
620        }
621
622        switch(GetEventKind(theEvent))
623        {
624            case kEventMouseDown:
625                {
626                    float mx = wheresMyMouse.h;
627                    float my = wheresMyMouse.v;
628                    transformMouseXY(mx, my);
629
630                    lastEmulatedMouseButton = 0;
631
632                    if (mouseButton == 1)
633                    {
634                        if( modifierKeys & cmdKey )
635                        {
636                            mouseButton = lastEmulatedMouseButton = 3;
637                        }
638                        else if( modifierKeys & optionKey )
639                        {
640                            mouseButton = lastEmulatedMouseButton = 2;
641                        }
642                    }
643
644                    if (clickCount > 1)
645                        getEventQueue()->mouseDoubleButtonPress(mx,my, mouseButton);
646                    else
647                        getEventQueue()->mouseButtonPress(mx, my, mouseButton);
648                }
649                break;
650            case kEventMouseUp:
651                {
652                    float mx = wheresMyMouse.h;
653                    float my = wheresMyMouse.v;
654                    transformMouseXY(mx, my);
655                    if (lastEmulatedMouseButton > 0) {
656                        getEventQueue()->mouseButtonRelease(mx, my, lastEmulatedMouseButton);
657                        lastEmulatedMouseButton = 0;
658                    }
659                    else {
660                        getEventQueue()->mouseButtonRelease(mx, my, mouseButton);
661                    }
662                }
663                break;
664
665            case kEventMouseDragged:
666                {
667                    // get pressure from the pen, only when mouse/pen is dragged
668                    TabletPointRec    theTabletRecord;
669                    if(noErr == GetEventParameter(theEvent,  kEventParamTabletPointRec, typeTabletPointRec, NULL,
670                                    sizeof(TabletPointRec), NULL, (void *)&theTabletRecord)) {
671
672                        getEventQueue()->penPressure(theTabletRecord.pressure / 65535.0f);
673                    }
674
675                    float mx = wheresMyMouse.h;
676                    float my = wheresMyMouse.v;
677                    transformMouseXY(mx, my);
678                    getEventQueue()->mouseMotion(mx, my);
679                }
680                break;
681
682            case kEventMouseMoved:
683                {
684                    float mx = wheresMyMouse.h;
685                    float my = wheresMyMouse.v;
686                    transformMouseXY(mx, my);
687                    getEventQueue()->mouseMotion(mx, my);
688                }
689                break;
690
691            // mouse with scroll-wheels
692            case kEventMouseWheelMoved:
693                {
694                    EventMouseWheelAxis axis;
695                    SInt32 delta;
696                    if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(axis), NULL, &axis )) {
697                        if (noErr == GetEventParameter( theEvent, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(delta), NULL, &delta )) {
698                            switch (axis) {
699                                case kEventMouseWheelAxisX:
700                                    getEventQueue()->mouseScroll( (delta > 0) ? osgGA::GUIEventAdapter::SCROLL_RIGHT : osgGA::GUIEventAdapter::SCROLL_LEFT);
701                                    break;
702                                case kEventMouseWheelAxisY:
703                                    getEventQueue()->mouseScroll( (delta < 0) ? osgGA::GUIEventAdapter::SCROLL_DOWN : osgGA::GUIEventAdapter::SCROLL_UP);
704                                    break;
705                            }
706                        }
707                    }
708                }
709                break;
710
711            // new trackpads and mighty mouse, (not officially documented, see http://developer.apple.com/qa/qa2005/qa1453.html )
712            case 11:
713                {
714                    enum
715                    {
716                        kEventParamMouseWheelSmoothVerticalDelta       = 'saxy', // typeSInt32
717                        kEventParamMouseWheelSmoothHorizontalDelta     = 'saxx' // typeSInt32
718                    };
719
720                    SInt32 scroll_delta_x = 0;
721                    SInt32 scroll_delta_y = 0;
722                    OSErr err = noErr;
723                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothVerticalDelta, typeLongInteger, NULL, sizeof(scroll_delta_y), NULL, &scroll_delta_y );
724                    err = GetEventParameter( theEvent, kEventParamMouseWheelSmoothHorizontalDelta, typeLongInteger, NULL, sizeof(scroll_delta_x), NULL, &scroll_delta_x );
725
726                    if ((scroll_delta_x != 0) || (scroll_delta_y != 0)) {
727                        getEventQueue()->mouseScroll2D( scroll_delta_x, scroll_delta_y);
728                    }
729                }
730                break;
731
732            default:
733                return false;
734        }
735    }
736
737    return true;
738}
739
740
741
742bool GraphicsWindowCarbon::handleKeyboardEvent(EventRef theEvent)
743{
744    handleModifierKeys(theEvent);
745
746    OSStatus status;
747
748    UInt32 rawkey;
749    GetEventParameter (theEvent,kEventParamKeyCode,typeUInt32, NULL,sizeof(rawkey), NULL,&rawkey);
750
751    // OSG_INFO << "key code: " << rawkey << " modifiers: " << modifierKeys << std::endl;
752
753    UInt32 dataSize;
754    /* jbw check return status so that we don't allocate a huge array */
755    status = GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, 0, &dataSize, NULL );
756    if (status != noErr) return false;
757    if (dataSize<=1) return false;
758
759    UniChar* uniChars = new UniChar[dataSize+1];
760    GetEventParameter( theEvent, kEventParamKeyUnicodes, typeUnicodeText, NULL, dataSize, NULL, (void*)uniChars );
761
762    unsigned int keychar = remapCarbonKey(static_cast<unsigned long>(uniChars[0]), rawkey);
763
764    switch(GetEventKind(theEvent))
765    {
766        case kEventRawKeyDown:
767        case kEventRawKeyRepeat:
768        {
769            //OSG_INFO << "GraphicsWindowCarbon::keyPress Up" << std::endl;
770            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
771            //OSG_INFO << "GraphicsWindowCarbon::keyPress" << std::endl;
772            getEventQueue()->keyPress(keychar);
773            break;
774        }
775
776        case kEventRawKeyUp:
777        {
778            //OSG_INFO << "GraphicsWindowCarbon::keyPress" << std::endl;
779            //getEventQueue()->getCurrentEventState()->setModKeyMask(modifierMask);
780            getEventQueue()->keyRelease(keychar);
781            break;
782        }
783
784        default:
785             break;
786
787    }
788
789    delete[] uniChars;
790
791    return true;
792}
793
794void GraphicsWindowCarbon::handleModifierKey(UInt32 modifierKey, UInt32 modifierMask, osgGA::GUIEventAdapter::KeySymbol keySymbol) {
795
796    if ((modifierKey & modifierMask) && !(_lastModifierKeys & modifierMask))
797    {
798        getEventQueue()->keyPress(keySymbol);
799    }
800
801    if (!(modifierKey & modifierMask) && (_lastModifierKeys & modifierMask))
802    {
803        getEventQueue()->keyRelease(keySymbol);
804    }
805}
806
807bool GraphicsWindowCarbon::handleModifierKeys(EventRef theEvent)
808{
809    UInt32 modifierKeys;
810    GetEventParameter (theEvent,kEventParamKeyModifiers,typeUInt32, NULL,sizeof(modifierKeys), NULL,&modifierKeys);
811
812    //std::cout << modifierKeys << std::endl;
813    if (_lastModifierKeys == modifierKeys)
814        return false;
815
816    handleModifierKey(modifierKeys, shiftKey, osgGA::GUIEventAdapter::KEY_Shift_L);
817    handleModifierKey(modifierKeys, controlKey, osgGA::GUIEventAdapter::KEY_Control_L);
818    handleModifierKey(modifierKeys, optionKey, osgGA::GUIEventAdapter::KEY_Alt_L);
819    handleModifierKey(modifierKeys, cmdKey, osgGA::GUIEventAdapter::KEY_Super_L);
820
821    // Caps lock needs some special handling, i did not find a way to get informed when the caps-lock-key gets released
822    if ((modifierKeys & alphaLock) && !(_lastModifierKeys & alphaLock))
823    {
824        getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock);
825        getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock);
826    }
827
828    if (!(modifierKeys & alphaLock) && (_lastModifierKeys & alphaLock))
829    {
830        getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_Caps_Lock);
831        getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_Caps_Lock);
832    }
833
834    _lastModifierKeys = modifierKeys;
835    return true;
836}
837
838
839
840void GraphicsWindowCarbon::checkEvents()
841{
842    if (!_realized) return;
843
844    EventRef theEvent;
845    EventTargetRef theTarget = GetEventDispatcherTarget();
846    while (ReceiveNextEvent(0, NULL, 0,true, &theEvent)== noErr)
847    {
848        switch(GetEventClass(theEvent))
849        {
850            case kEventClassMouse:
851                    {
852                    // handle the menubar
853                    Point wheresMyMouse;
854                    GetEventParameter (theEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(wheresMyMouse), NULL, &wheresMyMouse);
855
856                    EventMouseButton mouseButton = 0;
857                    GetEventParameter (theEvent, kEventParamMouseButton, typeMouseButton, NULL, sizeof(mouseButton), NULL, &mouseButton);
858
859                    WindowRef win;
860                    int fwres = FindWindow(wheresMyMouse, &win);
861
862                    if ((fwres == inMenuBar) && (mouseButton >= 1)) {
863                        MenuSelect(wheresMyMouse);
864                        HiliteMenu(0);
865                        return;
866                    }
867                    break;
868                }
869
870            case kEventClassApplication:
871                switch (GetEventKind(theEvent)) {
872                    case kEventAppQuit:
873                        getEventQueue()->quitApplication();
874                        break;
875                }
876                break;
877
878            case kEventClassAppleEvent:
879                {
880                    EventRecord eventRecord;
881                    ConvertEventRefToEventRecord(theEvent, &eventRecord);
882                    AEProcessAppleEvent(&eventRecord);
883                    return;
884                }
885                break;
886
887        }
888        SendEventToEventTarget (theEvent, theTarget);
889        ReleaseEvent(theEvent);
890    }
891    if (_closeRequested)
892        getEventQueue()->closeWindow();
893
894    if (s_quit_requested) {
895        getEventQueue()->quitApplication();
896        s_quit_requested = false;
897    }
898
899}
900
901
902bool GraphicsWindowCarbon::setWindowRectangleImplementation(int x, int y, int width, int height)
903{
904    int screenLeft(0), screenTop(0);
905    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
906   if (wsi)
907    {
908        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
909    }
910
911    Rect bounds = {y + screenTop, x + screenLeft, y + height + screenTop, x + width + screenLeft};
912    SetWindowBounds(getNativeWindowRef(), kWindowContentRgn, &bounds);
913    aglUpdateContext(_context);
914    MenubarController::instance()->update();
915    return true;
916}
917
918
919
920void GraphicsWindowCarbon::adaptResize(int x, int y, int w, int h)
921{
922    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
923    int screenLeft(0), screenTop(0);
924    if (wsi) {
925
926        // get the screen containing the window
927        unsigned int screenNdx = wsi->getScreenContaining(x,y,w,h);
928
929        // update traits
930        _traits->screenNum = screenNdx;
931
932        // get top left of screen
933        wsi->getScreenTopLeft((*_traits), screenLeft, screenTop);
934    }
935
936    resized(x-screenLeft,y-screenTop,w,h);
937}
938
939
940
941void GraphicsWindowCarbon::grabFocus()
942{
943    SelectWindow(_window);
944}
945
946
947
948void GraphicsWindowCarbon::grabFocusIfPointerInWindow()
949{
950   // TODO: implement
951   OSG_NOTIFY(osg::ALWAYS) << "GraphicsWindowCarbon::grabFocusIfPointerInWindow: not implemented" << std::endl;
952}
953
954
955void GraphicsWindowCarbon::useCursor(bool cursorOn)
956{
957    if (_traits.valid())
958        _traits->useCursor = cursorOn;
959    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
960    if (wsi == NULL) {
961        OSG_WARN << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl;
962        return;
963    }
964
965    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
966    CGDisplayErr err = (cursorOn ? CGDisplayShowCursor(displayId) : CGDisplayHideCursor(displayId));
967    if (err != kCGErrorSuccess) {
968        OSG_WARN << "GraphicsWindowCarbon::useCursor: failed with " << err << std::endl;
969    }
970}
971
972// FIXME: need to implement all cursor types
973// FIXME: I used deprecated functions, but don't know if there are any substitutable newer functions...
974void GraphicsWindowCarbon::setCursor(MouseCursor mouseCursor)
975{
976    if (_currentCursor == mouseCursor)
977      return;
978
979    UInt32 cursor;
980    switch (mouseCursor)
981    {
982        case NoCursor:
983          HideCursor();
984          _currentCursor = mouseCursor;
985          return;
986        case RightArrowCursor:
987            cursor = kThemeArrowCursor;
988            break;
989        case CrosshairCursor:
990            cursor = kThemeCrossCursor;
991            break;
992        case TextCursor:
993            cursor = kThemeIBeamCursor;
994            break;
995        case UpDownCursor:
996            cursor = kThemeResizeUpDownCursor;
997            break;
998        case LeftRightCursor:
999            cursor = kThemeResizeLeftRightCursor;
1000            break;
1001        default:
1002            cursor = kThemeArrowCursor;
1003            OSG_WARN << "GraphicsWindowCarbon::setCursor doesn't implement cursor: type = " << mouseCursor << std::endl;
1004    }
1005
1006    _currentCursor = mouseCursor;
1007    SetThemeCursor(cursor);
1008    ShowCursor();
1009}
1010
1011void GraphicsWindowCarbon::setSyncToVBlank(bool on)
1012{
1013    if (_traits.valid()) {
1014        _traits->vsync = on;
1015    }
1016}
1017
1018void GraphicsWindowCarbon::setWindowName (const std::string& name)
1019{
1020    _traits->windowName = name;
1021    if (!_traits->windowName.empty())
1022    {
1023        CFStringRef windowtitle = CFStringCreateWithBytes( kCFAllocatorDefault, (const UInt8*)(_traits->windowName.c_str()), _traits->windowName.length(),kCFStringEncodingUTF8, false );
1024        SetWindowTitleWithCFString( _window, windowtitle );
1025        CFRelease(windowtitle);
1026    }
1027}
1028
1029void GraphicsWindowCarbon::requestWarpPointer(float x,float y)
1030{
1031    if (!_realized)
1032    {
1033        OSG_INFO<<"GraphicsWindowCarbon::requestWarpPointer() - Window not realized; cannot warp pointer, screenNum="<< _traits->screenNum<<std::endl;
1034        return;
1035    }
1036
1037    DarwinWindowingSystemInterface* wsi = dynamic_cast<DarwinWindowingSystemInterface*>(osg::GraphicsContext::getWindowingSystemInterface());
1038    if (wsi == NULL)
1039    {
1040        OSG_WARN << "GraphicsWindowCarbon::useCursor: could not get OSXCarbonWindowingSystemInterface" << std::endl;
1041        return;
1042    }
1043
1044    CGDirectDisplayID displayId = wsi->getDisplayID((*_traits));
1045
1046    CGPoint point;
1047    point.x = x + _traits->x;
1048    point.y = y + _traits->y;
1049    CGDisplayMoveCursorToPoint(displayId, point);
1050
1051    getEventQueue()->mouseWarped(x,y);
1052}
1053
1054
1055void GraphicsWindowCarbon::transformMouseXY(float& x, float& y)
1056{
1057    if (getEventQueue()->getUseFixedMouseInputRange())
1058    {
1059        osgGA::GUIEventAdapter* eventState = getEventQueue()->getCurrentEventState();
1060        x = eventState->getXmin() + (eventState->getXmax()-eventState->getXmin())*x/float(_traits->width);
1061        y = eventState->getYmin() + (eventState->getYmax()-eventState->getYmin())*y/float(_traits->height);
1062    }
1063}
1064
1065class CarbonWindowingSystemInterface : public  DarwinWindowingSystemInterface {
1066public:
1067    CarbonWindowingSystemInterface() : DarwinWindowingSystemInterface()
1068    {
1069    }
1070
1071    virtual osg::GraphicsContext* createGraphicsContext(osg::GraphicsContext::Traits* traits)
1072    {
1073        _init();
1074
1075        return createGraphicsContextImplementation<PixelBufferCarbon, GraphicsWindowCarbon>(traits);
1076    }
1077
1078    virtual void _init()
1079    {
1080        if (_initialized) return;
1081
1082        DarwinWindowingSystemInterface::_init();
1083
1084        // register application event handler and AppleEventHandler to get quit-events:
1085        static const EventTypeSpec menueventSpec = {kEventClassCommand, kEventCommandProcess};
1086        OSErr status = InstallEventHandler(GetApplicationEventTarget(), NewEventHandlerUPP(ApplicationEventHandler), 1, &menueventSpec, 0, NULL);
1087        status = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false);
1088    }
1089
1090};
1091
1092
1093}
1094
1095#ifdef USE_DARWIN_CARBON_IMPLEMENTATION
1096RegisterWindowingSystemInterfaceProxy<CarbonWindowingSystemInterface> createWindowingSystemInterfaceProxy;
1097#endif
1098
1099
1100// declare C entry point for static compilation.
1101extern "C" void graphicswindow_Carbon(void)
1102{
1103    osg::GraphicsContext::setWindowingSystemInterface(new osgViewer::CarbonWindowingSystemInterface());
1104}
1105
1106#endif
Note: See TracBrowser for help on using the browser.