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

Revision 14009, 30.1 kB (checked in by robert, 2 days ago)

From Alberto Luaces,"the current code uses the preprocessor for generating the plugin path in
a way that when CMAKE_INSTALL_PREFIX contains something along the lines
of

/usr/x86_64-linux-gnu/

it gets substituted as

/usr/x86_64-1-gnu/

that is, the string is preprocessed again, thereby making changes to
anything that matches any defined symbol, as "linux" in this example
(https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=763816).

Quoting that path directly in CMake scripts solves that problem.
"

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