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

Revision 13429, 39.3 kB (checked in by robert, 12 hours ago)

Improved support for controlling the ShadingModel? via the VolumeSettings? object

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