1
0
Fork 0

Remove the custom graphics window impl

Probably not worth the compat hassle :)
This commit is contained in:
James Turner 2021-03-08 17:00:58 +00:00
parent c92c41a50f
commit 37272b14ac
2 changed files with 0 additions and 1091 deletions

View file

@ -1,898 +0,0 @@
// Copyright (C) 2017 James Turner
// derived from OSG GraphicsWindowQt by Wang Rui
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <osg/DeleteHandler>
#include <osg/Version>
#include "GraphicsWindowQt5.hxx"
#include <osgViewer/ViewerBase>
#include <QInputEvent>
#include <QDebug>
#include <QThread>
#include <QScreen>
#include <QGuiApplication>
#include <QAbstractEventDispatcher>
#include <QOpenGLContext>
#include <QSurfaceFormat>
#include <QTimer>
#include <Main/fg_props.hxx>
using namespace flightgear;
class QtKeyboardMap
{
public:
QtKeyboardMap()
{
mKeyMap[Qt::Key_Escape ] = osgGA::GUIEventAdapter::KEY_Escape;
mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete;
mKeyMap[Qt::Key_Home ] = osgGA::GUIEventAdapter::KEY_Home;
mKeyMap[Qt::Key_Enter ] = osgGA::GUIEventAdapter::KEY_KP_Enter;
mKeyMap[Qt::Key_End ] = osgGA::GUIEventAdapter::KEY_End;
mKeyMap[Qt::Key_Return ] = osgGA::GUIEventAdapter::KEY_Return;
mKeyMap[Qt::Key_PageUp ] = osgGA::GUIEventAdapter::KEY_Page_Up;
mKeyMap[Qt::Key_PageDown ] = osgGA::GUIEventAdapter::KEY_Page_Down;
mKeyMap[Qt::Key_Left ] = osgGA::GUIEventAdapter::KEY_Left;
mKeyMap[Qt::Key_Right ] = osgGA::GUIEventAdapter::KEY_Right;
mKeyMap[Qt::Key_Up ] = osgGA::GUIEventAdapter::KEY_Up;
mKeyMap[Qt::Key_Down ] = osgGA::GUIEventAdapter::KEY_Down;
mKeyMap[Qt::Key_Backspace ] = osgGA::GUIEventAdapter::KEY_BackSpace;
mKeyMap[Qt::Key_Tab ] = osgGA::GUIEventAdapter::KEY_Tab;
mKeyMap[Qt::Key_Space ] = osgGA::GUIEventAdapter::KEY_Space;
mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_Delete;
mKeyMap[Qt::Key_Alt ] = osgGA::GUIEventAdapter::KEY_Alt_L;
mKeyMap[Qt::Key_Shift ] = osgGA::GUIEventAdapter::KEY_Shift_L;
#if defined(Q_OS_MACOS)
// undo the Qt-mac remapping
mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Control_L;
mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Meta_L;
#else
mKeyMap[Qt::Key_Control ] = osgGA::GUIEventAdapter::KEY_Control_L;
mKeyMap[Qt::Key_Meta ] = osgGA::GUIEventAdapter::KEY_Meta_L;
#endif
mKeyMap[Qt::Key_Super_L ] = osgGA::GUIEventAdapter::KEY_Super_L;
mKeyMap[Qt::Key_Super_R ] = osgGA::GUIEventAdapter::KEY_Super_R;
mKeyMap[Qt::Key_Hyper_L ] = osgGA::GUIEventAdapter::KEY_Hyper_L;
mKeyMap[Qt::Key_Hyper_R ] = osgGA::GUIEventAdapter::KEY_Hyper_R;
mKeyMap[Qt::Key_F1 ] = osgGA::GUIEventAdapter::KEY_F1;
mKeyMap[Qt::Key_F2 ] = osgGA::GUIEventAdapter::KEY_F2;
mKeyMap[Qt::Key_F3 ] = osgGA::GUIEventAdapter::KEY_F3;
mKeyMap[Qt::Key_F4 ] = osgGA::GUIEventAdapter::KEY_F4;
mKeyMap[Qt::Key_F5 ] = osgGA::GUIEventAdapter::KEY_F5;
mKeyMap[Qt::Key_F6 ] = osgGA::GUIEventAdapter::KEY_F6;
mKeyMap[Qt::Key_F7 ] = osgGA::GUIEventAdapter::KEY_F7;
mKeyMap[Qt::Key_F8 ] = osgGA::GUIEventAdapter::KEY_F8;
mKeyMap[Qt::Key_F9 ] = osgGA::GUIEventAdapter::KEY_F9;
mKeyMap[Qt::Key_F10 ] = osgGA::GUIEventAdapter::KEY_F10;
mKeyMap[Qt::Key_F11 ] = osgGA::GUIEventAdapter::KEY_F11;
mKeyMap[Qt::Key_F12 ] = osgGA::GUIEventAdapter::KEY_F12;
mKeyMap[Qt::Key_F13 ] = osgGA::GUIEventAdapter::KEY_F13;
mKeyMap[Qt::Key_F14 ] = osgGA::GUIEventAdapter::KEY_F14;
mKeyMap[Qt::Key_F15 ] = osgGA::GUIEventAdapter::KEY_F15;
mKeyMap[Qt::Key_F16 ] = osgGA::GUIEventAdapter::KEY_F16;
mKeyMap[Qt::Key_F17 ] = osgGA::GUIEventAdapter::KEY_F17;
mKeyMap[Qt::Key_F18 ] = osgGA::GUIEventAdapter::KEY_F18;
mKeyMap[Qt::Key_F19 ] = osgGA::GUIEventAdapter::KEY_F19;
mKeyMap[Qt::Key_F20 ] = osgGA::GUIEventAdapter::KEY_F20;
mKeyMap[Qt::Key_Insert ] = osgGA::GUIEventAdapter::KEY_KP_Insert;
//mKeyMap[Qt::Key_Delete ] = osgGA::GUIEventAdapter::KEY_KP_Delete;
}
~QtKeyboardMap()
{
}
int remapKey(QKeyEvent* event)
{
const QChar unicodePoint = event->text().isEmpty() ? QChar() : event->text().at(0);
KeyMap::iterator itr = mKeyMap.find(event->key());
if (itr == mKeyMap.end()) {
if (unicodePoint.isNull()) {
// this happens for Ctrl modifiers on A-Z (at least). Keyboard.xml relies on the
// old ASCII mappings of these values, so we need to synthesise those here
// since Qt won't do it.
const auto k = event->key();
if ((k >= Qt::Key_A) && (k <= Qt::Key_Z)) {
return 1 + (k - Qt::Key_A); // offset into the ASCII control code range
} else {
qWarning() << Q_FUNC_INFO << "misssing mapping for key";
}
}
#if 0
qDebug() << "key" << event->key() << ", mods" << event->modifiers() << "Unicode:" << unicodePoint << ", ASCII:"
<< unicodePoint.toLatin1() << "(" << (int)unicodePoint.toLatin1() << "), raw text:" << event->text();
#endif
return int(unicodePoint.toLatin1());
}
return itr->second;
}
private:
typedef std::map<unsigned int, int> KeyMap;
KeyMap mKeyMap;
};
static QtKeyboardMap s_QtKeyboardMap;
GLWindow::GLWindow()
: QWindow()
{
_devicePixelRatio = 1.0;
connect(this, &QWindow::screenChanged, this, &GLWindow::onScreenChanged);
onScreenChanged();
}
void GLWindow::onScreenChanged()
{
qWarning() << Q_FUNC_INFO << "screen changed";
_devicePixelRatio = screen()->devicePixelRatio();
if (_isPrimaryWindow) {
// allow PUI and Canvas to be scaled
fgSetDouble("/sim/rendering/gui-pixel-ratio", _devicePixelRatio);
}
syncGeometryWithOSG();
}
void GLWindow::syncGeometryWithOSG()
{
const int w = width();
const int h = height();
int scaled_width = static_cast<int>(w *_devicePixelRatio);
int scaled_height = static_cast<int>(h*_devicePixelRatio);
if (_gw) {
_gw->resized( x(), y(), scaled_width, scaled_height);
_gw->getEventQueue()->windowResize( x(), y(), scaled_width, scaled_height );
_gw->requestRedraw();
_gw->_updateContextNeeded = true;
}
}
GLWindow::~GLWindow()
{
if (_gw) {
_gw->_window = nullptr;
_gw = nullptr;
}
}
bool GLWindow::event( QEvent* event )
{
if (event->type() == QEvent::WindowStateChange) {
// keep full-screen state in sync
const bool isFullscreen = (windowState() == Qt::WindowFullScreen);
if (_isPrimaryWindow) {
fgSetBool("/sim/startup/fullscreen", isFullscreen);
}
}
else if (event->type() == QEvent::UpdateRequest)
{
processUpdateEvent();
}
else if (event->type() == QEvent::Close) {
// spin an 'are you sure'? dialog here
// need to decide immediately unfortunately.
_gw->getEventQueue()->closeWindow();
}
// perform regular event handling
return QWindow::event( event );
}
void GLWindow::processUpdateEvent()
{
osg::ref_ptr<osgViewer::ViewerBase> v;
if (_gw->_viewer.lock(v)) {
v->frame();
}
// see discussion of QWindow::requestUpdate to see
// why this is good behaviour
if (_gw->_continousUpdate) {
requestUpdate();
}
}
static void setOSGModifier(int& modifiers, unsigned int bits, bool set)
{
if (set) {
modifiers |= bits;
} else {
modifiers &= ~bits;
}
}
void GLWindow::setKeyboardModifiers(const Qt::KeyboardModifiers qtMods)
{
auto es = _gw->getEventQueue()->getCurrentEventState();
auto modifiers = es->getModKeyMask();
#if defined(Q_OS_MACOS)
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_CTRL, qtMods & Qt::MetaModifier);
#else
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_CTRL, qtMods & Qt::ControlModifier);
#endif
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_ALT, qtMods & Qt::AltModifier);
setOSGModifier(modifiers, osgGA::GUIEventAdapter::MODKEY_SHIFT, qtMods & Qt::ShiftModifier);
_gw->getEventQueue()->getCurrentEventState()->setModKeyMask(modifiers);
}
void GLWindow::resizeEvent( QResizeEvent* event )
{
QWindow::resizeEvent(event);
syncGeometryWithOSG();
}
void GLWindow::moveEvent( QMoveEvent* event )
{
QWindow::moveEvent(event);
syncGeometryWithOSG();
}
void GLWindow::keyPressEvent( QKeyEvent* event )
{
setKeyboardModifiers( event->modifiers() );
int value = s_QtKeyboardMap.remapKey( event );
_gw->getEventQueue()->keyPress( value );
// this passes the event to the regular Qt key event processing,
// among others, it closes popup windows on ESC and forwards the event to the parent widgets
if( _forwardKeyEvents )
inherited::keyPressEvent( event );
}
void GLWindow::keyReleaseEvent( QKeyEvent* event )
{
if (event->isAutoRepeat()) {
event->ignore();
} else {
setKeyboardModifiers(event->modifiers() );
int value = s_QtKeyboardMap.remapKey( event );
_gw->getEventQueue()->keyRelease( value );
}
// this passes the event to the regular Qt key event processing,
// among others, it closes popup windows on ESC and forwards the event to the parent widgets
if( _forwardKeyEvents )
inherited::keyReleaseEvent( event );
}
void GLWindow::mousePressEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
void GLWindow::mouseReleaseEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseButtonRelease( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
void GLWindow::mouseDoubleClickEvent( QMouseEvent* event )
{
int button = 0;
switch ( event->button() )
{
case Qt::LeftButton: button = 1; break;
case Qt::MidButton: button = 2; break;
case Qt::RightButton: button = 3; break;
case Qt::NoButton: button = 0; break;
default: button = 0; break;
}
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseDoubleButtonPress( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio, button );
}
void GLWindow::mouseMoveEvent( QMouseEvent* event )
{
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseMotion( event->x()*_devicePixelRatio, event->y()*_devicePixelRatio );
}
void GLWindow::wheelEvent( QWheelEvent* event )
{
setKeyboardModifiers(event->modifiers());
_gw->getEventQueue()->mouseScroll(
event->orientation() == Qt::Vertical ?
(event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN) :
(event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) );
}
GraphicsWindowQt5::GraphicsWindowQt5(osg::GraphicsContext::Traits* traits)
{
_traits = traits;
init(0);
}
GraphicsWindowQt5::~GraphicsWindowQt5()
{
OSG_INFO << "destroying GraphicsWindowQt5" << std::endl;
close();
}
bool GraphicsWindowQt5::init( Qt::WindowFlags f )
{
// update _widget and parent by WindowData
WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : 0;
assert(!_window);
_ownsWidget = true;
// WindowFlags
Qt::WindowFlags flags = f | Qt::Window | Qt::CustomizeWindowHint;
if ( _traits->windowDecoration ) {
flags |= Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
flags |= Qt::WindowFullscreenButtonHint;
// TODO - check if this is desirable or not on Windows+Linux
//flags |= Qt::MaximizeUsingFullscreenGeometryHint;
}
// create window
_window.reset(new GLWindow);
_window->setFlags(flags);
_window->setSurfaceType(QSurface::OpenGLSurface);
_window->setFormat(traits2qSurfaceFormat(_traits.get()));
_window->create();
_window->setTitle( _traits->windowName.c_str() );
// to get OS-dependant default positioning of the window (which is desirable),
// we must take care to only set the position if explicitly requested.
// hence we set X & Y to these marker values by default.
// And hence only set position if both are valid.
if ((_traits->x != std::numeric_limits<int>::max()) && (_traits->y != std::numeric_limits<int>::max())) {
_window->setPosition( _traits->x, _traits->y );
}
QSize sz(_traits->width, _traits->height);
if ( !_traits->supportsResize ) {
_window->setMinimumSize( sz );
_window->setMaximumSize( sz );
} else {
_window->resize( sz );
}
if (windowData->createFullscreen) {
// this doesn't seem to actually work, so we
// check the flag again in realizeImplementation()
_window->setWindowState(Qt::WindowFullScreen);
}
_window->_isPrimaryWindow = windowData->isPrimaryWindow;
if (_window->_isPrimaryWindow) {
fgSetDouble("/sim/rendering/gui-pixel-ratio", _window->_devicePixelRatio);
}
_window->setGraphicsWindow( this );
useCursor( _traits->useCursor );
// initialize State
setState( new osg::State );
getState()->setGraphicsContext(this);
getState()->setContextID( osg::GraphicsContext::createNewContextID() );
// make sure the event queue has the correct window rectangle size and input range
getEventQueue()->syncWindowRectangleWithGraphicsContext();
return true;
}
QSurfaceFormat GraphicsWindowQt5::traits2qSurfaceFormat( const osg::GraphicsContext::Traits* traits )
{
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setAlphaBufferSize( traits->alpha );
format.setRedBufferSize( traits->red );
format.setGreenBufferSize( traits->green );
format.setBlueBufferSize( traits->blue );
format.setDepthBufferSize( traits->depth );
format.setStencilBufferSize( traits->stencil );
// format.setSampleBuffers( traits->sampleBuffers );
format.setSamples( traits->samples );
format.setAlphaBufferSize( traits->alpha>0 );
format.setDepthBufferSize( traits->depth );
format.setSwapBehavior( traits->doubleBuffer ?
QSurfaceFormat::DoubleBuffer :
QSurfaceFormat::DefaultSwapBehavior);
format.setSwapInterval( traits->vsync ? 1 : 0 );
format.setStereo( traits->quadBufferStereo ? 1 : 0 );
return format;
}
void GraphicsWindowQt5::qSurfaceFormat2traits( const QSurfaceFormat& format, osg::GraphicsContext::Traits* traits )
{
traits->red = format.redBufferSize();
traits->green = format.greenBufferSize();
traits->blue = format.blueBufferSize();
traits->alpha = format.alphaBufferSize();
traits->depth = format.depthBufferSize();
traits->stencil = format.stencilBufferSize();
traits->samples = format.samples();
traits->quadBufferStereo = format.stereo();
traits->doubleBuffer = (format.swapBehavior() == QSurfaceFormat::DoubleBuffer);
traits->vsync = format.swapInterval() >= 1;
}
osg::GraphicsContext::Traits* GraphicsWindowQt5::createTraits( const QWindow* window )
{
osg::GraphicsContext::Traits *traits = new osg::GraphicsContext::Traits;
qSurfaceFormat2traits( window->format(), traits );
QRect r = window->geometry();
traits->x = r.x();
traits->y = r.y();
traits->width = r.width();
traits->height = r.height();
traits->windowName = window->title().toLocal8Bit().data();
Qt::WindowFlags f = window->flags();
traits->windowDecoration = ( f & Qt::WindowTitleHint ) &&
( f & Qt::WindowMinMaxButtonsHint ) &&
( f & Qt::WindowSystemMenuHint );
traits->supportsResize = true;
/*
QSizePolicy sp = window->sizePolicy();
traits->supportsResize = sp.horizontalPolicy() != QSizePolicy::Fixed ||
sp.verticalPolicy() != QSizePolicy::Fixed;
*/
return traits;
}
bool GraphicsWindowQt5::setWindowRectangleImplementation( int x, int y, int width, int height )
{
if (!_window)
return false;
qDebug() << "setWRI window geometry to " << x << "," << y <<
" w=" << width << " h=" << height;
_window->setGeometry( x, y, width, height );
return true;
}
void GraphicsWindowQt5::getWindowRectangle( int& x, int& y, int& width, int& height )
{
if ( _window )
{
const QRect& geom = _window->geometry();
x = geom.x();
y = geom.y();
width = geom.width();
height = geom.height();
}
}
bool GraphicsWindowQt5::setWindowDecorationImplementation( bool windowDecoration )
{
Qt::WindowFlags flags = Qt::Window|Qt::CustomizeWindowHint;//|Qt::WindowStaysOnTopHint;
if ( windowDecoration )
flags |= Qt::WindowTitleHint|Qt::WindowMinMaxButtonsHint|Qt::WindowSystemMenuHint;
_traits->windowDecoration = windowDecoration;
if ( _window )
{
_window->setFlags( flags );
return true;
}
return false;
}
bool GraphicsWindowQt5::getWindowDecoration() const
{
return _traits->windowDecoration;
}
void GraphicsWindowQt5::grabFocus()
{
if ( _window )
_window->requestActivate();
}
void GraphicsWindowQt5::grabFocusIfPointerInWindow()
{
#if 0
if ( _widget->underMouse() )
_widget->setFocus( Qt::ActiveWindowFocusReason );
#endif
}
void GraphicsWindowQt5::raiseWindow()
{
if ( _window )
_window->raise();
}
void GraphicsWindowQt5::setWindowName( const std::string& name )
{
if ( _window )
_window->setTitle( QString::fromUtf8(name.c_str()) );
}
std::string GraphicsWindowQt5::getWindowName()
{
return _window ? _window->title().toStdString() : "";
}
void GraphicsWindowQt5::useCursor( bool cursorOn )
{
if ( _window )
{
_traits->useCursor = cursorOn;
if ( !cursorOn ) _window->setCursor( Qt::BlankCursor );
else _window->setCursor( _currentCursor );
}
}
void GraphicsWindowQt5::setCursor( MouseCursor cursor )
{
if ( cursor==InheritCursor && _window )
{
_window->unsetCursor();
}
switch ( cursor )
{
case NoCursor: _currentCursor = Qt::BlankCursor; break;
case RightArrowCursor: case LeftArrowCursor: _currentCursor = Qt::ArrowCursor; break;
case InfoCursor: _currentCursor = Qt::SizeAllCursor; break;
case DestroyCursor: _currentCursor = Qt::ForbiddenCursor; break;
case HelpCursor: _currentCursor = Qt::WhatsThisCursor; break;
case CycleCursor: _currentCursor = Qt::ForbiddenCursor; break;
case SprayCursor: _currentCursor = Qt::SizeAllCursor; break;
case WaitCursor: _currentCursor = Qt::WaitCursor; break;
case TextCursor: _currentCursor = Qt::IBeamCursor; break;
case CrosshairCursor: _currentCursor = Qt::CrossCursor; break;
case HandCursor: _currentCursor = Qt::OpenHandCursor; break;
case UpDownCursor: _currentCursor = Qt::SizeVerCursor; break;
case LeftRightCursor: _currentCursor = Qt::SizeHorCursor; break;
case TopSideCursor: case BottomSideCursor: _currentCursor = Qt::UpArrowCursor; break;
case LeftSideCursor: case RightSideCursor: _currentCursor = Qt::SizeHorCursor; break;
case TopLeftCorner: _currentCursor = Qt::SizeBDiagCursor; break;
case TopRightCorner: _currentCursor = Qt::SizeFDiagCursor; break;
case BottomRightCorner: _currentCursor = Qt::SizeBDiagCursor; break;
case BottomLeftCorner: _currentCursor = Qt::SizeFDiagCursor; break;
default: break;
};
if ( _window ) _window->setCursor( _currentCursor );
}
bool GraphicsWindowQt5::valid() const
{
return _window.get() != nullptr;
}
bool GraphicsWindowQt5::realizeImplementation()
{
WindowData* windowData = _traits.get() ? dynamic_cast<WindowData*>(_traits->inheritedWindowData.get()) : nullptr;
if (windowData->createFullscreen) {
_window->showFullScreen();
// work-around for resize events being discarded by EventQueue::setStartTick
_sendResizeOnEventCheck = true;
} else {
_window->show();
}
// make sure the event queue has the correct window rectangle size and input range
getEventQueue()->syncWindowRectangleWithGraphicsContext();
getEventQueue()->getCurrentEventState()->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS);
_realized = true;
return true;
}
bool GraphicsWindowQt5::isRealizedImplementation() const
{
return _realized;
}
void GraphicsWindowQt5::closeImplementation()
{
if ( _window ) {
_window->close();
_window.reset();
}
_context.reset();
_realized = false;
}
void GraphicsWindowQt5::runOperations()
{
// While in graphics thread this is last chance to do something useful before
// graphics thread will execute its operations.
if (_updateContextNeeded || (QOpenGLContext::currentContext() != _context.get())) {
makeCurrent();
_updateContextNeeded = false;
}
_window->beforeRendering();
GraphicsWindow::runOperations();
_window->afterRendering();
}
bool GraphicsWindowQt5::makeCurrentImplementation()
{
if (!_context) {
if ( _traits->sharedContext.valid() ) {
qWarning() << Q_FUNC_INFO << "share contexts not supported";
}
_context.reset(new QOpenGLContext());
_context->setFormat(_window->format());
bool result = _context->create();
if (!result)
{
OSG_WARN << "GraphicsWindowQt5: Can't create QOpenGLContext'" << std::endl;
return false;
}
_context->makeCurrent(_window.get());
// allow derived classes to do work now the context is initalised
contextInitalised();
}
if (_context && (QThread::currentThread() != _context->thread())) {
qWarning() << "attempt to make context current on wrong thread";
return false;
}
_context->makeCurrent(_window.get());
return true;
}
bool GraphicsWindowQt5::releaseContextImplementation()
{
_context->doneCurrent();
return true;
}
void GraphicsWindowQt5::swapBuffersImplementation()
{
_context->swapBuffers(_window.get());
}
void GraphicsWindowQt5::requestWarpPointer( float x, float y )
{
if ( _window )
QCursor::setPos( _window->mapToGlobal(QPoint((int)x,(int)y)) );
getEventQueue()->mouseWarped(x,y);
}
bool GraphicsWindowQt5::checkEvents()
{
if (_sendResizeOnEventCheck) {
_sendResizeOnEventCheck = false;
_window->syncGeometryWithOSG();
}
// todo - only if not running inside QApplication::exec; can we check this?
QCoreApplication::processEvents(QEventLoop::AllEvents);
return true;
}
void GraphicsWindowQt5::setViewer(osgViewer::ViewerBase* viewer)
{
osg::ref_ptr<osgViewer::ViewerBase> previous(_viewer);
_viewer = viewer;
viewerChanged(previous.get());
}
void GraphicsWindowQt5::viewerChanged(osgViewer::ViewerBase*)
{
// nothing
}
void GraphicsWindowQt5::requestRedraw()
{
_window->requestUpdate();
}
void GraphicsWindowQt5::requestContinuousUpdate(bool needed)
{
_continousUpdate = needed;
GraphicsWindow::requestContinuousUpdate(needed);
if (_continousUpdate) {
_window->requestUpdate();
}
}
void GraphicsWindowQt5::setFullscreen(bool isFullscreen)
{
if (isFullscreen) {
_window->showFullScreen();
} else {
// FIXME should restore previous state?
_window->showNormal();
}
}
class Qt5WindowingSystem : public osg::GraphicsContext::WindowingSystemInterface
{
public:
Qt5WindowingSystem()
{
#if OSG_VERSION_GREATER_THAN(3,5,9)
setName("FlightGearQt5");
#endif
}
~Qt5WindowingSystem()
{
if (osg::Referenced::getDeleteHandler())
{
osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0);
osg::Referenced::getDeleteHandler()->flushAll();
}
}
// Access the Qt windowing system through this singleton class.
static Qt5WindowingSystem* getInterface()
{
static Qt5WindowingSystem* qtInterface = new Qt5WindowingSystem;
return qtInterface;
}
// Return the number of screens present in the system
virtual unsigned int getNumScreens( const osg::GraphicsContext::ScreenIdentifier& /*si*/ )
{
return QGuiApplication::screens().size();
}
// Return the resolution of specified screen
// (0,0) is returned if screen is unknown
virtual void getScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si,
osg::GraphicsContext::ScreenSettings& resolution )
{
QScreen* screen = qScreenFromSI(si);
if (!screen) {
qWarning() << Q_FUNC_INFO << "no screen for identifier" << QString::fromStdString(si.displayName());
return;
}
resolution.width = screen->size().width();
resolution.height = screen->size().height();
resolution.colorDepth = screen->depth();
resolution.refreshRate = screen->refreshRate();
}
// Set the resolution for given screen
virtual bool setScreenSettings( const osg::GraphicsContext::ScreenIdentifier& /*si*/, const osg::GraphicsContext::ScreenSettings & /*resolution*/ )
{
OSG_WARN << "osgQt: setScreenSettings() not implemented yet." << std::endl;
return false;
}
// Enumerates available resolutions
virtual void enumerateScreenSettings( const osg::GraphicsContext::ScreenIdentifier& si,
osg::GraphicsContext::ScreenSettingsList & resolutions )
{
QScreen* screen = qScreenFromSI(si);
if (!screen) {
qWarning() << Q_FUNC_INFO << "no screen for identifier" << QString::fromStdString(si.displayName());
return;
}
resolutions.clear();
osg::GraphicsContext::ScreenSettings ss;
ss.width = screen->size().width();
ss.height = screen->size().height();
ss.colorDepth = screen->depth();
ss.refreshRate = screen->refreshRate();
resolutions.push_back(ss);
}
// Create a graphics context with given traits
virtual osg::GraphicsContext* createGraphicsContext( osg::GraphicsContext::Traits* traits )
{
if (traits->pbuffer)
{
OSG_WARN << "osgQt: createGraphicsContext - pbuffer not implemented yet." << std::endl;
return NULL;
}
else
{
osg::ref_ptr< GraphicsWindowQt5 > window = new GraphicsWindowQt5( traits );
if (window->valid()) {
return window.release();
}
else {
qWarning() << "window is not valid";
return NULL;
}
}
}
private:
QScreen* qScreenFromSI(const osg::GraphicsContext::ScreenIdentifier& si)
{
QList<QScreen*> screens = QGuiApplication::screens();
if (screens.size() < si.screenNum) {
return screens.at(si.screenNum);
}
return QGuiApplication::primaryScreen();
}
// No implementation for these
Qt5WindowingSystem( const Qt5WindowingSystem& );
Qt5WindowingSystem& operator=( const Qt5WindowingSystem& );
};
namespace flightgear
{
void initQtWindowingSystem()
{
#if OSG_VERSION_LESS_THAN(3,5,2)
osg::GraphicsContext::setWindowingSystemInterface(Qt5WindowingSystem::getInterface());
#else
osg::GraphicsContext::getWindowingSystemInterfaces()->addWindowingSystemInterface(Qt5WindowingSystem::getInterface());
#endif
}
} // of namespace flightgear

