mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-01-20 03:43:45 +00:00
Merge pull request #68351 from petabyteboy/feature/qt-patches-staging
qt512: Add patches for QTBUG-73459 and QTBUG-69077
This commit is contained in:
commit
5b14ea3b05
@ -53,6 +53,7 @@ let
|
||||
qtbase = [
|
||||
./qtbase.patch
|
||||
./qtbase-fixguicmake.patch
|
||||
./qtbase-trayicons.patch # can be removed with 5.12.4 or 5.13
|
||||
];
|
||||
qtdeclarative = [ ./qtdeclarative.patch ];
|
||||
qtscript = [ ./qtscript.patch ];
|
||||
@ -67,6 +68,10 @@ let
|
||||
./qtwebkit-darwin-no-qos-classes.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 =
|
||||
|
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 New Issue
Block a user