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

Revision 13482, 29.4 kB (checked in by robert, 49 minutes ago)

Improved widget/VolumeSettings updates to use new Property.ModifiedCount? to make sure updates are only done when required.

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