From 30ad57f5bd43902fe63eb3d12d475791ccd4848a Mon Sep 17 00:00:00 2001 From: Patrick J Volkerding Date: Fri, 21 Jan 2022 05:47:49 +0000 Subject: Fri Jan 21 05:47:49 UTC 2022 a/aaa_libraries-15.0-x86_64-15.txz: Rebuilt. Upgraded: libzstd.so.1.5.2. a/kernel-firmware-20220119_0c6a7b3-noarch-1.txz: Upgraded. a/kernel-generic-5.15.16-x86_64-1.txz: Upgraded. a/kernel-huge-5.15.16-x86_64-1.txz: Upgraded. a/kernel-modules-5.15.16-x86_64-1.txz: Upgraded. ap/vim-8.2.4166-x86_64-1.txz: Upgraded. d/kernel-headers-5.15.16-x86-1.txz: Upgraded. d/rust-1.58.1-x86_64-1.txz: Upgraded. k/kernel-source-5.15.16-noarch-1.txz: Upgraded. l/qt5-5.15.3_20211130_014c375b-x86_64-2.txz: Rebuilt. Applied upstream patch: [PATCH] Move the wayland socket polling to a separate event thread. Thanks to LuckyCyborg. l/svgalib-1.9.25-x86_64-7.txz: Rebuilt. Don't try to use the (broken) assembly. Thanks to nobodino. l/zstd-1.5.2-x86_64-1.txz: Upgraded. x/ibus-m17n-1.4.9-x86_64-1.txz: Upgraded. xap/vim-gvim-8.2.4166-x86_64-1.txz: Upgraded. extra/php80/php80-8.0.15-x86_64-1.txz: Upgraded. extra/php81/php81-8.1.2-x86_64-1.txz: Upgraded. isolinux/initrd.img: Rebuilt. kernels/*: Upgraded. usb-and-pxe-installers/usbboot.img: Rebuilt. --- source/l/qt5/patches/24.diff | 585 +++++++++++++++++++++++++++++++++++++++++++ source/l/qt5/qt5.SlackBuild | 11 +- 2 files changed, 594 insertions(+), 2 deletions(-) create mode 100644 source/l/qt5/patches/24.diff (limited to 'source/l/qt5') diff --git a/source/l/qt5/patches/24.diff b/source/l/qt5/patches/24.diff new file mode 100644 index 000000000..5921881b7 --- /dev/null +++ b/source/l/qt5/patches/24.diff @@ -0,0 +1,585 @@ +diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp +index ea344c61c3a4643f7c725a6287f20d742b210d24..a7ce280a5df538917758e50ba8d2ee117378d546 100644 +--- a/src/client/qwaylanddisplay.cpp ++++ b/src/client/qwaylanddisplay.cpp +@@ -85,10 +85,203 @@ + + #include + ++#include // for std::tie ++ ++static void checkWaylandError(struct wl_display *display) ++{ ++ int ecode = wl_display_get_error(display); ++ if ((ecode == EPIPE || ecode == ECONNRESET)) { ++ // special case this to provide a nicer error ++ qWarning("The Wayland connection broke. Did the Wayland compositor die?"); ++ } else { ++ qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode)); ++ } ++ _exit(1); ++} ++ + QT_BEGIN_NAMESPACE + + namespace QtWaylandClient { + ++class EventThread : public QThread ++{ ++ Q_OBJECT ++public: ++ enum OperatingMode { ++ EmitToDispatch, // Emit the signal, allow dispatching in a differnt thread. ++ SelfDispatch, // Dispatch the events inside this thread. ++ }; ++ ++ EventThread(struct wl_display * wl, struct wl_event_queue * ev_queue, ++ OperatingMode mode) ++ : m_fd(wl_display_get_fd(wl)) ++ , m_pipefd{ -1, -1 } ++ , m_wldisplay(wl) ++ , m_wlevqueue(ev_queue) ++ , m_mode(mode) ++ , m_reading(true) ++ , m_quitting(false) ++ { ++ setObjectName(QStringLiteral("WaylandEventThread")); ++ } ++ ++ void readAndDispatchEvents() ++ { ++ /* ++ * Dispatch pending events and flush the requests at least once. If the event thread ++ * is not reading, try to call _prepare_read() to allow the event thread to poll(). ++ * If that fails, re-try dispatch & flush again until _prepare_read() is successful. ++ * ++ * This allow any call to readAndDispatchEvents() to start event thread's polling, ++ * not only the one issued from event thread's waitForReading(), which means functions ++ * called from dispatch_pending() can safely spin an event loop. ++ */ ++ for (;;) { ++ if (dispatchQueuePending() < 0) { ++ checkWaylandError(m_wldisplay); ++ return; ++ } ++ ++ wl_display_flush(m_wldisplay); ++ ++ // We have to check if event thread is reading every time we dispatch ++ // something, as that may recursively call this function. ++ if (m_reading.loadAcquire()) ++ break; ++ ++ if (prepareReadQueue() == 0) { ++ QMutexLocker l(&m_mutex); ++ m_reading.storeRelease(true); ++ m_cond.wakeOne(); ++ break; ++ } ++ } ++ } ++ ++ void stop() ++ { ++ // We have to both write to the pipe and set the flag, as the thread may be ++ // either in the poll() or waiting for _prepare_read(). ++ if (m_pipefd[1] != -1 && write(m_pipefd[1], "\0", 1) == -1) ++ qWarning("Failed to write to the pipe: %s.", strerror(errno)); ++ ++ { ++ QMutexLocker l(&m_mutex); ++ m_quitting = true; ++ m_cond.wakeOne(); ++ } ++ ++ wait(); ++ } ++ ++Q_SIGNALS: ++ void needReadAndDispatch(); ++ ++protected: ++ void run() override ++ { ++ // we use this pipe to make the loop exit otherwise if we simply used a flag on the loop condition, if stop() gets ++ // called while poll() is blocking the thread will never quit since there are no wayland messages coming anymore. ++ struct Pipe ++ { ++ Pipe(int *fds) ++ : fds(fds) ++ { ++ if (qt_safe_pipe(fds) != 0) ++ qWarning("Pipe creation failed. Quitting may hang."); ++ } ++ ~Pipe() ++ { ++ if (fds[0] != -1) { ++ close(fds[0]); ++ close(fds[1]); ++ } ++ } ++ ++ int *fds; ++ } pipe(m_pipefd); ++ ++ // Make the main thread call wl_prepare_read(), dispatch the pending messages and flush the ++ // outbound ones. Wait until it's done before proceeding, unless we're told to quit. ++ while (waitForReading()) { ++ pollfd fds[2] = { { m_fd, POLLIN, 0 }, { m_pipefd[0], POLLIN, 0 } }; ++ poll(fds, 2, -1); ++ ++ if (fds[1].revents & POLLIN) { ++ // we don't really care to read the byte that was written here since we're closing down ++ wl_display_cancel_read(m_wldisplay); ++ break; ++ } ++ ++ if (fds[0].revents & POLLIN) ++ wl_display_read_events(m_wldisplay); ++ // The polll was succesfull and the event thread did the wl_display_read_events(). On the next iteration of the loop ++ // the event sent to the main thread will cause it to dispatch the messages just read, unless the loop exits in which ++ // case we don't care anymore about them. ++ else ++ wl_display_cancel_read(m_wldisplay); ++ } ++ } ++ ++private: ++ bool waitForReading() ++ { ++ Q_ASSERT(QThread::currentThread() == this); ++ ++ m_reading.storeRelease(false); ++ ++ if (m_mode == SelfDispatch) { ++ readAndDispatchEvents(); ++ } else { ++ Q_EMIT needReadAndDispatch(); ++ ++ QMutexLocker lock(&m_mutex); ++ // m_reading might be set from our emit or some other invocation of ++ // readAndDispatchEvents(). ++ while (!m_reading.loadRelaxed() && !m_quitting) ++ m_cond.wait(&m_mutex); ++ } ++ ++ return !m_quitting; ++ } ++ ++ int dispatchQueuePending() ++ { ++ if (m_wlevqueue) ++ return wl_display_dispatch_queue_pending(m_wldisplay, m_wlevqueue); ++ else ++ return wl_display_dispatch_pending(m_wldisplay); ++ } ++ ++ int prepareReadQueue() ++ { ++ if (m_wlevqueue) ++ return wl_display_prepare_read_queue(m_wldisplay, m_wlevqueue); ++ else ++ return wl_display_prepare_read(m_wldisplay); ++ } ++ ++ int m_fd; ++ int m_pipefd[2]; ++ wl_display *m_wldisplay; ++ wl_event_queue *m_wlevqueue; ++ OperatingMode m_mode; ++ ++ /* Concurrency note when operating in EmitToDispatch mode: ++ * m_reading is set to false inside event thread's waitForReading(), and is ++ * set to true inside main thread's readAndDispatchEvents(). ++ * The lock is not taken when setting m_reading to false, as the main thread ++ * is not actively waiting for it to turn false. However, the lock is taken ++ * inside readAndDispatchEvents() before setting m_reading to true, ++ * as the event thread is actively waiting for it under the wait condition. ++ */ ++ ++ QAtomicInteger m_reading; ++ bool m_quitting; ++ QMutex m_mutex; ++ QWaitCondition m_cond; ++}; ++ + Q_LOGGING_CATEGORY(lcQpaWayland, "qt.qpa.wayland"); // for general (uncategorized) Wayland platform logging + + struct wl_surface *QWaylandDisplay::createSurface(void *handle) +@@ -158,17 +351,16 @@ QWaylandDisplay::QWaylandDisplay(QWaylandIntegration *waylandIntegration) + if (!mXkbContext) + qCWarning(lcQpaWayland, "failed to create xkb context"); + #endif +- +- forceRoundTrip(); +- +- if (!mWaitingScreens.isEmpty()) { +- // Give wl_output.done and zxdg_output_v1.done events a chance to arrive +- forceRoundTrip(); +- } + } + + QWaylandDisplay::~QWaylandDisplay(void) + { ++ if (m_eventThread) ++ m_eventThread->stop(); ++ ++ if (m_frameEventQueueThread) ++ m_frameEventQueueThread->stop(); ++ + if (mSyncCallback) + wl_callback_destroy(mSyncCallback); + +@@ -189,6 +381,18 @@ QWaylandDisplay::~QWaylandDisplay(void) + wl_display_disconnect(mDisplay); + } + ++// Steps which is called just after constructor. This separates registry_global() out of the constructor ++// so that factory functions in integration can be overridden. ++void QWaylandDisplay::initialize() ++{ ++ forceRoundTrip(); ++ ++ if (!mWaitingScreens.isEmpty()) { ++ // Give wl_output.done and zxdg_output_v1.done events a chance to arrive ++ forceRoundTrip(); ++ } ++} ++ + void QWaylandDisplay::ensureScreen() + { + if (!mScreens.empty() || mPlaceholderScreen) +@@ -203,98 +407,37 @@ void QWaylandDisplay::ensureScreen() + + void QWaylandDisplay::checkError() const + { +- int ecode = wl_display_get_error(mDisplay); +- if ((ecode == EPIPE || ecode == ECONNRESET)) { +- // special case this to provide a nicer error +- qWarning("The Wayland connection broke. Did the Wayland compositor die?"); +- } else { +- qWarning("The Wayland connection experienced a fatal error: %s", strerror(ecode)); +- } +- _exit(1); ++ checkWaylandError(mDisplay); + } + ++// Called in main thread, either from queued signal or directly. + void QWaylandDisplay::flushRequests() + { +- if (wl_display_prepare_read(mDisplay) == 0) { +- wl_display_read_events(mDisplay); +- } +- +- if (wl_display_dispatch_pending(mDisplay) < 0) +- checkError(); +- +- { +- QReadLocker locker(&m_frameQueueLock); +- for (const FrameQueue &q : mExternalQueues) { +- QMutexLocker locker(q.mutex); +- while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0) +- wl_display_dispatch_queue_pending(mDisplay, q.queue); +- wl_display_read_events(mDisplay); +- wl_display_dispatch_queue_pending(mDisplay, q.queue); +- } +- } +- +- wl_display_flush(mDisplay); +-} +- +-void QWaylandDisplay::blockingReadEvents() +-{ +- if (wl_display_dispatch(mDisplay) < 0) +- checkError(); +-} +- +-void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q) +-{ +- QWriteLocker locker(&m_frameQueueLock); +- auto it = std::find_if(mExternalQueues.begin(), +- mExternalQueues.end(), +- [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; }); +- Q_ASSERT(it != mExternalQueues.end()); +- mExternalQueues.erase(it); +- if (q.queue != nullptr) +- wl_event_queue_destroy(q.queue); +- delete q.mutex; ++ m_eventThread->readAndDispatchEvents(); + } + +-QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue() ++// We have to wait until we have an eventDispatcher before creating the eventThread, ++// otherwise forceRoundTrip() may block inside _events_read() because eventThread is ++// polling. ++void QWaylandDisplay::initEventThread() + { +- QWriteLocker locker(&m_frameQueueLock); +- FrameQueue q{createEventQueue()}; +- mExternalQueues.append(q); +- return q; +-} ++ m_eventThread.reset( ++ new EventThread(mDisplay, /* default queue */ nullptr, EventThread::EmitToDispatch)); ++ connect(m_eventThread.get(), &EventThread::needReadAndDispatch, this, ++ &QWaylandDisplay::flushRequests, Qt::QueuedConnection); ++ m_eventThread->start(); + +-wl_event_queue *QWaylandDisplay::createEventQueue() +-{ +- return wl_display_create_queue(mDisplay); ++ // wl_display_disconnect() free this. ++ m_frameEventQueue = wl_display_create_queue(mDisplay); ++ m_frameEventQueueThread.reset( ++ new EventThread(mDisplay, m_frameEventQueue, EventThread::SelfDispatch)); ++ m_frameEventQueueThread->start(); + } + +-void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function condition, int timeout) ++void QWaylandDisplay::blockingReadEvents() + { +- 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(); +- +- if (!condition()) +- break; +- } ++ if (wl_display_dispatch(mDisplay) < 0) ++ checkWaylandError(mDisplay); + } + + QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const +@@ -669,4 +812,6 @@ QWaylandCursorTheme *QWaylandDisplay::loadCursorTheme(const QString &name, int p + + } // namespace QtWaylandClient + ++#include "qwaylanddisplay.moc" ++ + QT_END_NAMESPACE +diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h +index 09a1736a267d2816873667e9f1ecb4f4892f0ed0..42bc661d3064d770aa9fde8bd62ecdbbc89732a2 100644 +--- a/src/client/qwaylanddisplay_p.h ++++ b/src/client/qwaylanddisplay_p.h +@@ -109,6 +109,7 @@ class QWaylandSurface; + class QWaylandShellIntegration; + class QWaylandCursor; + class QWaylandCursorTheme; ++class EventThread; + + typedef void (*RegistryListener)(void *data, + struct wl_registry *registry, +@@ -120,15 +121,11 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland + Q_OBJECT + + public: +- struct FrameQueue { +- FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {} +- wl_event_queue *queue; +- QMutex *mutex; +- }; +- + QWaylandDisplay(QWaylandIntegration *waylandIntegration); + ~QWaylandDisplay(void) override; + ++ void initialize(); ++ + #if QT_CONFIG(xkbcommon) + struct xkb_context *xkbContext() const { return mXkbContext.get(); } + #endif +@@ -210,12 +207,11 @@ public: + void handleKeyboardFocusChanged(QWaylandInputDevice *inputDevice); + void handleWindowDestroyed(QWaylandWindow *window); + +- wl_event_queue *createEventQueue(); +- FrameQueue createFrameQueue(); +- void destroyFrameQueue(const FrameQueue &q); +- void dispatchQueueWhile(wl_event_queue *queue, std::function condition, int timeout = -1); ++ wl_event_queue *frameEventQueue() { return m_frameEventQueue; }; + + bool isKeyboardAvailable() const; ++ ++ void initEventThread(); + public slots: + void blockingReadEvents(); + void flushRequests(); +@@ -238,6 +234,9 @@ private: + }; + + struct wl_display *mDisplay = nullptr; ++ QScopedPointer m_eventThread; ++ wl_event_queue *m_frameEventQueue = nullptr; ++ QScopedPointer m_frameEventQueueThread; + QtWayland::wl_compositor mCompositor; + QScopedPointer mShm; + QList mWaitingScreens; +@@ -274,11 +273,9 @@ private: + QWaylandInputDevice *mLastInputDevice = nullptr; + QPointer mLastInputWindow; + QPointer mLastKeyboardFocus; +- QVector mActiveWindows; +- QVector mExternalQueues; ++ QList mActiveWindows; + struct wl_callback *mSyncCallback = nullptr; + static const wl_callback_listener syncCallbackListener; +- QReadWriteLock m_frameQueueLock; + + bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull(); + +diff --git a/src/client/qwaylandintegration.cpp b/src/client/qwaylandintegration.cpp +index e5e7dd42c9b0145f4c9852f7e15dcc83106c321d..3b876047293887d17eeb28819c7386ded9e1f131 100644 +--- a/src/client/qwaylandintegration.cpp ++++ b/src/client/qwaylandintegration.cpp +@@ -192,14 +192,18 @@ QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const + + void QWaylandIntegration::initialize() + { ++ mDisplay->initEventThread(); ++ ++ // Call after eventDispatcher is fully connected, for QWaylandDisplay::forceRoundTrip() ++ mDisplay->initialize(); ++ ++ // But the aboutToBlock() and awake() should be connected after initializePlatform(). ++ // Otherwise the connected flushRequests() may consumes up all events before processEvents starts to wait, ++ // so that processEvents(QEventLoop::WaitForMoreEvents) may be blocked in the forceRoundTrip(). + QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher; + QObject::connect(dispatcher, SIGNAL(aboutToBlock()), mDisplay.data(), SLOT(flushRequests())); + QObject::connect(dispatcher, SIGNAL(awake()), mDisplay.data(), SLOT(flushRequests())); + +- int fd = wl_display_get_fd(mDisplay->wl_display()); +- QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data()); +- QObject::connect(sn, SIGNAL(activated(QSocketDescriptor)), mDisplay.data(), SLOT(flushRequests())); +- + // Qt does not support running with no screens + mDisplay->ensureScreen(); + } +diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp +index 1597f67e63ae7834ded50e25b0acf86b71abcd73..7de19a742b6d3f6a3ce0955f59a5bf2879d29c9e 100644 +--- a/src/client/qwaylandwindow.cpp ++++ b/src/client/qwaylandwindow.cpp +@@ -76,7 +76,6 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr; + QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display) + : QPlatformWindow(window) + , mDisplay(display) +- , mFrameQueue(mDisplay->createFrameQueue()) + , mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP")) + { + { +@@ -95,8 +94,6 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display) + + QWaylandWindow::~QWaylandWindow() + { +- mDisplay->destroyFrameQueue(mFrameQueue); +- + delete mWindowDecoration; + + if (mSurface) +@@ -635,6 +632,8 @@ const wl_callback_listener QWaylandWindow::callbackListener = { + + void QWaylandWindow::handleFrameCallback() + { ++ QMutexLocker locker(&mFrameSyncMutex); ++ + mWaitingForFrameCallback = false; + mFrameCallbackElapsedTimer.invalidate(); + +@@ -656,12 +655,16 @@ void QWaylandWindow::handleFrameCallback() + mWaitingForUpdateDelivery = true; + QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection); + } ++ ++ mFrameSyncWait.notify_all(); + } + + bool QWaylandWindow::waitForFrameSync(int timeout) + { +- QMutexLocker locker(mFrameQueue.mutex); +- mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout); ++ QMutexLocker locker(&mFrameSyncMutex); ++ ++ QDeadlineTimer deadline(timeout); ++ while (mWaitingForFrameCallback && mFrameSyncWait.wait(&mFrameSyncMutex, deadline)) { } + + if (mWaitingForFrameCallback) { + qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed"; +@@ -1157,8 +1160,11 @@ void QWaylandWindow::requestUpdate() + 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; ++ { ++ QMutexLocker locker(&mFrameSyncMutex); ++ if (mWaitingForFrameCallback) ++ return; ++ } + + // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet + // This is a somewhat redundant behavior and might indicate a bug in the calling code, so log +@@ -1171,7 +1177,12 @@ void QWaylandWindow::requestUpdate() + // so use invokeMethod to delay the delivery a bit. + QMetaObject::invokeMethod(this, [this] { + // Things might have changed in the meantime +- if (hasPendingUpdateRequest() && !mWaitingForFrameCallback) ++ { ++ QMutexLocker locker(&mFrameSyncMutex); ++ if (mWaitingForFrameCallback) ++ return; ++ } ++ if (hasPendingUpdateRequest()) + deliverUpdateRequest(); + }, Qt::QueuedConnection); + } +@@ -1191,9 +1202,10 @@ void QWaylandWindow::handleUpdate() + if (!mSurface) + return; + +- QMutexLocker locker(mFrameQueue.mutex); ++ QMutexLocker locker(&mFrameSyncMutex); ++ + struct ::wl_surface *wrappedSurface = reinterpret_cast(wl_proxy_create_wrapper(mSurface->object())); +- wl_proxy_set_queue(reinterpret_cast(wrappedSurface), mFrameQueue.queue); ++ wl_proxy_set_queue(reinterpret_cast(wrappedSurface), mDisplay->frameEventQueue()); + mFrameCallback = wl_surface_frame(wrappedSurface); + wl_proxy_wrapper_destroy(wrappedSurface); + wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); +@@ -1203,6 +1215,8 @@ void QWaylandWindow::handleUpdate() + // Start a timer for handling the case when the compositor stops sending frame callbacks. + if (mFrameCallbackTimeout > 0) { + QMetaObject::invokeMethod(this, [this] { ++ QMutexLocker locker(&mFrameSyncMutex); ++ + if (mWaitingForFrameCallback) { + if (mFrameCallbackCheckIntervalTimerId < 0) + mFrameCallbackCheckIntervalTimerId = startTimer(mFrameCallbackTimeout); +diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h +index e06879620c3d033f093b0866f018ec80a72a97c3..d45980a80e9ecc9c5003fa2144de63e6337bda8a 100644 +--- a/src/client/qwaylandwindow_p.h ++++ b/src/client/qwaylandwindow_p.h +@@ -232,7 +232,7 @@ protected: + int mFrameCallbackCheckIntervalTimerId = -1; + QElapsedTimer mFrameCallbackElapsedTimer; + struct ::wl_callback *mFrameCallback = nullptr; +- QWaylandDisplay::FrameQueue mFrameQueue; ++ QMutex mFrameSyncMutex; + QWaitCondition mFrameSyncWait; + + // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer diff --git a/source/l/qt5/qt5.SlackBuild b/source/l/qt5/qt5.SlackBuild index b17df2fd5..d9b2b3942 100755 --- a/source/l/qt5/qt5.SlackBuild +++ b/source/l/qt5/qt5.SlackBuild @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 Patrick J. Volkerding, Sebeka, MN, USA +# Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Patrick J. Volkerding, Sebeka, MN, USA # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -31,7 +31,7 @@ cd $(dirname $0) ; CWD=$(pwd) PKGNAM=qt5 VERSION=$(ls qt-*.tar.?z | rev | cut -f 3- -d . | cut -f 1 -d - | rev) -BUILD=${BUILD:-1} +BUILD=${BUILD:-2} PKGSRC=$(echo $VERSION | cut -d - -f 1) PKGVER=$(echo $VERSION | tr - _) @@ -148,6 +148,13 @@ cd qtwebengine zcat $CWD/patches/qtwebengine-everywhere-src-5.15.2-%231904652.patch.gz | patch -p1 --verbose || exit 1 cd - 1>/dev/null +# Apply upstream patch to move the wayland socket polling to a separate event +# thread. This greatly improves the behavior of Plasma Wayland sessions, fixing +# (for example) stuttering that was occuring on multimedia applications. +cd qtwayland + zcat $CWD/patches/24.diff.gz | patch -p1 --verbose || exit 1 +cd - 1>/dev/null + # If PulseAudio is not found, use the _alsa $TAG and disable it in the build: if ! pkg-config --exists libpulse 2>/dev/null ; then PULSEAUDIO_OPTION="-no-pulseaudio -no-webengine-pulseaudio" -- cgit v1.2.3-65-gdbad