View file

@ -1,193 +0,0 @@
// Copyright (C) 2017 James Turner
// derived from OSG GraphicsWindowQt by Wang Rui
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef FGFS_GRAPHICSWINDOWQT
#define FGFS_GRAPHICSWINDOWQT
#include <QWindow>
#include <memory>
#include <osgViewer/GraphicsWindow>
#include <QMutex>
#include <QEvent>
#include <QQueue>
#include <QSet>
class QInputEvent;
class QGestureEvent;
class QOpenGLContext;
namespace osgViewer {
class ViewerBase;
}
namespace flightgear
{
// forward declarations
class GraphicsWindowQt5;
/// The function sets the WindowingSystem to Qt.
void initQtWindowingSystem();
class GLWindow : public QWindow
{
Q_OBJECT
typedef QWindow inherited;
public:
GLWindow();
virtual ~GLWindow();
virtual void setGraphicsWindow( GraphicsWindowQt5* gw ) { _gw = gw; }
virtual GraphicsWindowQt5* getGraphicsWindow() { return _gw; }
virtual const GraphicsWindowQt5* getGraphicsWindow() const { return _gw; }
inline bool getForwardKeyEvents() const { return _forwardKeyEvents; }
virtual void setForwardKeyEvents( bool f ) { _forwardKeyEvents = f; }
void setKeyboardModifiers(const Qt::KeyboardModifiers qtMods);
virtual void keyPressEvent( QKeyEvent* event );
virtual void keyReleaseEvent( QKeyEvent* event );
virtual void mousePressEvent( QMouseEvent* event );
virtual void mouseReleaseEvent( QMouseEvent* event );
virtual void mouseDoubleClickEvent( QMouseEvent* event );
virtual void mouseMoveEvent( QMouseEvent* event );
virtual void wheelEvent( QWheelEvent* event );
signals:
void beforeRendering();
void afterRendering();
private slots:
void onScreenChanged();
void processUpdateEvent();
protected:
void syncGeometryWithOSG();
void updateEventQueueModifiers(QKeyEvent* event);
friend class GraphicsWindowQt5;
GraphicsWindowQt5* _gw = nullptr; // back-pointer
bool _forwardKeyEvents = false;
qreal _devicePixelRatio = 1.0;
// is this the primary (GUI) window
bool _isPrimaryWindow = false;
virtual void resizeEvent( QResizeEvent* event );
virtual void moveEvent( QMoveEvent* event );
virtual bool event( QEvent* event );
};
class GraphicsWindowQt5 : public osgViewer::GraphicsWindow
{
public:
GraphicsWindowQt5( osg::GraphicsContext::Traits* traits = 0);
virtual ~GraphicsWindowQt5();
inline GLWindow* getGLWindow() { return _window.get(); }
inline const GLWindow* getGLWindow() const { return _window.get(); }
struct WindowData : public osg::Referenced
{
WindowData( GLWindow* win = NULL ): _window(win) {}
GLWindow* _window;
bool createFullscreen = false;
// is this the main window, corresponding to the /sim/startup
// properties? If so we will drive them in some cases.
bool isPrimaryWindow = false;
};
bool init( Qt::WindowFlags f );
static QSurfaceFormat traits2qSurfaceFormat( const osg::GraphicsContext::Traits* traits );
static void qSurfaceFormat2traits( const QSurfaceFormat& format, osg::GraphicsContext::Traits* traits );
static osg::GraphicsContext::Traits* createTraits( const QWindow* window );
virtual bool setWindowRectangleImplementation( int x, int y, int width, int height );
virtual void getWindowRectangle( int& x, int& y, int& width, int& height );
virtual bool setWindowDecorationImplementation( bool windowDecoration );
virtual bool getWindowDecoration() const;
virtual void grabFocus();
virtual void grabFocusIfPointerInWindow();
virtual void raiseWindow();
virtual void setWindowName( const std::string& name );
virtual std::string getWindowName();
virtual void useCursor( bool cursorOn );
virtual void setCursor( MouseCursor cursor );
// inline bool getTouchEventsEnabled() const { return _widget->getTouchEventsEnabled(); }
// virtual void setTouchEventsEnabled( bool e ) { _widget->setTouchEventsEnabled(e); }
virtual bool valid() const;
virtual bool realizeImplementation();
virtual bool isRealizedImplementation() const;
virtual void closeImplementation();
virtual bool makeCurrentImplementation();
virtual bool releaseContextImplementation();
virtual void swapBuffersImplementation();
virtual void runOperations();
virtual bool checkEvents();
virtual void requestRedraw();
virtual void requestContinuousUpdate(bool needed=true);
virtual void requestWarpPointer( float x, float y );
/**
* set the viewer for this window. This will be refreshed when then
* QGuiApplication event loop runs (via exec), or when the window
* needs to be updated.
*/
void setViewer( osgViewer::ViewerBase *viewer );
virtual void contextInitalised() { ; }
void setFullscreen(bool isFullscreen);
protected:
virtual void viewerChanged(osgViewer::ViewerBase*);
friend class GLWindow;
std::unique_ptr<GLWindow> _window;
std::unique_ptr<QOpenGLContext> _context;
QOpenGLContext* _shareContext = nullptr;
bool _ownsWidget;
QCursor _currentCursor;
bool _realized = false;
bool _updateContextNeeded = false;
bool _continousUpdate = false;
osg::observer_ptr< osgViewer::ViewerBase > _viewer;
// if true, we will generate a resize event on the next
// call to check events. Ths works around OSG clearing the
// event queue on us.
bool _sendResizeOnEventCheck = false;
};
} // of namespace flightgear
#endif