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

Revision 13130, 38.9 kB (checked in by robert, 15 hours ago)

From Jason Beverage, "It looks like the Callback header got accidentally removed from the CMakeLists.txt in the submission yesterday for the geometry instancing example."

  • 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.get());
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.