diff options
author | Liang Qi <liang.qi@qt.io> | 2018-02-14 11:27:58 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-02-14 12:51:24 +0100 |
commit | 305dd1b61f657474d751cc3b24f58249ec21b61b (patch) | |
tree | 5a90972ecf0f3e499625482d194903b474d9ece6 /src/plugins | |
parent | 76010f4af8c9a59a20c489d70c7f99b802f9721f (diff) | |
parent | dfffb5299bf83b87607f28f55afaf3c404910f9f (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.11
Conflicts:
.qmake.conf
src/corelib/animation/qvariantanimation.cpp
src/corelib/global/qglobal.cpp
src/corelib/global/qlogging.cpp
src/corelib/io/qprocess_win.cpp
src/corelib/json/qjsonarray.cpp
src/corelib/tools/qsimd_p.h
src/corelib/tools/qtimezoneprivate_p.h
src/corelib/xml/qxmlstream_p.h
src/gui/kernel/qsimpledrag.cpp
src/gui/kernel/qsimpledrag_p.h
src/plugins/generic/generic.pro
src/plugins/platforms/cocoa/qcocoamenu.mm
src/widgets/styles/qmacstyle_mac.mm
tests/auto/concurrent/qtconcurrentmap/BLACKLIST
tests/auto/corelib/io/qfileinfo/tst_qfileinfo.cpp
tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
tests/auto/gui/kernel/qwindow/BLACKLIST
tests/auto/widgets/dialogs/qmessagebox/BLACKLIST
Change-Id: I508d686cf20f7f8cc6a7119b9bc7c3bbb505c58e
Diffstat (limited to 'src/plugins')
25 files changed, 303 insertions, 327 deletions
diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro index 824fd0388f..afdc613167 100644 --- a/src/plugins/bearer/bearer.pro +++ b/src/plugins/bearer/bearer.pro @@ -6,6 +6,6 @@ QT_FOR_CONFIG += network-private SUBDIRS += connman networkmanager } -android:SUBDIRS += android +android:!android-embedded: SUBDIRS += android isEmpty(SUBDIRS):SUBDIRS = generic diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index fe4c5be4cb..f548a1fa96 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -438,6 +438,16 @@ QAndroidInputContext::QAndroidInputContext() QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged, this, &QAndroidInputContext::updateSelectionHandles); + QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::anchorRectangleChanged, + this, &QAndroidInputContext::updateSelectionHandles); + QObject::connect(QGuiApplication::inputMethod(), &QInputMethod::inputItemClipRectangleChanged, this, [this]{ + auto im = qGuiApp->inputMethod(); + if (!im->inputItemClipRectangle().contains(im->anchorRectangle()) || + !im->inputItemClipRectangle().contains(im->cursorRectangle())) { + m_cursorHandleShown = CursorHandleNotShown; + updateSelectionHandles(); + } + }); } QAndroidInputContext::~QAndroidInputContext() @@ -595,27 +605,63 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) double pixelDensity = window ? QHighDpiScaling::factor(window) : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); - QPoint point(x / pixelDensity, y / pixelDensity); - y -= leftRect.width() / 2; + QPointF point(x / pixelDensity, y / pixelDensity); + point.setY(point.y() - leftRect.width() / 2); if (handleId == 1) { setSelectionOnFocusObject(point, point); return; } - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition); + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImCurrentSelection); QCoreApplication::sendEvent(m_focusObject, &query); int cpos = query.value(Qt::ImCursorPosition).toInt(); int anchor = query.value(Qt::ImAnchorPosition).toInt(); - + bool rtl = query.value(Qt::ImCurrentSelection).toString().isRightToLeft(); auto rightRect = im->anchorRectangle(); if (cpos > anchor) std::swap(leftRect, rightRect); + auto checkLeftHandle = [&rightRect](QPointF &handlePos) { + if (handlePos.y() > rightRect.center().y()) + handlePos.setY(rightRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && handlePos.x() >= rightRect.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRtlRightHandle = [&rightRect](QPointF &handlePos) { + if (handlePos.y() > rightRect.center().y()) + handlePos.setY(rightRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && rightRect.x() >= handlePos.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRightHandle = [&leftRect](QPointF &handlePos) { + if (handlePos.y() < leftRect.center().y()) + handlePos.setY(leftRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && leftRect.x() >= handlePos.x()) + return false; // same line and wrong X pos ? + return true; + }; + + auto checkRtlLeftHandle = [&leftRect](QPointF &handlePos) { + if (handlePos.y() < leftRect.center().y()) + handlePos.setY(leftRect.center().y()); // adjust Y handle pos + if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && handlePos.x() >= leftRect.x()) + return false; // same line and wrong X pos ? + return true; + }; + if (handleId == 2) { - QPoint rightPoint(rightRect.center().toPoint()); + QPointF rightPoint(rightRect.center()); + if ((!rtl && !checkLeftHandle(point)) || (rtl && !checkRtlRightHandle(point))) + return; setSelectionOnFocusObject(point, rightPoint); } else if (handleId == 3) { - QPoint leftPoint(leftRect.center().toPoint()); + QPointF leftPoint(leftRect.center()); + if ((!rtl && !checkRightHandle(point)) || (rtl && !checkRtlLeftHandle(point))) + return; setSelectionOnFocusObject(leftPoint, point); } } diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm index 32be9ad4ee..a94e0dc517 100644 --- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm +++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm @@ -311,6 +311,24 @@ QT_USE_NAMESPACE return NO; // Someday qApp->quitOnLastWindowClosed(); when QApp and NSApp work closer together. } +- (void)applicationWillHide:(NSNotification *)notification +{ + if (reflectionDelegate + && [reflectionDelegate respondsToSelector:@selector(applicationWillHide:)]) { + [reflectionDelegate applicationWillHide:notification]; + } + + // When the application is hidden Qt will hide the popup windows associated with + // it when it has lost the activation for the application. However, when it gets + // to this point it believes the popup windows to be hidden already due to the + // fact that the application itself is hidden, which will cause a problem when + // the application is made visible again. + const QWindowList topLevelWindows = QGuiApplication::topLevelWindows(); + for (QWindow *topLevelWindow : qAsConst(topLevelWindows)) { + if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) + topLevelWindow->hide(); + } +} - (void)applicationDidBecomeActive:(NSNotification *)notification { diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm index 00bfc8bef5..94f2125bad 100644 --- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm +++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm @@ -415,6 +415,13 @@ static QString strippedText(QString s) } else { QList<QUrl> result; QString filename = QString::fromNSString([[mSavePanel URL] path]).normalized(QString::NormalizationForm_C); + const QString defaultSuffix = mOptions->defaultSuffix(); + const QFileInfo fileInfo(filename); + // If neither the user or the NSSavePanel have provided a suffix, use + // the default suffix (if it exists). + if (fileInfo.suffix().isEmpty() && !defaultSuffix.isEmpty()) { + filename.append('.').append(defaultSuffix); + } result << QUrl::fromLocalFile(filename.remove(QLatin1String("___qt_very_unlikely_prefix_"))); return result; } @@ -442,10 +449,7 @@ static QString strippedText(QString s) [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead? if (mOptions->acceptMode() == QFileDialogOptions::AcceptSave) { - QStringList ext = [self acceptableExtensionsForSave]; - const QString defaultSuffix = mOptions->defaultSuffix(); - if (!ext.isEmpty() && !defaultSuffix.isEmpty()) - ext.prepend(defaultSuffix); + const QStringList ext = [self acceptableExtensionsForSave]; [mSavePanel setAllowedFileTypes:ext.isEmpty() ? nil : qt_mac_QStringListToNSMutableArray(ext)]; } else { [mOpenPanel setAllowedFileTypes:nil]; // delegate panel:shouldEnableURL: does the file filtering for NSOpenPanel diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index 7a550b163b..b3c2d5ae90 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -44,9 +44,11 @@ #include <QtCore/QtDebug> #include "qcocoaapplication.h" +#include "qcocoaintegration.h" #include "qcocoamenuloader.h" #include "qcocoamenubar.h" #include "qcocoawindow.h" +#include "qcocoascreen.h" QT_BEGIN_NAMESPACE @@ -364,8 +366,9 @@ void QCocoaMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, [popupCell setMenu:m_nativeMenu]; [popupCell selectItem:nsItem]; - int availableHeight = screen->availableSize().height(); - const QPoint &globalPos = parentWindow->mapToGlobal(pos); + QCocoaScreen *cocoaScreen = static_cast<QCocoaScreen *>(screen->handle()); + int availableHeight = cocoaScreen->availableGeometry().height(); + const QPoint &globalPos = cocoaWindow->mapToGlobal(pos); int menuHeight = m_nativeMenu.size.height; if (globalPos.y() + menuHeight > availableHeight) { // Maybe we need to fix the vertical popup position but we don't know the diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm index e756f0aeb0..f4c968ab57 100644 --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm @@ -72,8 +72,6 @@ ** ****************************************************************************/ -#define QT_MAC_SYSTEMTRAY_USE_GROWL - #include "qcocoasystemtrayicon.h" #ifndef QT_NO_SYSTEMTRAYICON diff --git a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp index f3efbea60b..29cfd4ea79 100644 --- a/src/plugins/platforms/eglfs/api/qeglfswindow.cpp +++ b/src/plugins/platforms/eglfs/api/qeglfswindow.cpp @@ -117,7 +117,7 @@ void QEglFSWindow::create() QOpenGLCompositor *compositor = QOpenGLCompositor::instance(); if (screen->primarySurface() != EGL_NO_SURFACE) { if (Q_UNLIKELY(!isRaster() || !compositor->targetWindow())) { -#if !defined(Q_OS_ANDROID) +#if !defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED) // We can have either a single OpenGL window or multiple raster windows. // Other combinations cannot work. qFatal("EGLFS: OpenGL windows cannot be mixed with others."); diff --git a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp index 6f79cd96d3..f835dbf6d4 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbintegration.cpp @@ -59,13 +59,13 @@ #include <QtInputSupport/private/qlibinputhandler_p.h> #endif -#if QT_CONFIG(evdev) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(evdev) #include <QtInputSupport/private/qevdevmousemanager_p.h> #include <QtInputSupport/private/qevdevkeyboardmanager_p.h> #include <QtInputSupport/private/qevdevtouchmanager_p.h> #endif -#if QT_CONFIG(tslib) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(tslib) #include <QtInputSupport/private/qtslib_p.h> #endif @@ -162,7 +162,7 @@ void QLinuxFbIntegration::createInputHandlers() new QTsLibMouseHandler(QLatin1String("TsLib"), QString()); #endif -#if QT_CONFIG(evdev) && !defined(Q_OS_ANDROID) +#if QT_CONFIG(evdev) new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString(), this); new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString(), this); #if QT_CONFIG(tslib) diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index 9ccc2b54b9..e61887618f 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -1,7 +1,7 @@ TEMPLATE = subdirs QT_FOR_CONFIG += gui-private -android: SUBDIRS += android +android:!android-embedded: SUBDIRS += android !android: SUBDIRS += minimal @@ -36,7 +36,7 @@ qtConfig(directfb) { qtConfig(linuxfb): SUBDIRS += linuxfb -qtConfig(vnc): SUBDIRS += vnc +qtHaveModule(network):qtConfig(vnc): SUBDIRS += vnc freebsd { SUBDIRS += bsdfb diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 15d33200e5..96bfa1dd19 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -71,14 +71,14 @@ HEADERS = main.h \ LIBS += -lscreen -qtConfig(opengles2) { +qtConfig(egl) { SOURCES += qqnxglcontext.cpp \ qqnxeglwindow.cpp HEADERS += qqnxglcontext.h \ qqnxeglwindow.h - QMAKE_USE += opengl_es2 egl + QMAKE_USE += egl } qtConfig(qqnx_pps) { diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.cpp b/src/plugins/platforms/qnx/qqnxeglwindow.cpp index 33ce0f924c..48766fc435 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxeglwindow.cpp @@ -56,18 +56,12 @@ QT_BEGIN_NAMESPACE QQnxEglWindow::QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow) : QQnxWindow(window, context, needRootWindow), - m_platformOpenGLContext(0), m_newSurfaceRequested(true), + m_eglDisplay(EGL_NO_DISPLAY), m_eglSurface(EGL_NO_SURFACE) { initWindow(); - // Set window usage - const int val = SCREEN_USAGE_OPENGL_ES2; - const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &val); - if (Q_UNLIKELY(result != 0)) - qFatal("QQnxEglWindow: failed to set window alpha usage, errno=%d", errno); - m_requestedBufferSize = shouldMakeFullScreen() ? screen()->geometry().size() : window->geometry().size(); } @@ -77,14 +71,58 @@ QQnxEglWindow::~QQnxEglWindow() destroyEGLSurface(); } -void QQnxEglWindow::createEGLSurface() +bool QQnxEglWindow::isInitialized() const { + return m_eglSurface != EGL_NO_SURFACE; +} + +void QQnxEglWindow::ensureInitialized(QQnxGLContext* context) +{ + if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { + const QMutexLocker locker(&m_mutex); // Set geomety must not reset the requestedBufferSize till + // the surface is created + + if (m_requestedBufferSize != bufferSize() || m_eglSurface == EGL_NO_SURFACE) { + if (m_eglSurface != EGL_NO_SURFACE) { + context->doneCurrent(); + destroyEGLSurface(); + } + createEGLSurface(context); + } else { + // Must've been a sequence of unprocessed changes returning us to the original size. + resetBuffers(); + } + } +} + +void QQnxEglWindow::createEGLSurface(QQnxGLContext *context) +{ + if (context->format().renderableType() != QSurfaceFormat::OpenGLES) { + qFatal("QQnxEglWindow: renderable type is not OpenGLES"); + return; + } + + // Set window usage + int usage = SCREEN_USAGE_OPENGL_ES2; +#if _SCREEN_VERSION >= _SCREEN_MAKE_VERSION(1, 0, 0) + if (context->format().majorVersion() == 3) + usage |= SCREEN_USAGE_OPENGL_ES3; +#endif + + const int result = screen_set_window_property_iv(nativeHandle(), SCREEN_PROPERTY_USAGE, &usage); + if (Q_UNLIKELY(result != 0)) + qFatal("QQnxEglWindow: failed to set window usage, errno=%d", errno); + if (!m_requestedBufferSize.isValid()) { qWarning("QQNX: Trying to create 0 size EGL surface. " "Please set a valid window size before calling QOpenGLContext::makeCurrent()"); return; } + m_eglDisplay = context->eglDisplay(); + m_eglConfig = context->eglConfig(); + m_format = context->format(); + // update the window's buffers before we create the EGL surface setBufferSize(m_requestedBufferSize); @@ -94,24 +132,27 @@ void QQnxEglWindow::createEGLSurface() EGL_NONE }; - qEglWindowDebug() << "Creating EGL surface" << platformOpenGLContext()->getEglDisplay() - << platformOpenGLContext()->getEglConfig(); + qEglWindowDebug() << "Creating EGL surface from" << this << context + << window()->surfaceType() << window()->type(); // Create EGL surface - m_eglSurface = eglCreateWindowSurface(platformOpenGLContext()->getEglDisplay(), - platformOpenGLContext()->getEglConfig(), - (EGLNativeWindowType) nativeHandle(), eglSurfaceAttrs); - if (m_eglSurface == EGL_NO_SURFACE) { - const EGLenum error = QQnxGLContext::checkEGLError("eglCreateWindowSurface"); - qWarning("QQNX: failed to create EGL surface, err=%d", error); - } + EGLSurface eglSurface = eglCreateWindowSurface( + m_eglDisplay, + m_eglConfig, + (EGLNativeWindowType) nativeHandle(), + eglSurfaceAttrs); + + if (eglSurface == EGL_NO_SURFACE) + qWarning("QQNX: failed to create EGL surface, err=%d", eglGetError()); + + m_eglSurface = eglSurface; } void QQnxEglWindow::destroyEGLSurface() { // Destroy EGL surface if it exists if (m_eglSurface != EGL_NO_SURFACE) { - EGLBoolean eglResult = eglDestroySurface(platformOpenGLContext()->getEglDisplay(), m_eglSurface); + EGLBoolean eglResult = eglDestroySurface(m_eglDisplay, m_eglSurface); if (Q_UNLIKELY(eglResult != EGL_TRUE)) qFatal("QQNX: failed to destroy EGL surface, err=%d", eglGetError()); } @@ -119,40 +160,8 @@ void QQnxEglWindow::destroyEGLSurface() m_eglSurface = EGL_NO_SURFACE; } -void QQnxEglWindow::swapEGLBuffers() +EGLSurface QQnxEglWindow::surface() const { - qEglWindowDebug(); - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Post EGL surface to window - eglResult = eglSwapBuffers(m_platformOpenGLContext->getEglDisplay(), m_eglSurface); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to swap EGL buffers, err=%d", eglGetError()); - - windowPosted(); -} - -EGLSurface QQnxEglWindow::getSurface() -{ - if (m_newSurfaceRequested.testAndSetOrdered(true, false)) { - const QMutexLocker locker(&m_mutex); //Set geomety must not reset the requestedBufferSize till - //the surface is created - - if ((m_requestedBufferSize != bufferSize()) || (m_eglSurface == EGL_NO_SURFACE)) { - if (m_eglSurface != EGL_NO_SURFACE) { - platformOpenGLContext()->doneCurrent(); - destroyEGLSurface(); - } - createEGLSurface(); - } else { - // Must've been a sequence of unprocessed changes returning us to the original size. - resetBuffers(); - } - } - return m_eglSurface; } @@ -169,35 +178,24 @@ void QQnxEglWindow::setGeometry(const QRect &rect) // that test. const QMutexLocker locker(&m_mutex); m_requestedBufferSize = newGeometry.size(); - if (m_platformOpenGLContext != 0 && bufferSize() != newGeometry.size()) + if (isInitialized() && bufferSize() != newGeometry.size()) m_newSurfaceRequested.testAndSetRelease(false, true); } QQnxWindow::setGeometry(newGeometry); } -void QQnxEglWindow::setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext) -{ - // This function does not take ownership of the platform gl context. - // It is owned by the frontend QOpenGLContext - m_platformOpenGLContext = platformOpenGLContext; -} - int QQnxEglWindow::pixelFormat() const { - if (!m_platformOpenGLContext) //The platform GL context was not set yet - return -1; - - const QSurfaceFormat format = m_platformOpenGLContext->format(); // Extract size of color channels from window format - const int redSize = format.redBufferSize(); + const int redSize = m_format.redBufferSize(); if (Q_UNLIKELY(redSize == -1)) qFatal("QQnxWindow: red size not defined"); - const int greenSize = format.greenBufferSize(); + const int greenSize = m_format.greenBufferSize(); if (Q_UNLIKELY(greenSize == -1)) qFatal("QQnxWindow: green size not defined"); - const int blueSize = format.blueBufferSize(); + const int blueSize = m_format.blueBufferSize(); if (Q_UNLIKELY(blueSize == -1)) qFatal("QQnxWindow: blue size not defined"); diff --git a/src/plugins/platforms/qnx/qqnxeglwindow.h b/src/plugins/platforms/qnx/qqnxeglwindow.h index 183be11ddc..3a3840f13c 100644 --- a/src/plugins/platforms/qnx/qqnxeglwindow.h +++ b/src/plugins/platforms/qnx/qqnxeglwindow.h @@ -53,13 +53,10 @@ public: QQnxEglWindow(QWindow *window, screen_context_t context, bool needRootWindow); ~QQnxEglWindow(); - void createEGLSurface(); - void destroyEGLSurface(); - void swapEGLBuffers(); - EGLSurface getSurface(); + EGLSurface surface() const; - void setPlatformOpenGLContext(QQnxGLContext *platformOpenGLContext); - QQnxGLContext *platformOpenGLContext() const { return m_platformOpenGLContext; } + bool isInitialized() const; + void ensureInitialized(QQnxGLContext *context); void setGeometry(const QRect &rect) override; @@ -68,6 +65,9 @@ protected: void resetBuffers() override; private: + void createEGLSurface(QQnxGLContext *context); + void destroyEGLSurface(); + QSize m_requestedBufferSize; // This mutex is used to protect access to the m_requestedBufferSize @@ -78,9 +78,11 @@ private: // QQnxGLContext::makeCurrent() mutable QMutex m_mutex; - QQnxGLContext *m_platformOpenGLContext; QAtomicInt m_newSurfaceRequested; + EGLDisplay m_eglDisplay; + EGLConfig m_eglConfig; EGLSurface m_eglSurface; + QSurfaceFormat m_format; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.cpp b/src/plugins/platforms/qnx/qqnxglcontext.cpp index d35a4f0bba..d4493943e2 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.cpp +++ b/src/plugins/platforms/qnx/qqnxglcontext.cpp @@ -59,117 +59,13 @@ QT_BEGIN_NAMESPACE EGLDisplay QQnxGLContext::ms_eglDisplay = EGL_NO_DISPLAY; -QQnxGLContext::QQnxGLContext(QOpenGLContext *glContext) - : QPlatformOpenGLContext(), - m_glContext(glContext), - m_currentEglSurface(EGL_NO_SURFACE) +QQnxGLContext::QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share) + : QEGLPlatformContext(format, share, ms_eglDisplay) { - qGLContextDebug(); - QSurfaceFormat format = m_glContext->format(); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Get colour channel sizes from window format - int alphaSize = format.alphaBufferSize(); - int redSize = format.redBufferSize(); - int greenSize = format.greenBufferSize(); - int blueSize = format.blueBufferSize(); - - // Check if all channels are don't care - if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { - // Set colour channels based on depth of window's screen - QQnxScreen *screen = static_cast<QQnxScreen*>(glContext->screen()->handle()); - int depth = screen->depth(); - if (depth == 32) { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } else { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } - } else { - // Choose best match based on supported pixel formats - if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { - // SCREEN_FORMAT_RGB565 - alphaSize = 0; - redSize = 5; - greenSize = 6; - blueSize = 5; - } else { - // SCREEN_FORMAT_RGBA8888 - alphaSize = 8; - redSize = 8; - greenSize = 8; - blueSize = 8; - } - } - - // Update colour channel sizes in window format - format.setAlphaBufferSize(alphaSize); - format.setRedBufferSize(redSize); - format.setGreenBufferSize(greenSize); - format.setBlueBufferSize(blueSize); - - // Select EGL config based on requested window format - m_eglConfig = q_configFromGLFormat(ms_eglDisplay, format); - if (Q_UNLIKELY(m_eglConfig == 0)) - qFatal("QQnxGLContext: failed to find EGL config"); - - QQnxGLContext *glShareContext = static_cast<QQnxGLContext*>(m_glContext->shareHandle()); - m_eglShareContext = glShareContext ? glShareContext->m_eglContext : EGL_NO_CONTEXT; - - m_eglContext = eglCreateContext(ms_eglDisplay, m_eglConfig, m_eglShareContext, - contextAttrs(format)); - if (Q_UNLIKELY(m_eglContext == EGL_NO_CONTEXT)) { - checkEGLError("eglCreateContext"); - qFatal("QQnxGLContext: failed to create EGL context, err=%d", eglGetError()); - } - - // Query/cache window format of selected EGL config - m_windowFormat = q_glFormatFromConfig(ms_eglDisplay, m_eglConfig); } QQnxGLContext::~QQnxGLContext() { - qGLContextDebug(); - - // Cleanup EGL context if it exists - if (m_eglContext != EGL_NO_CONTEXT) - eglDestroyContext(ms_eglDisplay, m_eglContext); -} - -EGLenum QQnxGLContext::checkEGLError(const char *msg) -{ - static const char *errmsg[] = - { - "EGL function succeeded", - "EGL is not initialized, or could not be initialized, for the specified display", - "EGL cannot access a requested resource", - "EGL failed to allocate resources for the requested operation", - "EGL fail to access an unrecognized attribute or attribute value was passed in an attribute list", - "EGLConfig argument does not name a valid EGLConfig", - "EGLContext argument does not name a valid EGLContext", - "EGL current surface of the calling thread is no longer valid", - "EGLDisplay argument does not name a valid EGLDisplay", - "EGL arguments are inconsistent", - "EGLNativePixmapType argument does not refer to a valid native pixmap", - "EGLNativeWindowType argument does not refer to a valid native window", - "EGL one or more argument values are invalid", - "EGLSurface argument does not name a valid surface configured for rendering", - "EGL power management event has occurred", - }; - EGLenum error = eglGetError(); - fprintf(stderr, "%s: %s\n", msg, errmsg[error - EGL_SUCCESS]); - return error; } void QQnxGLContext::initializeContext() @@ -178,16 +74,12 @@ void QQnxGLContext::initializeContext() // Initialize connection to EGL ms_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if (Q_UNLIKELY(ms_eglDisplay == EGL_NO_DISPLAY)) { - checkEGLError("eglGetDisplay"); - qFatal("QQnxGLContext: failed to obtain EGL display"); - } + if (Q_UNLIKELY(ms_eglDisplay == EGL_NO_DISPLAY)) + qFatal("QQnxGLContext: failed to obtain EGL display: %x", eglGetError()); EGLBoolean eglResult = eglInitialize(ms_eglDisplay, 0, 0); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) { - checkEGLError("eglInitialize"); + if (Q_UNLIKELY(eglResult != EGL_TRUE)) qFatal("QQnxGLContext: failed to initialize EGL display, err=%d", eglGetError()); - } } void QQnxGLContext::shutdownContext() @@ -198,98 +90,32 @@ void QQnxGLContext::shutdownContext() eglTerminate(ms_eglDisplay); } -bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) +EGLSurface QQnxGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface) { - qGLContextDebug(); - - Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface); - - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQnxGLContext: failed to set EGL API, err=%d", eglGetError()); - - QQnxEglWindow *platformWindow = dynamic_cast<QQnxEglWindow*>(surface); - if (!platformWindow) - return false; - - platformWindow->setPlatformOpenGLContext(this); - - if (m_currentEglSurface == EGL_NO_SURFACE || m_currentEglSurface != platformWindow->getSurface()) { - m_currentEglSurface = platformWindow->getSurface(); - doneCurrent(); - } - - eglResult = eglMakeCurrent(ms_eglDisplay, m_currentEglSurface, m_currentEglSurface, m_eglContext); - if (eglResult != EGL_TRUE) { - checkEGLError("eglMakeCurrent"); - qWarning("QQNX: failed to set current EGL context, err=%d", eglGetError()); - return false; - } - return (eglResult == EGL_TRUE); + QQnxEglWindow *window = static_cast<QQnxEglWindow *>(surface); + window->ensureInitialized(this); + return window->surface(); } -void QQnxGLContext::doneCurrent() +bool QQnxGLContext::makeCurrent(QPlatformSurface *surface) { qGLContextDebug(); - - // set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // clear curent EGL context and unbind EGL surface - eglResult = eglMakeCurrent(ms_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to clear current EGL context, err=%d", eglGetError()); + return QEGLPlatformContext::makeCurrent(surface); } void QQnxGLContext::swapBuffers(QPlatformSurface *surface) { qGLContextDebug(); - QQnxEglWindow *platformWindow = dynamic_cast<QQnxEglWindow*>(surface); - if (!platformWindow) - return; - - platformWindow->swapEGLBuffers(); -} -QFunctionPointer QQnxGLContext::getProcAddress(const char *procName) -{ - qGLContextDebug(); + QEGLPlatformContext::swapBuffers(surface); - // Set current rendering API - EGLBoolean eglResult = eglBindAPI(EGL_OPENGL_ES_API); - if (Q_UNLIKELY(eglResult != EGL_TRUE)) - qFatal("QQNX: failed to set EGL API, err=%d", eglGetError()); - - // Lookup EGL extension function pointer - QFunctionPointer result = static_cast<QFunctionPointer>(eglGetProcAddress(procName)); - if (!result) - result = reinterpret_cast<QFunctionPointer>(dlsym(RTLD_DEFAULT, procName)); - return result; -} - -bool QQnxGLContext::isSharing() const -{ - return m_eglShareContext != EGL_NO_CONTEXT; -} - -EGLDisplay QQnxGLContext::getEglDisplay() { - return ms_eglDisplay; + QQnxEglWindow *platformWindow = static_cast<QQnxEglWindow*>(surface); + platformWindow->windowPosted(); } -EGLint *QQnxGLContext::contextAttrs(const QSurfaceFormat &format) +void QQnxGLContext::doneCurrent() { - qGLContextDebug(); - - // Choose EGL settings based on OpenGL version -#if defined(QT_OPENGL_ES_2) - static EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, format.version().first, EGL_NONE }; - return attrs; -#else - return 0; -#endif + QEGLPlatformContext::doneCurrent(); } QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxglcontext.h b/src/plugins/platforms/qnx/qqnxglcontext.h index 6e5408e8bf..19179a80e2 100644 --- a/src/plugins/platforms/qnx/qqnxglcontext.h +++ b/src/plugins/platforms/qnx/qqnxglcontext.h @@ -46,49 +46,31 @@ #include <QtCore/QSize> #include <EGL/egl.h> +#include <QtEglSupport/private/qeglplatformcontext_p.h> QT_BEGIN_NAMESPACE class QQnxWindow; -class QQnxGLContext : public QPlatformOpenGLContext +class QQnxGLContext : public QEGLPlatformContext { public: - QQnxGLContext(QOpenGLContext *glContext); + QQnxGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share); virtual ~QQnxGLContext(); - static EGLenum checkEGLError(const char *msg); - static void initializeContext(); static void shutdownContext(); - void requestSurfaceChange(); - bool makeCurrent(QPlatformSurface *surface) override; - void doneCurrent() override; void swapBuffers(QPlatformSurface *surface) override; - QFunctionPointer getProcAddress(const char *procName) override; - - virtual QSurfaceFormat format() const override { return m_windowFormat; } - bool isSharing() const override; + void doneCurrent() override; - static EGLDisplay getEglDisplay(); - EGLConfig getEglConfig() const { return m_eglConfig;} - EGLContext getEglContext() const { return m_eglContext; } +protected: + EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface) override; private: //Can be static because different displays returne the same handle static EGLDisplay ms_eglDisplay; - - QSurfaceFormat m_windowFormat; - QOpenGLContext *m_glContext; - - EGLConfig m_eglConfig; - EGLContext m_eglContext; - EGLContext m_eglShareContext; - EGLSurface m_currentEglSurface; - - static EGLint *contextAttrs(const QSurfaceFormat &format); }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp index 072510e052..bffe7ee34b 100644 --- a/src/plugins/platforms/qnx/qqnxintegration.cpp +++ b/src/plugins/platforms/qnx/qqnxintegration.cpp @@ -313,7 +313,58 @@ QPlatformBackingStore *QQnxIntegration::createPlatformBackingStore(QWindow *wind QPlatformOpenGLContext *QQnxIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const { qIntegrationDebug(); - return new QQnxGLContext(context); + + // Get color channel sizes from window format + QSurfaceFormat format = context->format(); + int alphaSize = format.alphaBufferSize(); + int redSize = format.redBufferSize(); + int greenSize = format.greenBufferSize(); + int blueSize = format.blueBufferSize(); + + // Check if all channels are don't care + if (alphaSize == -1 && redSize == -1 && greenSize == -1 && blueSize == -1) { + // Set color channels based on depth of window's screen + QQnxScreen *screen = static_cast<QQnxScreen*>(context->screen()->handle()); + int depth = screen->depth(); + if (depth == 32) { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } else { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } + } else { + // Choose best match based on supported pixel formats + if (alphaSize <= 0 && redSize <= 5 && greenSize <= 6 && blueSize <= 5) { + // SCREEN_FORMAT_RGB565 + alphaSize = 0; + redSize = 5; + greenSize = 6; + blueSize = 5; + } else { + // SCREEN_FORMAT_RGBA8888 + alphaSize = 8; + redSize = 8; + greenSize = 8; + blueSize = 8; + } + } + + // Update color channel sizes in window format + format.setAlphaBufferSize(alphaSize); + format.setRedBufferSize(redSize); + format.setGreenBufferSize(greenSize); + format.setBlueBufferSize(blueSize); + context->setFormat(format); + + QQnxGLContext *ctx = new QQnxGLContext(context->format(), context->shareHandle()); + return ctx; } #endif diff --git a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp index 468fe9cd91..3eebb9c742 100644 --- a/src/plugins/platforms/qnx/qqnxnativeinterface.cpp +++ b/src/plugins/platforms/qnx/qqnxnativeinterface.cpp @@ -98,7 +98,7 @@ void *QQnxNativeInterface::nativeResourceForIntegration(const QByteArray &resour void *QQnxNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context) { if (resource == "eglcontext" && context) - return static_cast<QQnxGLContext*>(context->handle())->getEglContext(); + return static_cast<QQnxGLContext*>(context->handle())->eglContext(); return 0; } diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 8a498434aa..a6d5623d04 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -49,10 +49,14 @@ #include <screen/screen.h> -// For pre-7.0 SDPs, map some screen property names to the old +#if !defined(_SCREEN_VERSION) +#define _SCREEN_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) +#define _SCREEN_VERSION _SCREEN_MAKE_VERSION(0, 0, 0) +#endif + +// For pre-1.0.0 screen, map some screen property names to the old // names. -#include <sys/neutrino.h> -#if _NTO_VERSION < 700 +#if _SCREEN_VERSION < _SCREEN_MAKE_VERSION(1, 0, 0) const int SCREEN_PROPERTY_FLAGS = SCREEN_PROPERTY_KEY_FLAGS; const int SCREEN_PROPERTY_FOCUS = SCREEN_PROPERTY_KEYBOARD_FOCUS; const int SCREEN_PROPERTY_MODIFIERS = SCREEN_PROPERTY_KEY_MODIFIERS; diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h index dfcca78f80..2895a547b1 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.h +++ b/src/plugins/platforms/qnx/qqnxwindow.h @@ -112,12 +112,13 @@ public: bool shouldMakeFullScreen() const; + void windowPosted(); + protected: virtual int pixelFormat() const = 0; virtual void resetBuffers() = 0; void initWindow(); - void windowPosted(); screen_context_t m_screenContext; diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 70ee708b61..80ee7b2287 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -68,7 +68,6 @@ #include <QtCore/QMutex> #include <QtCore/QMutexLocker> #include <QtCore/QUuid> -#include <QtCore/QRegularExpression> #include <QtCore/QTemporaryFile> #include <QtCore/private/qsystemlibrary_p.h> @@ -1135,12 +1134,32 @@ void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel } } +static bool isHexRange(const QString& s, int start, int end) +{ + for (;start < end; ++start) { + QChar ch = s.at(start); + if (!(ch.isDigit() + || (ch >= QLatin1Char('a') && ch <= QLatin1Char('f')) + || (ch >= QLatin1Char('A') && ch <= QLatin1Char('F')))) + return false; + } + return true; +} + static inline bool isClsid(const QString &s) { // detect "374DE290-123F-4565-9164-39C4925E467B". - static const QRegularExpression pattern(QLatin1String("\\A[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\\z")); - Q_ASSERT(pattern.isValid()); - return pattern.match(s).hasMatch(); + const QChar dash(QLatin1Char('-')); + return s.size() == 36 + && isHexRange(s, 0, 8) + && s.at(8) == dash + && isHexRange(s, 9, 13) + && s.at(13) == dash + && isHexRange(s, 14, 18) + && s.at(18) == dash + && isHexRange(s, 19, 23) + && s.at(23) == dash + && isHexRange(s, 24, 36); } void QWindowsNativeFileDialogBase::selectFile(const QString &fileName) const diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index ada124b5af..038ee5cd62 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -2558,7 +2558,7 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) newFrame.moveTo(topLeft); qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins << currentFrameGeometry << "->" << newFrame; - SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); + SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOACTIVATE); } } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 56a737e882..21024385b0 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -134,7 +134,11 @@ static void updateFormatFromContext(QSurfaceFormat &format) } format.setProfile(QSurfaceFormat::NoProfile); + const bool isStereo = format.testOption(QSurfaceFormat::StereoBuffers); format.setOptions(QSurfaceFormat::FormatOptions()); + // Restore flags that come from the VisualInfo/FBConfig. + if (isStereo) + format.setOption(QSurfaceFormat::StereoBuffers); if (format.renderableType() == QSurfaceFormat::OpenGL) { if (format.version() < qMakePair(3, 0)) { diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5b05a230e4..61cfed4db7 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2071,7 +2071,7 @@ bool QXcbWindow::isEmbedded() const QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapToGlobal(pos); QPoint ret; auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), @@ -2088,7 +2088,7 @@ QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const { if (!m_embedded) - return pos; + return QPlatformWindow::mapFromGlobal(pos); QPoint ret; auto reply = Q_XCB_REPLY(xcb_translate_coordinates, xcb_connection(), diff --git a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp index 0b67739095..ec4ff68e8d 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3menu.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3menu.cpp @@ -41,6 +41,7 @@ #include <QtGui/qwindow.h> #include <QtGui/qpa/qplatformtheme.h> +#include <QtGui/qpa/qplatformwindow.h> #undef signals #include <gtk/gtk.h> @@ -426,9 +427,11 @@ void QGtk3Menu::showPopup(const QWindow *parentWindow, const QRect &targetRect, if (index != -1) gtk_menu_set_active(GTK_MENU(m_menu), index); - m_targetPos = targetRect.bottomLeft(); - if (parentWindow) - m_targetPos = parentWindow->mapToGlobal(m_targetPos); + m_targetPos = QPoint(targetRect.x(), targetRect.y() + targetRect.height()); + + QPlatformWindow *pw = parentWindow ? parentWindow->handle() : nullptr; + if (pw) + m_targetPos = pw->mapToGlobal(m_targetPos); gtk_menu_popup(GTK_MENU(m_menu), NULL, NULL, qt_gtk_menu_position_func, this, 0, gtk_get_current_event_time()); } diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp index 6447776f25..077955eb4e 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp @@ -153,7 +153,7 @@ bool QGtk3Theme::usePlatformNativeDialog(DialogType type) const case ColorDialog: return true; case FileDialog: - return true; + return useNativeFileDialog(); case FontDialog: return true; default: @@ -167,6 +167,8 @@ QPlatformDialogHelper *QGtk3Theme::createPlatformDialogHelper(DialogType type) c case ColorDialog: return new QGtk3ColorDialogHelper; case FileDialog: + if (!useNativeFileDialog()) + return nullptr; return new QGtk3FileDialogHelper; case FontDialog: return new QGtk3FontDialogHelper; @@ -185,4 +187,17 @@ QPlatformMenuItem* QGtk3Theme::createPlatformMenuItem() const return new QGtk3MenuItem; } +bool QGtk3Theme::useNativeFileDialog() +{ + /* Require GTK3 >= 3.15.5 to avoid running into this bug: + * https://bugzilla.gnome.org/show_bug.cgi?id=725164 + * + * While this bug only occurs when using widget-based file dialogs + * (native GTK3 dialogs are fine) we have to disable platform file + * dialogs entirely since we can't avoid creation of a platform + * dialog helper. + */ + return gtk_check_version(3, 15, 5) == 0; +} + QT_END_NAMESPACE diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.h b/src/plugins/platformthemes/gtk3/qgtk3theme.h index 8f03b84bb6..54296d2ff1 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.h +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h @@ -59,6 +59,8 @@ public: QPlatformMenuItem* createPlatformMenuItem() const override; static const char *name; +private: + static bool useNativeFileDialog(); }; QT_END_NAMESPACE |