qt5.12: Add patches for QTBUG-73459 and QTBUG-69077
QT 5.12 introduced a regression, where a QT program wouldn't show its tray icon, if there was no tray bar during program startup. (QTBUG-73459) QT 5.12 introduced a regression, where qtwebengine applications would freeze in some wayland compositors if a surface from the instance was not visible (for example having a qutebrowser window on another workspace in sway would freeze all qutebrowser windows). Both got fixed already in Qt 5.12.4, but according to #57042 and its sibling issues/PRs it doesn't seem to get fixed in near future for nixpkgs.
This commit is contained in:
parent
d046ab888c
commit
94af997d40
|
@ -53,6 +53,7 @@ let
|
||||||
qtbase = [
|
qtbase = [
|
||||||
./qtbase.patch
|
./qtbase.patch
|
||||||
./qtbase-fixguicmake.patch
|
./qtbase-fixguicmake.patch
|
||||||
|
./qtbase-trayicons.patch # can be removed with 5.12.4 or 5.13
|
||||||
];
|
];
|
||||||
qtdeclarative = [ ./qtdeclarative.patch ];
|
qtdeclarative = [ ./qtdeclarative.patch ];
|
||||||
qtscript = [ ./qtscript.patch ];
|
qtscript = [ ./qtscript.patch ];
|
||||||
|
@ -67,6 +68,10 @@ let
|
||||||
./qtwebkit-darwin-no-qos-classes.patch
|
./qtwebkit-darwin-no-qos-classes.patch
|
||||||
];
|
];
|
||||||
qttools = [ ./qttools.patch ];
|
qttools = [ ./qttools.patch ];
|
||||||
|
qtwayland = [
|
||||||
|
./qtwayland-fix-webengine-freezeups-1.patch # can be removed with 5.12.4 or 5.13
|
||||||
|
./qtwayland-fix-webengine-freezeups-2.patch # can be removed with 5.12.4 or 5.13
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
qtModule =
|
qtModule =
|
||||||
|
|
175
pkgs/development/libraries/qt-5/5.12/qtbase-trayicons.patch
Normal file
175
pkgs/development/libraries/qt-5/5.12/qtbase-trayicons.patch
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
From 4d5e59c54a805ba4e7311fe58c9adc492ca1b35a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexander Volkov <a.volkov@rusbitech.ru>
|
||||||
|
Date: Mon, 4 Feb 2019 18:42:35 +0300
|
||||||
|
Subject: [PATCH] QSystemTrayIcon/X11: Create tray icon window when system tray
|
||||||
|
appears
|
||||||
|
|
||||||
|
... and destroy it otherwise.
|
||||||
|
|
||||||
|
Fixes: QTBUG-61898
|
||||||
|
Fixes: QTBUG-73459
|
||||||
|
Done-with: Gatis Paeglis <gatis.paeglis@qt.io>
|
||||||
|
Change-Id: I6bd8f397f7ccdb123f6a60d4fa466f7b0d760dfc
|
||||||
|
---
|
||||||
|
src/widgets/util/qsystemtrayicon_p.h | 4 ++
|
||||||
|
src/widgets/util/qsystemtrayicon_x11.cpp | 75 ++++++++++++++++++++++----------
|
||||||
|
2 files changed, 57 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/widgets/util/qsystemtrayicon_p.h b/src/widgets/util/qsystemtrayicon_p.h
|
||||||
|
index 5bdf020a472..e31532ea193 100644
|
||||||
|
--- a/src/widgets/util/qsystemtrayicon_p.h
|
||||||
|
+++ b/src/widgets/util/qsystemtrayicon_p.h
|
||||||
|
@@ -69,6 +69,7 @@
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QSystemTrayIconSys;
|
||||||
|
+class QSystemTrayWatcher;
|
||||||
|
class QPlatformSystemTrayIcon;
|
||||||
|
class QToolButton;
|
||||||
|
class QLabel;
|
||||||
|
@@ -90,6 +91,8 @@ public:
|
||||||
|
void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon,
|
||||||
|
QSystemTrayIcon::MessageIcon msgIcon, int msecs);
|
||||||
|
|
||||||
|
+ void destroyIcon();
|
||||||
|
+
|
||||||
|
static bool isSystemTrayAvailable_sys();
|
||||||
|
static bool supportsMessages_sys();
|
||||||
|
|
||||||
|
@@ -101,6 +104,7 @@ public:
|
||||||
|
QSystemTrayIconSys *sys;
|
||||||
|
QPlatformSystemTrayIcon *qpa_sys;
|
||||||
|
bool visible;
|
||||||
|
+ QSystemTrayWatcher *trayWatcher;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void install_sys_qpa();
|
||||||
|
diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp
|
||||||
|
index 86532456c76..70e5f3678ea 100644
|
||||||
|
--- a/src/widgets/util/qsystemtrayicon_x11.cpp
|
||||||
|
+++ b/src/widgets/util/qsystemtrayicon_x11.cpp
|
||||||
|
@@ -92,9 +92,6 @@ protected:
|
||||||
|
virtual void resizeEvent(QResizeEvent *) override;
|
||||||
|
virtual void moveEvent(QMoveEvent *) override;
|
||||||
|
|
||||||
|
-private slots:
|
||||||
|
- void systemTrayWindowChanged(QScreen *screen);
|
||||||
|
-
|
||||||
|
private:
|
||||||
|
QSystemTrayIcon *q;
|
||||||
|
};
|
||||||
|
@@ -116,15 +113,6 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
|
||||||
|
setMouseTracking(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
-void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *)
|
||||||
|
-{
|
||||||
|
- if (!locateSystemTray()) {
|
||||||
|
- QBalloonTip::hideBalloon();
|
||||||
|
- hide(); // still no luck
|
||||||
|
- destroy();
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
QRect QSystemTrayIconSys::globalGeometry() const
|
||||||
|
{
|
||||||
|
return QRect(mapToGlobal(QPoint(0, 0)), size());
|
||||||
|
@@ -199,10 +187,41 @@ void QSystemTrayIconSys::resizeEvent(QResizeEvent *event)
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
+class QSystemTrayWatcher: public QObject
|
||||||
|
+{
|
||||||
|
+ Q_OBJECT
|
||||||
|
+public:
|
||||||
|
+ QSystemTrayWatcher(QSystemTrayIcon *trayIcon)
|
||||||
|
+ : QObject(trayIcon)
|
||||||
|
+ , mTrayIcon(trayIcon)
|
||||||
|
+ {
|
||||||
|
+ // This code uses string-based syntax because we want to connect to a signal
|
||||||
|
+ // which is defined in XCB plugin - QXcbNativeInterface::systemTrayWindowChanged().
|
||||||
|
+ connect(qGuiApp->platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)),
|
||||||
|
+ this, SLOT(systemTrayWindowChanged(QScreen*)));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+private slots:
|
||||||
|
+ void systemTrayWindowChanged(QScreen *)
|
||||||
|
+ {
|
||||||
|
+ auto icon = static_cast<QSystemTrayIconPrivate *>(QObjectPrivate::get(mTrayIcon));
|
||||||
|
+ icon->destroyIcon();
|
||||||
|
+ if (icon->visible && locateSystemTray()) {
|
||||||
|
+ icon->sys = new QSystemTrayIconSys(mTrayIcon);
|
||||||
|
+ icon->sys->show();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+private:
|
||||||
|
+ QSystemTrayIcon *mTrayIcon = nullptr;
|
||||||
|
+};
|
||||||
|
+////////////////////////////////////////////////////////////////////////////
|
||||||
|
+
|
||||||
|
QSystemTrayIconPrivate::QSystemTrayIconPrivate()
|
||||||
|
: sys(0),
|
||||||
|
qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()),
|
||||||
|
- visible(false)
|
||||||
|
+ visible(false),
|
||||||
|
+ trayWatcher(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -213,16 +232,21 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
|
||||||
|
|
||||||
|
void QSystemTrayIconPrivate::install_sys()
|
||||||
|
{
|
||||||
|
+ Q_Q(QSystemTrayIcon);
|
||||||
|
+
|
||||||
|
if (qpa_sys) {
|
||||||
|
install_sys_qpa();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
- Q_Q(QSystemTrayIcon);
|
||||||
|
- if (!sys && locateSystemTray()) {
|
||||||
|
- sys = new QSystemTrayIconSys(q);
|
||||||
|
- QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)),
|
||||||
|
- sys, SLOT(systemTrayWindowChanged(QScreen*)));
|
||||||
|
- sys->show();
|
||||||
|
+
|
||||||
|
+ if (!sys) {
|
||||||
|
+ if (!trayWatcher)
|
||||||
|
+ trayWatcher = new QSystemTrayWatcher(q);
|
||||||
|
+
|
||||||
|
+ if (locateSystemTray()) {
|
||||||
|
+ sys = new QSystemTrayIconSys(q);
|
||||||
|
+ sys->show();
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -241,14 +265,21 @@ void QSystemTrayIconPrivate::remove_sys()
|
||||||
|
remove_sys_qpa();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ destroyIcon();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void QSystemTrayIconPrivate::destroyIcon()
|
||||||
|
+{
|
||||||
|
if (!sys)
|
||||||
|
return;
|
||||||
|
QBalloonTip::hideBalloon();
|
||||||
|
- sys->hide(); // this should do the trick, but...
|
||||||
|
- delete sys; // wm may resize system tray only for DestroyEvents
|
||||||
|
- sys = 0;
|
||||||
|
+ sys->hide();
|
||||||
|
+ delete sys;
|
||||||
|
+ sys = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
+
|
||||||
|
void QSystemTrayIconPrivate::updateIcon_sys()
|
||||||
|
{
|
||||||
|
if (qpa_sys) {
|
||||||
|
--
|
||||||
|
2.16.3
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
From 9aced4f9571e74cc57b853598aa4b3f38d66363d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Johan Klokkhammer Helsing <johan.helsing@qt.io>
|
||||||
|
Date: Thu, 1 Nov 2018 13:48:52 +0100
|
||||||
|
Subject: [PATCH 1/2] Client: Don't be exposed if we want to create a sub or
|
||||||
|
shell surface
|
||||||
|
|
||||||
|
Because some shells don't allow attaching buffers before configure, we need to
|
||||||
|
not be exposed until we know that we don't want a shell surface.
|
||||||
|
|
||||||
|
Change-Id: Ida7101a99f953d02cf6401e4ea8d28cfabd6e102
|
||||||
|
Reviewed-by: Giulio Camuffo <giulio.camuffo@kdab.com>
|
||||||
|
Reviewed-by: David Edmundson <davidedmundson@kde.org>
|
||||||
|
---
|
||||||
|
src/client/qwaylanddisplay.cpp | 13 ++++++-------
|
||||||
|
src/client/qwaylanddisplay_p.h | 6 +++---
|
||||||
|
src/client/qwaylandwindow.cpp | 18 +++++++++++++++---
|
||||||
|
3 files changed, 24 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
||||||
|
index a2957e0d..f2bd3160 100644
|
||||||
|
--- a/src/client/qwaylanddisplay.cpp
|
||||||
|
+++ b/src/client/qwaylanddisplay.cpp
|
||||||
|
@@ -88,13 +88,6 @@ struct wl_surface *QWaylandDisplay::createSurface(void *handle)
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
-QWaylandShellSurface *QWaylandDisplay::createShellSurface(QWaylandWindow *window)
|
||||||
|
-{
|
||||||
|
- if (!mWaylandIntegration->shellIntegration())
|
||||||
|
- return nullptr;
|
||||||
|
- return mWaylandIntegration->shellIntegration()->createShellSurface(window);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
|
||||||
|
{
|
||||||
|
struct ::wl_region *region = mCompositor.create_region();
|
||||||
|
@@ -108,12 +101,18 @@ struct ::wl_region *QWaylandDisplay::createRegion(const QRegion &qregion)
|
||||||
|
::wl_subsurface *QWaylandDisplay::createSubSurface(QWaylandWindow *window, QWaylandWindow *parent)
|
||||||
|
{
|
||||||
|
if (!mSubCompositor) {
|
||||||
|
+ qCWarning(lcQpaWayland) << "Can't create subsurface, not supported by the compositor.";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSubCompositor->get_subsurface(window->object(), parent->object());
|
||||||
|
}
|
||||||
|
|
||||||
|
+QWaylandShellIntegration *QWaylandDisplay::shellIntegration() const
|
||||||
|
+{
|
||||||
|
+ return mWaylandIntegration->shellIntegration();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
QWaylandClientBufferIntegration * QWaylandDisplay::clientBufferIntegration() const
|
||||||
|
{
|
||||||
|
return mWaylandIntegration->clientBufferIntegration();
|
||||||
|
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
||||||
|
index 0dd8d7af..cc6a0a72 100644
|
||||||
|
--- a/src/client/qwaylanddisplay_p.h
|
||||||
|
+++ b/src/client/qwaylanddisplay_p.h
|
||||||
|
@@ -94,7 +94,7 @@ class QWaylandQtKeyExtension;
|
||||||
|
class QWaylandWindow;
|
||||||
|
class QWaylandIntegration;
|
||||||
|
class QWaylandHardwareIntegration;
|
||||||
|
-class QWaylandShellSurface;
|
||||||
|
+class QWaylandShellIntegration;
|
||||||
|
class QWaylandCursorTheme;
|
||||||
|
|
||||||
|
typedef void (*RegistryListener)(void *data,
|
||||||
|
@@ -115,13 +115,13 @@ public:
|
||||||
|
QWaylandScreen *screenForOutput(struct wl_output *output) const;
|
||||||
|
|
||||||
|
struct wl_surface *createSurface(void *handle);
|
||||||
|
- QWaylandShellSurface *createShellSurface(QWaylandWindow *window);
|
||||||
|
struct ::wl_region *createRegion(const QRegion &qregion);
|
||||||
|
struct ::wl_subsurface *createSubSurface(QWaylandWindow *window, QWaylandWindow *parent);
|
||||||
|
|
||||||
|
+ QWaylandShellIntegration *shellIntegration() const;
|
||||||
|
QWaylandClientBufferIntegration *clientBufferIntegration() const;
|
||||||
|
-
|
||||||
|
QWaylandWindowManagerIntegration *windowManagerIntegration() const;
|
||||||
|
+
|
||||||
|
#if QT_CONFIG(cursor)
|
||||||
|
void setCursor(struct wl_buffer *buffer, struct wl_cursor_image *image, qreal dpr);
|
||||||
|
void setCursor(const QSharedPointer<QWaylandBuffer> &buffer, const QPoint &hotSpot, qreal dpr);
|
||||||
|
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
||||||
|
index 4ac2ca51..600ea1df 100644
|
||||||
|
--- a/src/client/qwaylandwindow.cpp
|
||||||
|
+++ b/src/client/qwaylandwindow.cpp
|
||||||
|
@@ -50,6 +50,7 @@
|
||||||
|
#include "qwaylandnativeinterface_p.h"
|
||||||
|
#include "qwaylanddecorationfactory_p.h"
|
||||||
|
#include "qwaylandshmbackingstore_p.h"
|
||||||
|
+#include "qwaylandshellintegration_p.h"
|
||||||
|
|
||||||
|
#if QT_CONFIG(wayland_datadevice)
|
||||||
|
#include "qwaylanddatadevice_p.h"
|
||||||
|
@@ -138,8 +139,9 @@ void QWaylandWindow::initWindow()
|
||||||
|
}
|
||||||
|
} else if (shouldCreateShellSurface()) {
|
||||||
|
Q_ASSERT(!mShellSurface);
|
||||||
|
+ Q_ASSERT(mDisplay->shellIntegration());
|
||||||
|
|
||||||
|
- mShellSurface = mDisplay->createShellSurface(this);
|
||||||
|
+ mShellSurface = mDisplay->shellIntegration()->createShellSurface(this);
|
||||||
|
if (mShellSurface) {
|
||||||
|
// Set initial surface title
|
||||||
|
setWindowTitle(window()->title());
|
||||||
|
@@ -211,6 +213,9 @@ void QWaylandWindow::initializeWlSurface()
|
||||||
|
|
||||||
|
bool QWaylandWindow::shouldCreateShellSurface() const
|
||||||
|
{
|
||||||
|
+ if (!mDisplay->shellIntegration())
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
if (shouldCreateSubSurface())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
@@ -963,9 +968,16 @@ void QWaylandWindow::unfocus()
|
||||||
|
|
||||||
|
bool QWaylandWindow::isExposed() const
|
||||||
|
{
|
||||||
|
+ if (!window()->isVisible())
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
if (mShellSurface)
|
||||||
|
- return window()->isVisible() && mShellSurface->isExposed();
|
||||||
|
- return QPlatformWindow::isExposed();
|
||||||
|
+ return mShellSurface->isExposed();
|
||||||
|
+
|
||||||
|
+ if (mSubSurfaceWindow)
|
||||||
|
+ return mSubSurfaceWindow->parent()->isExposed();
|
||||||
|
+
|
||||||
|
+ return !(shouldCreateShellSurface() || shouldCreateSubSurface());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWaylandWindow::isActive() const
|
||||||
|
--
|
||||||
|
2.22.0
|
||||||
|
|
|
@ -0,0 +1,493 @@
|
||||||
|
From d85beeb65820d6e5733f88af63b15f77d03aa6ba Mon Sep 17 00:00:00 2001
|
||||||
|
From: Johan Klokkhammer Helsing <johan.helsing@qt.io>
|
||||||
|
Date: Mon, 28 Jan 2019 09:48:26 +0100
|
||||||
|
Subject: [PATCH 2/2] Client: Full implementation for frame callbacks (second
|
||||||
|
try)
|
||||||
|
|
||||||
|
The Wayland plugin now takes full control over delivering update request and
|
||||||
|
implement frame callbacks for both egl and shm.
|
||||||
|
|
||||||
|
[ChangeLog][QPA plugin] The non-blocking version of eglSwapBuffers is now used, if
|
||||||
|
supported. This fixed a bug where minimized windows would block the event loop.
|
||||||
|
|
||||||
|
[ChangeLog][QPA plugin] Windows that don't get frame callbacks from the
|
||||||
|
compositor within 100 ms are now set as not exposed. This should stop most
|
||||||
|
clients from rendering unnecessary frames to minimized or hidden windows.
|
||||||
|
|
||||||
|
Also, when we relied on the QPA version of requestUpdate, we would sometimes
|
||||||
|
deliver one update request while we were waiting for a frame callback. When we
|
||||||
|
implement the fallback timer ourselves we can make sure we only deliver the
|
||||||
|
fallback if there are no pending frame callbacks.
|
||||||
|
|
||||||
|
QtQuick and other applications often depend on blocking swapBuffers to throttle
|
||||||
|
animations. If the context's surface format has a non-zero swapInterval, try to
|
||||||
|
emulate a blocking swap.
|
||||||
|
|
||||||
|
Fixes: QTBUG-69077
|
||||||
|
Change-Id: I3c6964f31a16e9aff70b8ec3c5340e640a30fef2
|
||||||
|
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
|
||||||
|
---
|
||||||
|
src/client/qwaylanddisplay.cpp | 38 +++-
|
||||||
|
src/client/qwaylanddisplay_p.h | 3 +
|
||||||
|
src/client/qwaylandwindow.cpp | 180 +++++++++++++++---
|
||||||
|
src/client/qwaylandwindow_p.h | 17 +-
|
||||||
|
.../client/wayland-egl/qwaylandglcontext.cpp | 25 ++-
|
||||||
|
.../qwaylandxcompositeeglcontext.cpp | 2 +-
|
||||||
|
.../qwaylandxcompositeglxcontext.cpp | 2 +-
|
||||||
|
7 files changed, 218 insertions(+), 49 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
|
||||||
|
index f2bd3160..82003a30 100644
|
||||||
|
--- a/src/client/qwaylanddisplay.cpp
|
||||||
|
+++ b/src/client/qwaylanddisplay.cpp
|
||||||
|
@@ -68,6 +68,8 @@
|
||||||
|
|
||||||
|
#include <QtWaylandClient/private/qwayland-text-input-unstable-v2.h>
|
||||||
|
|
||||||
|
+#include <QtCore/private/qcore_unix_p.h>
|
||||||
|
+
|
||||||
|
#include <QtCore/QAbstractEventDispatcher>
|
||||||
|
#include <QtGui/private/qguiapplication_p.h>
|
||||||
|
|
||||||
|
@@ -190,7 +192,6 @@ void QWaylandDisplay::flushRequests()
|
||||||
|
wl_display_flush(mDisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
-
|
||||||
|
void QWaylandDisplay::blockingReadEvents()
|
||||||
|
{
|
||||||
|
if (wl_display_dispatch(mDisplay) < 0) {
|
||||||
|
@@ -204,6 +205,41 @@ void QWaylandDisplay::exitWithError()
|
||||||
|
::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
+wl_event_queue *QWaylandDisplay::createEventQueue()
|
||||||
|
+{
|
||||||
|
+ return wl_display_create_queue(mDisplay);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bool ()> condition, int timeout)
|
||||||
|
+{
|
||||||
|
+ if (!condition())
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ QElapsedTimer timer;
|
||||||
|
+ timer.start();
|
||||||
|
+ struct pollfd pFd = qt_make_pollfd(wl_display_get_fd(mDisplay), POLLIN);
|
||||||
|
+ while (timeout == -1 || timer.elapsed() < timeout) {
|
||||||
|
+ while (wl_display_prepare_read_queue(mDisplay, queue) != 0)
|
||||||
|
+ wl_display_dispatch_queue_pending(mDisplay, queue);
|
||||||
|
+
|
||||||
|
+ wl_display_flush(mDisplay);
|
||||||
|
+
|
||||||
|
+ const int remaining = qMax(timeout - timer.elapsed(), 0ll);
|
||||||
|
+ const int pollTimeout = timeout == -1 ? -1 : remaining;
|
||||||
|
+ if (qt_poll_msecs(&pFd, 1, pollTimeout) > 0)
|
||||||
|
+ wl_display_read_events(mDisplay);
|
||||||
|
+ else
|
||||||
|
+ wl_display_cancel_read(mDisplay);
|
||||||
|
+
|
||||||
|
+ if (wl_display_dispatch_queue_pending(mDisplay, queue) < 0) {
|
||||||
|
+ checkError();
|
||||||
|
+ exitWithError();
|
||||||
|
+ }
|
||||||
|
+ if (!condition())
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < mScreens.size(); ++i) {
|
||||||
|
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
|
||||||
|
index cc6a0a72..fa8b4c3f 100644
|
||||||
|
--- a/src/client/qwaylanddisplay_p.h
|
||||||
|
+++ b/src/client/qwaylanddisplay_p.h
|
||||||
|
@@ -182,6 +182,9 @@ public:
|
||||||
|
void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice);
|
||||||
|
void handleWindowDestroyed(QWaylandWindow *window);
|
||||||
|
|
||||||
|
+ wl_event_queue *createEventQueue();
|
||||||
|
+ void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
|
||||||
|
+
|
||||||
|
public slots:
|
||||||
|
void blockingReadEvents();
|
||||||
|
void flushRequests();
|
||||||
|
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
|
||||||
|
index 600ea1df..4d399f8f 100644
|
||||||
|
--- a/src/client/qwaylandwindow.cpp
|
||||||
|
+++ b/src/client/qwaylandwindow.cpp
|
||||||
|
@@ -67,6 +67,7 @@
|
||||||
|
#include <QtGui/private/qwindow_p.h>
|
||||||
|
|
||||||
|
#include <QtCore/QDebug>
|
||||||
|
+#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
@@ -81,6 +82,7 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
||||||
|
QWaylandWindow::QWaylandWindow(QWindow *window)
|
||||||
|
: QPlatformWindow(window)
|
||||||
|
, mDisplay(waylandScreen()->display())
|
||||||
|
+ , mFrameQueue(mDisplay->createEventQueue())
|
||||||
|
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
||||||
|
{
|
||||||
|
static WId id = 1;
|
||||||
|
@@ -363,6 +365,8 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect)
|
||||||
|
{
|
||||||
|
if (!(mShellSurface && mShellSurface->handleExpose(rect)))
|
||||||
|
QWindowSystemInterface::handleExposeEvent(window(), rect);
|
||||||
|
+ else
|
||||||
|
+ qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending";
|
||||||
|
mLastExposeGeometry = rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -547,18 +551,11 @@ void QWaylandWindow::handleScreenRemoved(QScreen *qScreen)
|
||||||
|
void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!buffer->committed());
|
||||||
|
- if (mFrameCallback) {
|
||||||
|
- wl_callback_destroy(mFrameCallback);
|
||||||
|
- mFrameCallback = nullptr;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
if (buffer) {
|
||||||
|
- mFrameCallback = frame();
|
||||||
|
- wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
||||||
|
- mWaitingForFrameSync = true;
|
||||||
|
+ handleUpdate();
|
||||||
|
buffer->setBusy();
|
||||||
|
|
||||||
|
- attach(buffer->buffer(), x, y);
|
||||||
|
+ QtWayland::wl_surface::attach(buffer->buffer(), x, y);
|
||||||
|
} else {
|
||||||
|
QtWayland::wl_surface::attach(nullptr, 0, 0);
|
||||||
|
}
|
||||||
|
@@ -614,32 +611,61 @@ void QWaylandWindow::commit(QWaylandBuffer *buffer, const QRegion &damage)
|
||||||
|
}
|
||||||
|
|
||||||
|
const wl_callback_listener QWaylandWindow::callbackListener = {
|
||||||
|
- QWaylandWindow::frameCallback
|
||||||
|
+ [](void *data, wl_callback *callback, uint32_t time) {
|
||||||
|
+ Q_UNUSED(callback);
|
||||||
|
+ Q_UNUSED(time);
|
||||||
|
+ auto *window = static_cast<QWaylandWindow*>(data);
|
||||||
|
+ if (window->thread() != QThread::currentThread())
|
||||||
|
+ QMetaObject::invokeMethod(window, [=] { window->handleFrameCallback(); }, Qt::QueuedConnection);
|
||||||
|
+ else
|
||||||
|
+ window->handleFrameCallback();
|
||||||
|
+ }
|
||||||
|
};
|
||||||
|
|
||||||
|
-void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uint32_t time)
|
||||||
|
+void QWaylandWindow::handleFrameCallback()
|
||||||
|
{
|
||||||
|
- Q_UNUSED(time);
|
||||||
|
- Q_UNUSED(callback);
|
||||||
|
- QWaylandWindow *self = static_cast<QWaylandWindow*>(data);
|
||||||
|
+ bool wasExposed = isExposed();
|
||||||
|
|
||||||
|
- self->mWaitingForFrameSync = false;
|
||||||
|
- if (self->mUpdateRequested) {
|
||||||
|
- self->mUpdateRequested = false;
|
||||||
|
- self->deliverUpdateRequest();
|
||||||
|
+ if (mFrameCallbackTimerId != -1) {
|
||||||
|
+ killTimer(mFrameCallbackTimerId);
|
||||||
|
+ mFrameCallbackTimerId = -1;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ mWaitingForFrameCallback = false;
|
||||||
|
+ mFrameCallbackTimedOut = false;
|
||||||
|
+
|
||||||
|
+ if (!wasExposed && isExposed())
|
||||||
|
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
|
||||||
|
+ if (wasExposed && hasPendingUpdateRequest())
|
||||||
|
+ deliverUpdateRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
QMutex QWaylandWindow::mFrameSyncMutex;
|
||||||
|
|
||||||
|
-void QWaylandWindow::waitForFrameSync()
|
||||||
|
+bool QWaylandWindow::waitForFrameSync(int timeout)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&mFrameSyncMutex);
|
||||||
|
- if (!mWaitingForFrameSync)
|
||||||
|
- return;
|
||||||
|
- mDisplay->flushRequests();
|
||||||
|
- while (mWaitingForFrameSync)
|
||||||
|
- mDisplay->blockingReadEvents();
|
||||||
|
+ if (!mWaitingForFrameCallback)
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue);
|
||||||
|
+ mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout);
|
||||||
|
+
|
||||||
|
+ if (mWaitingForFrameCallback) {
|
||||||
|
+ qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||||||
|
+ mFrameCallbackTimedOut = true;
|
||||||
|
+ mWaitingForUpdate = false;
|
||||||
|
+ sendExposeEvent(QRect());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Stop current frame timer if any, can't use killTimer directly, because we might be on a diffent thread
|
||||||
|
+ if (mFrameCallbackTimerId != -1) {
|
||||||
|
+ int id = mFrameCallbackTimerId;
|
||||||
|
+ mFrameCallbackTimerId = -1;
|
||||||
|
+ QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return !mWaitingForFrameCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
QMargins QWaylandWindow::frameMargins() const
|
||||||
|
@@ -971,6 +997,9 @@ bool QWaylandWindow::isExposed() const
|
||||||
|
if (!window()->isVisible())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
+ if (mFrameCallbackTimedOut)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
if (mShellSurface)
|
||||||
|
return mShellSurface->isExposed();
|
||||||
|
|
||||||
|
@@ -1046,12 +1075,107 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa
|
||||||
|
return m_properties.value(name, defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void QWaylandWindow::timerEvent(QTimerEvent *event)
|
||||||
|
+{
|
||||||
|
+ if (event->timerId() == mFallbackUpdateTimerId) {
|
||||||
|
+ killTimer(mFallbackUpdateTimerId);
|
||||||
|
+ mFallbackUpdateTimerId = -1;
|
||||||
|
+ qCDebug(lcWaylandBackingstore) << "mFallbackUpdateTimer timed out";
|
||||||
|
+
|
||||||
|
+ if (!isExposed()) {
|
||||||
|
+ qCDebug(lcWaylandBackingstore) << "Fallback update timer: Window not exposed,"
|
||||||
|
+ << "not delivering update request.";
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (mWaitingForUpdate && hasPendingUpdateRequest() && !mWaitingForFrameCallback) {
|
||||||
|
+ qCWarning(lcWaylandBackingstore) << "Delivering update request through fallback timer,"
|
||||||
|
+ << "may not be in sync with display";
|
||||||
|
+ deliverUpdateRequest();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (event->timerId() == mFrameCallbackTimerId) {
|
||||||
|
+ killTimer(mFrameCallbackTimerId);
|
||||||
|
+ mFrameCallbackTimerId = -1;
|
||||||
|
+ qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
|
||||||
|
+ mFrameCallbackTimedOut = true;
|
||||||
|
+ mWaitingForUpdate = false;
|
||||||
|
+ sendExposeEvent(QRect());
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void QWaylandWindow::requestUpdate()
|
||||||
|
{
|
||||||
|
- if (!mWaitingForFrameSync)
|
||||||
|
- QPlatformWindow::requestUpdate();
|
||||||
|
- else
|
||||||
|
- mUpdateRequested = true;
|
||||||
|
+ Q_ASSERT(hasPendingUpdateRequest()); // should be set by QPA
|
||||||
|
+
|
||||||
|
+ // If we have a frame callback all is good and will be taken care of there
|
||||||
|
+ if (mWaitingForFrameCallback)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet
|
||||||
|
+ if (mWaitingForUpdate) {
|
||||||
|
+ // Ideally, we should just have returned here, but we're not guaranteed that the client
|
||||||
|
+ // will actually update, so start this timer to deliver another request update after a while
|
||||||
|
+ // *IF* the client doesn't update.
|
||||||
|
+ int fallbackTimeout = 100;
|
||||||
|
+ mFallbackUpdateTimerId = startTimer(fallbackTimeout);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Some applications (such as Qt Quick) depend on updates being delivered asynchronously,
|
||||||
|
+ // so use invokeMethod to delay the delivery a bit.
|
||||||
|
+ QMetaObject::invokeMethod(this, [this] {
|
||||||
|
+ // Things might have changed in the meantime
|
||||||
|
+ if (hasPendingUpdateRequest() && !mWaitingForUpdate && !mWaitingForFrameCallback)
|
||||||
|
+ deliverUpdateRequest();
|
||||||
|
+ }, Qt::QueuedConnection);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly
|
||||||
|
+// with eglSwapBuffers) to know when it's time to commit the next one.
|
||||||
|
+// Can be called from the render thread (without locking anything) so make sure to not make races in this method.
|
||||||
|
+void QWaylandWindow::handleUpdate()
|
||||||
|
+{
|
||||||
|
+ // TODO: Should sync subsurfaces avoid requesting frame callbacks?
|
||||||
|
+
|
||||||
|
+ if (mFrameCallback) {
|
||||||
|
+ wl_callback_destroy(mFrameCallback);
|
||||||
|
+ mFrameCallback = nullptr;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (mFallbackUpdateTimerId != -1) {
|
||||||
|
+ // Ideally, we would stop the fallback timer here, but since we're on another thread,
|
||||||
|
+ // it's not allowed. Instead we set mFallbackUpdateTimer to -1 here, so we'll just
|
||||||
|
+ // ignore it if it times out before it's cleaned up by the invokeMethod call.
|
||||||
|
+ int id = mFallbackUpdateTimerId;
|
||||||
|
+ mFallbackUpdateTimerId = -1;
|
||||||
|
+ QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ mFrameCallback = frame();
|
||||||
|
+ wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
|
||||||
|
+ mWaitingForFrameCallback = true;
|
||||||
|
+ mWaitingForUpdate = false;
|
||||||
|
+
|
||||||
|
+ // Stop current frame timer if any, can't use killTimer directly, see comment above.
|
||||||
|
+ if (mFrameCallbackTimerId != -1) {
|
||||||
|
+ int id = mFrameCallbackTimerId;
|
||||||
|
+ mFrameCallbackTimerId = -1;
|
||||||
|
+ QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Start a timer for handling the case when the compositor stops sending frame callbacks.
|
||||||
|
+ QMetaObject::invokeMethod(this, [=] { // Again; can't do it directly
|
||||||
|
+ if (mWaitingForFrameCallback)
|
||||||
|
+ mFrameCallbackTimerId = startTimer(100);
|
||||||
|
+ }, Qt::QueuedConnection);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void QWaylandWindow::deliverUpdateRequest()
|
||||||
|
+{
|
||||||
|
+ mWaitingForUpdate = true;
|
||||||
|
+ QPlatformWindow::deliverUpdateRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QWaylandWindow::addAttachOffset(const QPoint point)
|
||||||
|
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
|
||||||
|
index 56ebd3cc..c47123dc 100644
|
||||||
|
--- a/src/client/qwaylandwindow_p.h
|
||||||
|
+++ b/src/client/qwaylandwindow_p.h
|
||||||
|
@@ -120,7 +120,7 @@ public:
|
||||||
|
void handleExpose(const QRegion ®ion);
|
||||||
|
void commit(QWaylandBuffer *buffer, const QRegion &damage);
|
||||||
|
|
||||||
|
- void waitForFrameSync();
|
||||||
|
+ bool waitForFrameSync(int timeout);
|
||||||
|
|
||||||
|
QMargins frameMargins() const override;
|
||||||
|
|
||||||
|
@@ -191,7 +191,10 @@ public:
|
||||||
|
|
||||||
|
bool startSystemMove(const QPoint &pos) override;
|
||||||
|
|
||||||
|
+ void timerEvent(QTimerEvent *event) override;
|
||||||
|
void requestUpdate() override;
|
||||||
|
+ void handleUpdate();
|
||||||
|
+ void deliverUpdateRequest() override;
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void applyConfigure();
|
||||||
|
@@ -211,10 +214,17 @@ protected:
|
||||||
|
Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton;
|
||||||
|
|
||||||
|
WId mWindowId;
|
||||||
|
- bool mWaitingForFrameSync = false;
|
||||||
|
+ bool mWaitingForFrameCallback = false;
|
||||||
|
+ bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
|
||||||
|
+ int mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback
|
||||||
|
struct ::wl_callback *mFrameCallback = nullptr;
|
||||||
|
+ struct ::wl_event_queue *mFrameQueue = nullptr;
|
||||||
|
QWaitCondition mFrameSyncWait;
|
||||||
|
|
||||||
|
+ // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
|
||||||
|
+ bool mWaitingForUpdate = false;
|
||||||
|
+ int mFallbackUpdateTimerId = -1; // Started when waiting for app to commit
|
||||||
|
+
|
||||||
|
QMutex mResizeLock;
|
||||||
|
bool mWaitingToApplyConfigure = false;
|
||||||
|
bool mCanResize = true;
|
||||||
|
@@ -253,11 +263,10 @@ private:
|
||||||
|
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
|
||||||
|
void handleScreenChanged();
|
||||||
|
|
||||||
|
- bool mUpdateRequested = false;
|
||||||
|
QRect mLastExposeGeometry;
|
||||||
|
|
||||||
|
static const wl_callback_listener callbackListener;
|
||||||
|
- static void frameCallback(void *data, struct wl_callback *wl_callback, uint32_t time);
|
||||||
|
+ void handleFrameCallback();
|
||||||
|
|
||||||
|
static QMutex mFrameSyncMutex;
|
||||||
|
static QWaylandWindow *mMouseGrab;
|
||||||
|
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||||
|
index e58403ad..30dab408 100644
|
||||||
|
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||||
|
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
|
||||||
|
@@ -315,7 +315,9 @@ QWaylandGLContext::QWaylandGLContext(EGLDisplay eglDisplay, QWaylandDisplay *dis
|
||||||
|
mSupportNonBlockingSwap = false;
|
||||||
|
}
|
||||||
|
if (!mSupportNonBlockingSwap) {
|
||||||
|
- qWarning() << "Non-blocking swap buffers not supported. Subsurface rendering can be affected.";
|
||||||
|
+ qWarning(lcQpaWayland) << "Non-blocking swap buffers not supported."
|
||||||
|
+ << "Subsurface rendering can be affected."
|
||||||
|
+ << "It may also cause the event loop to freeze in some situations";
|
||||||
|
}
|
||||||
|
|
||||||
|
updateGLFormat();
|
||||||
|
@@ -550,20 +552,15 @@ void QWaylandGLContext::swapBuffers(QPlatformSurface *surface)
|
||||||
|
m_blitter->blit(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
-
|
||||||
|
- QWaylandSubSurface *sub = window->subSurfaceWindow();
|
||||||
|
- if (sub) {
|
||||||
|
- QMutexLocker l(sub->syncMutex());
|
||||||
|
-
|
||||||
|
- int si = (sub->isSync() && mSupportNonBlockingSwap) ? 0 : m_format.swapInterval();
|
||||||
|
-
|
||||||
|
- eglSwapInterval(m_eglDisplay, si);
|
||||||
|
- eglSwapBuffers(m_eglDisplay, eglSurface);
|
||||||
|
- } else {
|
||||||
|
- eglSwapInterval(m_eglDisplay, m_format.swapInterval());
|
||||||
|
- eglSwapBuffers(m_eglDisplay, eglSurface);
|
||||||
|
+ int swapInterval = mSupportNonBlockingSwap ? 0 : m_format.swapInterval();
|
||||||
|
+ eglSwapInterval(m_eglDisplay, swapInterval);
|
||||||
|
+ if (swapInterval == 0 && m_format.swapInterval() > 0) {
|
||||||
|
+ // Emulating a blocking swap
|
||||||
|
+ glFlush(); // Flush before waiting so we can swap more quickly when the frame event arrives
|
||||||
|
+ window->waitForFrameSync(100);
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ window->handleUpdate();
|
||||||
|
+ eglSwapBuffers(m_eglDisplay, eglSurface);
|
||||||
|
|
||||||
|
window->setCanResize(true);
|
||||||
|
}
|
||||||
|
diff --git a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp
|
||||||
|
index c07ad534..a6fead95 100644
|
||||||
|
--- a/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp
|
||||||
|
+++ b/src/hardwareintegration/client/xcomposite-egl/qwaylandxcompositeeglcontext.cpp
|
||||||
|
@@ -65,7 +65,7 @@ void QWaylandXCompositeEGLContext::swapBuffers(QPlatformSurface *surface)
|
||||||
|
QSize size = w->geometry().size();
|
||||||
|
|
||||||
|
w->commit(w->buffer(), QRegion(0, 0, size.width(), size.height()));
|
||||||
|
- w->waitForFrameSync();
|
||||||
|
+ w->waitForFrameSync(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
EGLSurface QWaylandXCompositeEGLContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
|
||||||
|
diff --git a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp
|
||||||
|
index 33ae2e03..35188741 100644
|
||||||
|
--- a/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp
|
||||||
|
+++ b/src/hardwareintegration/client/xcomposite-glx/qwaylandxcompositeglxcontext.cpp
|
||||||
|
@@ -93,7 +93,7 @@ void QWaylandXCompositeGLXContext::swapBuffers(QPlatformSurface *surface)
|
||||||
|
glXSwapBuffers(m_display, w->xWindow());
|
||||||
|
|
||||||
|
w->commit(w->buffer(), QRegion(0, 0, size.width(), size.height()));
|
||||||
|
- w->waitForFrameSync();
|
||||||
|
+ w->waitForFrameSync(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
QFunctionPointer QWaylandXCompositeGLXContext::getProcAddress(const char *procName)
|
||||||
|
--
|
||||||
|
2.22.0
|
||||||
|
|
Loading…
Reference in a new issue