root/OpenSceneGraph/trunk/src/osgQt/GraphicsWindowQt.cpp @ 14044

Revision 14044, 30.3 kB (checked in by robert, 57 minutes ago)

Added if () block to avoid script variables set to NOT-Found being used in searching

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 2009 Wang Rui
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#include <osg/DeleteHandler>
15#include <osgQt/GraphicsWindowQt>
16#include <osgViewer/ViewerBase>
17#include <QInputEvent>
18
19using namespace osgQt;
20
21
22class QtKeyboardMap
23{
24
25public:
26    QtKeyboardMap()
27    {
28        mKeyMap[Qt::Key_Escape     ] = osgGA::GUIEventAdapter::KEY_Escape;
29        mKeyMap[Qt::Key_Delete   ] = osgGA::GUIEventAdapter::KEY_Delete;
30        mKeyMap[Qt::Key_Home       ] = osgGA::GUIEventAdapter::KEY_Home;
31        mKeyMap[Qt::Key_Enter      ] = osgGA::GUIEventAdapter::KEY_KP_Enter;
32        mKeyMap[Qt::Key_End        ] = osgGA::GUIEventAdapter::KEY_End;
33        mKeyMap[Qt::Key_Return     ] = osgGA::GUIEventAdapter::KEY_Return;
34        mKeyMap[Qt::Key_PageUp     ] = osgGA::GUIEventAdapter::KEY_Page_Up;
35        mKeyMap[Qt::Key_PageDown   ] = osgGA::GUIEventAdapter::KEY_Page_Down;
36        mKeyMap[Qt::Key_Left       ] = osgGA::GUIEventAdapter::KEY_Left;
37        mKeyMap[Qt::Key_Right      ] = osgGA::GUIEventAdapter::KEY_Right;
38        mKeyMap[Qt::Key_Up         ] = osgGA::GUIEventAdapter::KEY_Up;
39        mKeyMap[Qt::Key_Down       ] = osgGA::GUIEventAdapter::KEY_Down;
40        mKeyMap[Qt::Key_Backspace  ] = osgGA::GUIEventAdapter::KEY_BackSpace;
41        mKeyMap[Qt::Key_Tab        ] = osgGA::GUIEventAdapter::KEY_Tab;
42        mKeyMap[Qt::Key_Space      ] = osgGA::GUIEventAdapter::KEY_Space;
43        mKeyMap[Qt::Key_Delete     ] = osgGA::GUIEventAdapter::KEY_Delete;
44        mKeyMap[Qt::Key_Alt      ] = osgGA::GUIEventAdapter::KEY_Alt_L;
45        mKeyMap[Qt::Key_Shift    ] = osgGA::GUIEventAdapter::KEY_Shift_L;
46        mKeyMap[Qt::Key_Control  ] = osgGA::GUIEventAdapter::KEY_Control_L;
47        mKeyMap[Qt::Key_Meta     ] = osgGA::GUIEventAdapter::KEY_Meta_L;
48
49        mKeyMap[Qt::Key_F1             ] = osgGA::GUIEventAdapter::KEY_F1;
50        mKeyMap[Qt::Key_F2             ] = osgGA::GUIEventAdapter::KEY_F2;
51        mKeyMap[Qt::Key_F3             ] = osgGA::GUIEventAdapter::KEY_F3;
52        mKeyMap[Qt::Key_F4             ] = osgGA::GUIEventAdapter::KEY_F4;
53        mKeyMap[Qt::Key_F5             ] = osgGA::GUIEventAdapter::KEY_F5;
54        mKeyMap[Qt::Key_F6             ] = osgGA::GUIEventAdapter::KEY_F6;
55        mKeyMap[Qt::Key_F7             ] = osgGA::GUIEventAdapter::KEY_F7;
56        mKeyMap[Qt::Key_F8             ] = osgGA::GUIEventAdapter::KEY_F8;
57        mKeyMap[Qt::Key_F9             ] = osgGA::GUIEventAdapter::KEY_F9;
58        mKeyMap[Qt::Key_F10            ] = osgGA::GUIEventAdapter::KEY_F10;
59        mKeyMap[Qt::Key_F11            ] = osgGA::GUIEventAdapter::KEY_F11;
60        mKeyMap[Qt::Key_F12            ] = osgGA::GUIEventAdapter::KEY_F12;
61        mKeyMap[Qt::Key_F13            ] = osgGA::GUIEventAdapter::KEY_F13;
62        mKeyMap[Qt::Key_F14            ] = osgGA::GUIEventAdapter::KEY_F14;
63        mKeyMap[Qt::Key_F15            ] = osgGA::GUIEventAdapter::KEY_F15;
64        mKeyMap[Qt::Key_F16            ] = osgGA::GUIEventAdapter::KEY_F16;
65        mKeyMap[Qt::Key_F17            ] = osgGA::GUIEventAdapter::KEY_F17;
66        mKeyMap[Qt::Key_F18            ] = osgGA::GUIEventAdapter::KEY_F18;
67        mKeyMap[Qt::Key_F19            ] = osgGA::GUIEventAdapter::KEY_F19;
68        mKeyMap[Qt::Key_F20            ] = osgGA::GUIEventAdapter::KEY_F20;
69
70        mKeyMap[Qt::Key_hyphen         ] = '-';
71        mKeyMap[Qt::Key_Equal         ] = '=';
72
73        mKeyMap[Qt::Key_division      ] = osgGA::GUIEventAdapter::KEY_KP_Divide;
74        mKeyMap[Qt::Key_multiply      ] = osgGA::GUIEventAdapter::KEY_KP_Multiply;
75        mKeyMap[Qt::Key_Minus         ] = '-';
76        mKeyMap[Qt::Key_Plus          ] = '+';
77        //mKeyMap[Qt::Key_H              ] = osgGA::GUIEventAdapter::KEY_KP_Home;
78        //mKeyMap[Qt::Key_                    ] = osgGA::GUIEventAdapter::KEY_KP_Up;
79        //mKeyMap[92                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Up;
80        //mKeyMap[86                    ] = osgGA::GUIEventAdapter::KEY_KP_Left;
81        //mKeyMap[87                    ] = osgGA::GUIEventAdapter::KEY_KP_Begin;
82        //mKeyMap[88                    ] = osgGA::GUIEventAdapter::KEY_KP_Right;
83        //mKeyMap[83                    ] = osgGA::GUIEventAdapter::KEY_KP_End;
84        //mKeyMap[84                    ] = osgGA::GUIEventAdapter::KEY_KP_Down;
85        //mKeyMap[85                    ] = osgGA::GUIEventAdapter::KEY_KP_Page_Down;
86        mKeyMap[Qt::Key_Insert        ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
87        //mKeyMap[Qt::Key_Delete        ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
88    }
89
90    ~QtKeyboardMap()
91    {
92    }
93
94    int remapKey(QKeyEvent* event)
95    {
96        KeyMap::iterator itr = mKeyMap.find(event->key());
97        if (itr == mKeyMap.end())
98        {
99            return int(*(event->text().toLatin1().data()));
100        }
101        else
102            return itr->second;
103    }
104
105    private:
106    typedef std::map<unsigned int, int> KeyMap;
107    KeyMap mKeyMap;
108};
109
110static QtKeyboardMap s_QtKeyboardMap;
111
112
113/// The object responsible for the scene re-rendering.
114class HeartBeat : public QObject {
115public:
116int _timerId;
117osg::Timer _lastFrameStartTime;
118osg::observer_ptr< osgViewer::ViewerBase > _viewer;
119
120HeartBeat();
121virtual ~HeartBeat();
122void init( osgViewer::ViewerBase *viewer );
123void stopTimer();
124void timerEvent( QTimerEvent *event );
125};
126
127static HeartBeat heartBeat;
128
129#if (QT_VERSION < QT_VERSION_CHECK(5, 2, 0))
130    #define GETDEVICEPIXELRATIO() 1.0
131#else
132    #define GETDEVICEPIXELRATIO() devicePixelRatio()
133#endif
134
135GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents )
136: QGLWidget(parent, shareWidget, f),
137_gw( NULL ),
138_forwardKeyEvents( forwardKeyEvents )
139{
140    _devicePixelRatio = GETDEVICEPIXELRATIO();
141}
142
143GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
144                    bool forwardKeyEvents )
145: QGLWidget(context, parent, shareWidget, f),
146_gw( NULL ),
147_forwardKeyEvents( forwardKeyEvents )
148{
149    _devicePixelRatio = GETDEVICEPIXELRATIO();
150}
151
152GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f,
153                    bool forwardKeyEvents )
154: QGLWidget(format, parent, shareWidget, f),
155_gw( NULL ),
156_forwardKeyEvents( forwardKeyEvents )
157{
158    _devicePixelRatio = GETDEVICEPIXELRATIO();
159}
160
161GLWidget::~GLWidget()
162{
163    // close GraphicsWindowQt and remove the reference to us
164    if( _gw )
165    {
166        _gw->close();
167        _gw->_widget = NULL;
168        _gw = NULL;
169    }
170}
171
172void GLWidget::processDeferredEvents()
173{
174    QQueue<QEvent::Type> deferredEventQueueCopy;
175    {
176        QMutexLocker lock(&_deferredEventQueueMutex);
177        deferredEventQueueCopy = _deferredEventQueue;
178        _eventCompressor.clear();
179        _deferredEventQueue.clear();
180    }
181
182    while (!deferredEventQueueCopy.isEmpty())
183    {
184        QEvent event(deferredEventQueueCopy.dequeue());
185        QGLWidget::event(&event);
186    }
187}
188
189bool GLWidget::event( QEvent* event )
190{
191
192    // QEvent::Hide
193    //
194    // workaround "Qt-workaround" that does glFinish before hiding the widget
195    // (the Qt workaround was seen at least in Qt 4.6.3 and 4.7.0)
196    //
197    // Qt makes the context current, performs glFinish, and releases the context.
198    // This makes the problem in OSG multithreaded environment as the context
199    // is active in another thread, thus it can not be made current for the purpose
200    // of glFinish in this thread.
201
202    // QEvent::ParentChange
203    //
204    // Reparenting GLWidget may create a new underlying window and a new GL context.
205    // Qt will then call doneCurrent on the GL context about to be deleted. The thread
206    // where old GL context was current has no longer current context to render to and
207    // we cannot make new GL context current in this thread.
208
209    // We workaround above problems by deferring execution of problematic event requests.
210    // These events has to be enqueue and executed later in a main GUI thread (GUI operations
211    // outside the main thread are not allowed) just before makeCurrent is called from the
212    // right thread. The good place for doing that is right after swap in a swapBuffersImplementation.
213
214    if (event->type() == QEvent::Hide)
215    {
216        // enqueue only the last of QEvent::Hide and QEvent::Show
217        enqueueDeferredEvent(QEvent::Hide, QEvent::Show);
218        return true;
219    }
220    else if (event->type() == QEvent::Show)
221    {
222        // enqueue only the last of QEvent::Show or QEvent::Hide
223        enqueueDeferredEvent(QEvent::Show, QEvent::Hide);
224        return true;
225    }
226    else if (event->type() == QEvent::ParentChange)
227    {
228        // enqueue only the last QEvent::ParentChange
229        enqueueDeferredEvent(QEvent::ParentChange);
230        return true;
231    }
232
233    // perform regular event handling
234    return QGLWidget::event( event );
235}
236
237void GLWidget::setKeyboardModifiers( QInputEvent* event )
238{
239    int modkey = event->modifiers() & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier);
240    unsigned int mask = 0;
241    if ( modkey & Qt::ShiftModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_SHIFT;
242    if ( modkey & Qt::ControlModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_CTRL;
243    if ( modkey & Qt::AltModifier ) mask |= osgGA::GUIEventAdapter::MODKEY_ALT;
244    _gw->getEventQueue()->getCurrentEventState()->setModKeyMask( mask );
245}
246
247void GLWidget::resizeEvent( QResizeEvent* event )
248{
249    const QSize& size = event->size();
250
251    int scaled_width = static_cast<int>(size.width()*_devicePixelRatio);
252    int scaled_height = static_cast<int>(size.height()*_devicePixelRatio);
253    _gw->resized( x(), y(), scaled_width,  scaled_height);
254    _gw->getEventQueue()->windowResize( x(), y(), scaled_width, scaled_height );
255    _gw->requestRedraw();
256}
257
258void GLWidget::moveEvent( QMoveEvent* event )
259{
260    const QPoint& pos = event->pos();
261    int scaled_width = static_cast<int>(width()*_devicePixelRatio);
262    int scaled_height = static_cast<int>(height()*_devicePixelRatio);
263    _gw->resized( pos.x(), pos.y(), scaled_width,  scaled_height );
264    _gw->getEventQueue()->windowResize( pos.x(), pos.y(), scaled_width,  scaled_height );
265}
266
267void GLWidget::glDraw()
268{
269    _gw->requestRedraw();
270}
271
272void GLWidget::keyPressEvent( QKeyEvent* event )
273{
274    setKeyboardModifiers( event );
275    int value = s_QtKeyboardMap.remapKey( event );
276    _gw->getEventQueue()->keyPress( value );
277
278    // this passes the event to the regular Qt key event processing,
279    // among others, it closes popup windows on ESC and forwards the event to the parent widgets
280    if( _forwardKeyEvents )
281        inherited::keyPressEvent( event );
282}
283
284void GLWidget::keyReleaseEvent( QKeyEvent* event )
285{
286    if( event->isAutoRepeat() )
287    {
288        event->ignore();
289    }
290    else
291    {
292        setKeyboardModifiers( event );
293        int value = s_QtKeyboardMap.remapKey( event );
294        _gw->getEventQueue()->keyRelease( value );
295    }
296
297    // this passes the event to the regular Qt key event processing,
298    // among others, it closes popup windows on ESC and forwards the event to the parent widgets
299    if( _forwardKeyEvents )
300        inherited::keyReleaseEvent( event );
301}
302
303void GLWidget::mousePressEvent( QMouseEvent* event )
304{
305    int button = 0;
306    switch ( event->button() )
307    {
308        case Qt::LeftButton: button = 1; break;
309        case Qt::MidButton: button = 2; break;
310        case Qt::RightButton: button = 3; break;
311        case Qt::NoButton: button = 0; break;
312        default: button = 0; break;
313    }
314    setKeyboardModifiers( event );
315    _gw->getEventQueue()->mouseButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
316}
317
318void GLWidget::mouseReleaseEvent( QMouseEvent* event )
319{
320    int button = 0;
321    switch ( event->button() )
322    {
323        case Qt::LeftButton: button = 1; break;
324        case Qt::MidButton: button = 2; break;
325        case Qt::RightButton: button = 3; break;
326        case Qt::NoButton: button = 0; break;
327        default: button = 0; break;
328    }
329    setKeyboardModifiers( event );
330    _gw->getEventQueue()->mouseButtonRelease( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
331}
332
333void GLWidget::mouseDoubleClickEvent( QMouseEvent* event )
334{
335    int button = 0;
336    switch ( event->button() )
337    {
338        case Qt::LeftButton: button = 1; break;
339        case Qt::MidButton: button = 2; break;
340        case Qt::RightButton: button = 3; break;
341        case Qt::NoButton: button = 0; break;
342        default: button = 0; break;
343    }
344    setKeyboardModifiers( event );
345    _gw->getEventQueue()->mouseDoubleButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
346}
347
348void GLWidget::mouseMoveEvent( QMouseEvent* event )
349{
350    setKeyboardModifiers( event );
351    _gw->getEventQueue()->mouseMotion( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio );
352}
353
354void GLWidget::wheelEvent( QWheelEvent* event )
355{
356    setKeyboardModifiers( event );
357    _gw->getEventQueue()->mouseScroll(
358        event->orientation() == Qt::Vertical ?
359            (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
360            (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) );
361}
362
363
364
365GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )
366:   _realized(false)
367{
368
369    _widget = NULL;
370    _traits = traits;
371    init( parent, shareWidget, f );
372}
373
374GraphicsWindowQt::GraphicsWindowQt( GLWidget* widget )
375:   _realized(false)
376{
377    _widget = widget;
378    _traits = _widget ? createTraits( _widget ) : new osg::GraphicsContext::Traits;
379    init( NULL, NULL, 0 );
380}
381
382GraphicsWindowQt::~GraphicsWindowQt()
383{
384    close();
385
386    // remove reference from GLWidget
387    if ( _widget )
388        _widget->_gw = NULL;
389}
390
391bool GraphicsWindowQt::init( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f )
392{
393    // update _widget and parent by WindowData
394    WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
395    if ( !_widget )
396        _widget = windowData ? windowData->_widget : NULL;
397    if ( !parent )
398        parent = windowData ? windowData->_parent : NULL;
399
400    // create widget if it does not exist
401    _ownsWidget = _widget == NULL;
402    if ( !_widget )
403    {
404        // shareWidget
405        if ( !shareWidget ) {
406            GraphicsWindowQt* sharedContextQt = dynamic_cast<GraphicsWindowQt*>(_traits->sharedContext.get());
407            if ( sharedContextQt )
408                shareWidget = sharedContextQt->getGLWidget();
409        }
410
411        // WindowFlags
412        Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint;
413        if ( _traits->windowDecoration )
414            flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint
415#if (QT_VERSION_CHECK(4, 5, 0) <= QT_VERSION)
416                | Qt::WindowCloseButtonHint
417#endif
418                ;
419
420        // create widget
421        _widget = new GLWidget( traits2qglFormat( _traits.get() ), parent, shareWidget, flags );
422    }
423
424    // set widget name and position
425    // (do not set it when we inherited the widget)
426    if ( _ownsWidget )
427    {
428        _widget->setWindowTitle( _traits->windowName.c_str() );
429        _widget->move( _traits->x, _traits->y );
430        if ( !_traits->supportsResize ) _widget->setFixedSize( _traits->width, _traits->height );
431        else _widget->resize( _traits->width, _traits->height );
432    }
433
434    // initialize widget properties
435    _widget->setAutoBufferSwap( false );
436    _widget->setMouseTracking( true );
437    _widget->setFocusPolicy( Qt::WheelFocus );
438    _widget->setGraphicsWindow( this );
439    useCursor( _traits->useCursor );
440
441    // initialize State
442    setState( new osg::State );
443    getState()->setGraphicsContext(this);
444
445    // initialize contextID
446    if ( _traits.valid() && _traits->sharedContext.valid() )
447    {
448        getState()->setContextID( _traits->sharedContext->getState()->getContextID() );
449        incrementContextIDUsageCount( getState()->getContextID() );
450    }
451    else
452    {
453        getState()->setContextID( osg::GraphicsContext::createNewContextID() );
454    }
455
456    // make sure the event queue has the correct window rectangle size and input range
457    getEventQueue()->syncWindowRectangleWithGraphcisContext();
458
459    return true;
460}
461
462QGLFormat GraphicsWindowQt::traits2qglFormat( const osg::GraphicsContext::Traits* traits )
463{
464    QGLFormat format( QGLFormat::defaultFormat() );
465
466    format.setAlphaBufferSize( traits->alpha );
467    format.setRedBufferSize( traits->red );
468    format.setGreenBufferSize( traits->green );
469    format.setBlueBufferSize( traits->blue );
470    format.setDepthBufferSize( traits->depth );
471    format.setStencilBufferSize( traits->stencil );
472    format.setSampleBuffers( traits->sampleBuffers );
473    format.setSamples( traits->samples );
474
475    format.setAlpha( traits->alpha>0 );
476    format.setDepth( traits->depth>0 );
477    format.setStencil( traits->stencil>0 );
478    format.setDoubleBuffer( traits->doubleBuffer );
479    format.setSwapInterval( traits->vsync ? 1 : 0 );
480    format.setStereo( traits->quadBufferStereo ? 1 : 0 );
481
482    return format;
483}
484
485void GraphicsWindowQt::qglFormat2traits( const QGLFormat& format, osg::GraphicsContext::Traits* traits )
486{
487    traits->red = format.redBufferSize();
488    traits->green = format.greenBufferSize();
489    traits->blue = format.blueBufferSize();
490    traits->alpha = format.alpha() ? format.alphaBufferSize() : 0;
491    traits->depth = format.depth() ? format.depthBufferSize() : 0;
492    traits->stencil = format.stencil() ? format.stencilBufferSize() : 0;
493
494    traits->sampleBuffers = format.sampleBuffers() ? 1 : 0;
495    traits->samples = format.samples();
496
497    traits->quadBufferStereo = format.stereo();
498    traits->doubleBuffer = format.doubleBuffer();
499
500    traits->vsync = format.swapInterval() >= 1;
501}
502
503osg::GraphicsContext::Traits* GraphicsWindowQt::createTraits( const QGLWidget* widget )
504{
505    osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits;
506
507    qglFormat2traits( widget->format(), traits );
508
509    QRect r = widget->geometry();
510    traits->x = r.x();
511    traits->y = r.y();
512    traits->width = r.width();
513    traits->height = r.height();
514
515    traits->windowName = widget->windowTitle().toLocal8Bit().data();
516    Qt::WindowFlags f = widget->windowFlags();
517    traits->windowDecoration = ( f & Qt::WindowTitleHint ) &&
518                            ( f & Qt::WindowMinMaxButtonsHint ) &&
519                            ( f & Qt::WindowSystemMenuHint );
520    QSizePolicy sp = widget->sizePolicy();
521    traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed ||
522                            sp.verticalPolicy() != QSizePolicy::Fixed;
523
524    return traits;
525}
526
527bool GraphicsWindowQt::setWindowRectangleImplementation( int x, int y, int width, int height )
528{
529    if ( _widget == NULL )
530        return false;
531
532    _widget->setGeometry( x, y, width, height );
533    return true;
534}
535
536void GraphicsWindowQt::getWindowRectangle( int& x, int& y, int& width, int& height )
537{
538    if ( _widget )
539    {
540        const QRect& geom = _widget->geometry();
541        x = geom.x();
542        y = geom.y();
543        width = geom.width();
544        height = geom.height();
545    }
546}
547
548bool GraphicsWindowQt::setWindowDecorationImplementation( bool windowDecoration )
549{
550    Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
551    if ( windowDecoration )
552        flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint;
553    _traits->windowDecoration = windowDecoration;
554
555    if ( _widget )
556    {
557        _widget->setWindowFlags( flags );
558
559        return true;
560    }
561
562    return false;
563}
564
565bool GraphicsWindowQt::getWindowDecoration() const
566{
567    return _traits->windowDecoration;
568}
569
570void GraphicsWindowQt::grabFocus()
571{
572    if ( _widget )
573        _widget->setFocus( Qt::ActiveWindowFocusReason );
574}
575
576void GraphicsWindowQt::grabFocusIfPointerInWindow()
577{
578    if ( _widget->underMouse() )
579        _widget->setFocus( Qt::ActiveWindowFocusReason );
580}
581
582void GraphicsWindowQt::raiseWindow()
583{
584    if ( _widget )
585        _widget->raise();
586}
587
588void GraphicsWindowQt::setWindowName( const std::string& name )
589{
590    if ( _widget )
591        _widget->setWindowTitle( name.c_str() );
592}
593
594std::string GraphicsWindowQt::getWindowName()
595{
596    return _widget ? _widget->windowTitle().toStdString() : "";
597}
598
599void GraphicsWindowQt::useCursor( bool cursorOn )
600{
601    if ( _widget )
602    {
603        _traits->useCursor = cursorOn;
604        if ( !cursorOn ) _widget->setCursor( Qt::BlankCursor );
605        else _widget->setCursor( _currentCursor );
606    }
607}
608
609void GraphicsWindowQt::setCursor( MouseCursor cursor )
610{
611    if ( cursor==InheritCursor && _widget )
612    {
613        _widget->unsetCursor();
614    }
615
616    switch ( cursor )
617    {
618    case NoCursor: _currentCursor = Qt::BlankCursor; break;
619    case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break;
620    case InfoCursor: _currentCursor = Qt::SizeAllCursor; break;
621    case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break;
622    case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break;
623    case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break;
624    case SprayCursor: _currentCursor = Qt::SizeAllCursor; break;
625    case WaitCursor: _currentCursor = Qt::WaitCursor; break;
626    case TextCursor: _currentCursor = Qt::IBeamCursor; break;
627    case CrosshairCursor: _currentCursor = Qt::CrossCursor; break;
628    case HandCursor: _currentCursor = Qt::OpenHandCursor; break;
629    case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break;
630    case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break;
631    case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break;
632    case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break;
633    case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break;
634    case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break;
635    case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break;
636    case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break;
637    default: break;
638    };
639    if ( _widget ) _widget->setCursor( _currentCursor );
640}
641
642bool GraphicsWindowQt::valid() const
643{
644    return _widget && _widget->isValid();
645}
646
647bool GraphicsWindowQt::realizeImplementation()
648{
649    // save the current context
650    // note: this will save only Qt-based contexts
651    const QGLContext *savedContext = QGLContext::currentContext();
652
653    // initialize GL context for the widget
654    if ( !valid() )
655        _widget->glInit();
656
657    // make current
658    _realized = true;
659    bool result = makeCurrent();
660    _realized = false;
661
662    // fail if we do not have current context
663    if ( !result )
664    {
665        if ( savedContext )
666            const_cast< QGLContext* >( savedContext )->makeCurrent();
667
668        OSG_WARN << "Window realize: Can make context current." << std::endl;
669        return false;
670    }
671
672    _realized = true;
673
674    // make sure the event queue has the correct window rectangle size and input range
675    getEventQueue()->syncWindowRectangleWithGraphcisContext();
676
677    // make this window's context not current
678    // note: this must be done as we will probably make the context current from another thread
679    //       and it is not allowed to have one context current in two threads
680    if( !releaseContext() )
681        OSG_WARN << "Window realize: Can not release context." << std::endl;
682
683    // restore previous context
684    if ( savedContext )
685        const_cast< QGLContext* >( savedContext )->makeCurrent();
686
687    return true;
688}
689
690bool GraphicsWindowQt::isRealizedImplementation() const
691{
692    return _realized;
693}
694
695void GraphicsWindowQt::closeImplementation()
696{
697    if ( _widget )
698        _widget->close();
699    _realized = false;
700}
701
702void GraphicsWindowQt::runOperations()
703{
704    // While in graphics thread this is last chance to do something useful before
705    // graphics thread will execute its operations.
706    if (_widget->getNumDeferredEvents() > 0)
707        _widget->processDeferredEvents();
708
709    if (QGLContext::currentContext() != _widget->context())
710        _widget->makeCurrent();
711
712    GraphicsWindow::runOperations();
713}
714
715bool GraphicsWindowQt::makeCurrentImplementation()
716{
717    if (_widget->getNumDeferredEvents() > 0)
718        _widget->processDeferredEvents();
719
720    _widget->makeCurrent();
721
722    return true;
723}
724
725bool GraphicsWindowQt::releaseContextImplementation()
726{
727    _widget->doneCurrent();
728    return true;
729}
730
731void GraphicsWindowQt::swapBuffersImplementation()
732{
733    _widget->swapBuffers();
734
735    // FIXME: the processDeferredEvents should really be executed in a GUI (main) thread context but
736    // I couln't find any reliable way to do this. For now, lets hope non of *GUI thread only operations* will
737    // be executed in a QGLWidget::event handler. On the other hand, calling GUI only operations in the
738    // QGLWidget event handler is an indication of a Qt bug.
739    if (_widget->getNumDeferredEvents() > 0)
740        _widget->processDeferredEvents();
741
742    // We need to call makeCurrent here to restore our previously current context
743    // which may be changed by the processDeferredEvents function.
744    if (QGLContext::currentContext() != _widget->context())
745        _widget->makeCurrent();
746}
747
748void GraphicsWindowQt::requestWarpPointer( float x, float y )
749{
750    if ( _widget )
751        QCursor::setPos( _widget->mapToGlobal(QPoint((int)x,(int)y)) );
752}
753
754
755class QtWindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
756{
757public:
758
759    QtWindowingSystem()
760    {
761        OSG_INFO << "QtWindowingSystemInterface()" << std::endl;
762    }
763
764    ~QtWindowingSystem()
765    {
766        if (osg::Referenced::getDeleteHandler())
767        {
768            osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
769            osg::Referenced::getDeleteHandler()->flushAll();
770        }
771    }
772
773    // Access the Qt windowing system through this singleton class.
774    static QtWindowingSystem* getInterface()
775    {
776        static QtWindowingSystem* qtInterface = new QtWindowingSystem;
777        return qtInterface;
778    }
779
780    // Return the number of screens present in the system
781    virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& /*si*/ )
782    {
783        OSG_WARN << "osgQt: getNumScreens() not implemented yet." << std::endl;
784        return 0;
785    }
786
787    // Return the resolution of specified screen
788    // (0,0) is returned if screen is unknown
789    virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, osg::GraphicsContext::ScreenSettings & /*resolution*/ )
790    {
791        OSG_WARN << "osgQt: getScreenSettings() not implemented yet." << std::endl;
792    }
793
794    // Set the resolution for given screen
795    virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, const osg::GraphicsContext::ScreenSettings & /*resolution*/ )
796    {
797        OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl;
798        return false;
799    }
800
801    // Enumerates available resolutions
802    virtual void enumerateScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*screenIdentifier*/, osg::GraphicsContext::ScreenSettingsList & /*resolution*/ )
803    {
804        OSG_WARN << "osgQt: enumerateScreenSettings() not implemented yet." << std::endl;
805    }
806
807    // Create a graphics context with given traits
808    virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits )
809    {
810        if (traits->pbuffer)
811        {
812            OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl;
813            return NULL;
814        }
815        else
816        {
817            osg::ref_ptr< GraphicsWindowQt > window = new GraphicsWindowQt( traits );
818            if (window->valid()) return window.release();
819            else return NULL;
820        }
821    }
822
823private:
824
825    // No implementation for these
826    QtWindowingSystem( const QtWindowingSystem& );
827    QtWindowingSystem& operator=( const QtWindowingSystem& );
828};
829
830
831// declare C entry point for static compilation.
832extern "C" void OSGQT_EXPORT graphicswindow_Qt(void)
833{
834    osg::GraphicsContext::setWindowingSystemInterface(QtWindowingSystem::getInterface());
835}
836
837
838void osgQt::initQtWindowingSystem()
839{
840    graphicswindow_Qt();
841}
842
843
844
845void osgQt::setViewer( osgViewer::ViewerBase *viewer )
846{
847    heartBeat.init( viewer );
848}
849
850
851/// Constructor. Must be called from main thread.
852HeartBeat::HeartBeat() : _timerId( 0 )
853{
854}
855
856
857/// Destructor. Must be called from main thread.
858HeartBeat::~HeartBeat()
859{
860    stopTimer();
861}
862
863
864void HeartBeat::stopTimer()
865{
866    if ( _timerId != 0 )
867    {
868        killTimer( _timerId );
869        _timerId = 0;
870    }
871}
872
873
874/// Initializes the loop for viewer. Must be called from main thread.
875void HeartBeat::init( osgViewer::ViewerBase *viewer )
876{
877    if( _viewer == viewer )
878        return;
879
880    stopTimer();
881
882    _viewer = viewer;
883
884    if( viewer )
885    {
886        _timerId = startTimer( 0 );
887        _lastFrameStartTime.setStartTick( 0 );
888    }
889}
890
891
892void HeartBeat::timerEvent( QTimerEvent */*event*/ )
893{
894    osg::ref_ptr< osgViewer::ViewerBase > viewer;
895    if( !_viewer.lock( viewer ) )
896    {
897        // viewer has been deleted -> stop timer
898        stopTimer();
899        return;
900    }
901
902    // limit the frame rate
903    if( viewer->getRunMaxFrameRate() > 0.0)
904    {
905        double dt = _lastFrameStartTime.time_s();
906        double minFrameTime = 1.0 / viewer->getRunMaxFrameRate();
907        if (dt < minFrameTime)
908            OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-dt)));
909    }
910    else
911    {
912        // avoid excessive CPU loading when no frame is required in ON_DEMAND mode
913        if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND )
914        {
915            double dt = _lastFrameStartTime.time_s();
916            if (dt < 0.01)
917                OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(0.01-dt)));
918        }
919
920        // record start frame time
921        _lastFrameStartTime.setStartTick();
922
923        // make frame
924        if( viewer->getRunFrameScheme() == osgViewer::ViewerBase::ON_DEMAND )
925        {
926            if( viewer->checkNeedToDoFrame() )
927            {
928                viewer->frame();
929            }
930        }
931        else
932        {
933            viewer->frame();
934        }
935    }
936}
Note: See TracBrowser for help on using the browser.