From 04c24fe27e82a54abc72e5ee692e5fa38718c3c3 Mon Sep 17 00:00:00 2001 From: zhaofangxun Date: Tue, 8 Sep 2026 11:10:14 +0800 Subject: [PATCH 1/2] fix(dock): merge theme events into single atomic notification Use a debounce QTimer (single-shot, interval=0) to coalesce color_theme_changed, theme_changed, and active_color_changed events into one atomic send. This eliminates the race condition where three separate Wayland events fired in the same event loop cycle caused intermittent icon rendering failures during dark mode switching on 4K/225% scaling. Replaces direct send calls in setDockColorTheme(), onThemeChanged(), and onActiveColorChanged() with scheduleThemeNotify(). --- panels/dock/pluginmanagerextension.cpp | 35 +++++++++++++++----------- panels/dock/pluginmanagerextension_p.h | 3 +++ 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/panels/dock/pluginmanagerextension.cpp b/panels/dock/pluginmanagerextension.cpp index b130a2257..b1cf53258 100644 --- a/panels/dock/pluginmanagerextension.cpp +++ b/panels/dock/pluginmanagerextension.cpp @@ -483,6 +483,18 @@ void PluginPopup::plugin_popup_set_cursor(Resource *resource, int32_t cursor_sha PluginManager::PluginManager(QWaylandCompositor *compositor) : QWaylandCompositorExtensionTemplate(compositor) { + m_themeNotifyTimer = new QTimer(this); + m_themeNotifyTimer->setSingleShot(true); + m_themeNotifyTimer->setInterval(0); + connect(m_themeNotifyTimer, &QTimer::timeout, this, [this]() { + foreachPluginSurface([this](Resource *source) { + send_color_theme_changed(source->handle, m_dockColorTheme); + auto theme = DGuiApplicationHelper::instance()->applicationTheme(); + send_theme_changed(source->handle, theme->themeName(), theme->iconThemeName()); + send_active_color_changed(source->handle, theme->activeColor().name(), theme->darkActiveColor().name()); + }); + }); + auto theme = DGuiApplicationHelper::instance()->applicationTheme(); QObject::connect(theme, &DPlatformTheme::fontNameChanged, this, &PluginManager::onFontChanged); QObject::connect(theme, &DPlatformTheme::fontPointSizeChanged, this, &PluginManager::onFontChanged); @@ -609,12 +621,7 @@ void PluginManager::setDockColorTheme(uint32_t type) return; m_dockColorTheme = type; - foreach (PluginSurface *plugin, m_pluginSurfaces) { - Resource *target = resourceMap().value(plugin->surface()->waylandClient()); - if (target) { - send_color_theme_changed(target->handle, m_dockColorTheme); - } - } + scheduleThemeNotify(); } void PluginManager::setEmbedPanelMinHeight(int height) @@ -824,10 +831,7 @@ void PluginManager::onFontChanged() void PluginManager::onActiveColorChanged() { - foreachPluginSurface([this](Resource *source) { - auto theme = DGuiApplicationHelper::instance()->applicationTheme(); - send_active_color_changed(source->handle, theme->activeColor().name(), theme->darkActiveColor().name()); - }); + scheduleThemeNotify(); } PluginSurface* PluginManager::findPluginSurface(const QString &pluginId, const QString &itemKey) const @@ -842,10 +846,7 @@ PluginSurface* PluginManager::findPluginSurface(const QString &pluginId, const Q void PluginManager::onThemeChanged() { - foreachPluginSurface([this](Resource *source) { - auto theme = DGuiApplicationHelper::instance()->applicationTheme(); - send_theme_changed(source->handle, theme->themeName(), theme->iconThemeName()); - }); + scheduleThemeNotify(); } void PluginManager::foreachPluginSurface(PluginSurfaceCallback callback) @@ -858,6 +859,12 @@ void PluginManager::foreachPluginSurface(PluginSurfaceCallback callback) } } +void PluginManager::scheduleThemeNotify() +{ + if (m_themeNotifyTimer) + m_themeNotifyTimer->start(); +} + QString PluginManager::dockSizeMsg() const { if (m_dockSize.isEmpty()) diff --git a/panels/dock/pluginmanagerextension_p.h b/panels/dock/pluginmanagerextension_p.h index d3b46284c..26833cf41 100644 --- a/panels/dock/pluginmanagerextension_p.h +++ b/panels/dock/pluginmanagerextension_p.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -128,6 +129,7 @@ private Q_SLOTS: QString popupMinHeightMsg() const; using PluginSurfaceCallback = std::function; void foreachPluginSurface(PluginSurfaceCallback callback); + void scheduleThemeNotify(); PluginSurface* findPluginSurface(const QString &pluginId, const QString &itemKey) const; private: @@ -146,6 +148,7 @@ private Q_SLOTS: // Map of pending XEmbed callbacks: wid -> callback info // Supports multiple concurrent requests from different clients QMap m_pendingXEmbedCallbacks; + QTimer *m_themeNotifyTimer = nullptr; }; class PluginSurface : public QWaylandShellSurfaceTemplate, public QtWaylandServer::plugin From efe2c15d7ea53d672a5e9226ef997aadcdb60a49 Mon Sep 17 00:00:00 2001 From: zhaofangxun Date: Tue, 8 Sep 2026 11:24:15 +0800 Subject: [PATCH 2/2] fix: hoist applicationTheme() call outside foreachPluginSurface loop --- panels/dock/pluginmanagerextension.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/panels/dock/pluginmanagerextension.cpp b/panels/dock/pluginmanagerextension.cpp index b1cf53258..c40430d86 100644 --- a/panels/dock/pluginmanagerextension.cpp +++ b/panels/dock/pluginmanagerextension.cpp @@ -487,9 +487,9 @@ PluginManager::PluginManager(QWaylandCompositor *compositor) m_themeNotifyTimer->setSingleShot(true); m_themeNotifyTimer->setInterval(0); connect(m_themeNotifyTimer, &QTimer::timeout, this, [this]() { - foreachPluginSurface([this](Resource *source) { + auto theme = DGuiApplicationHelper::instance()->applicationTheme(); + foreachPluginSurface([this, theme](Resource *source) { send_color_theme_changed(source->handle, m_dockColorTheme); - auto theme = DGuiApplicationHelper::instance()->applicationTheme(); send_theme_changed(source->handle, theme->themeName(), theme->iconThemeName()); send_active_color_changed(source->handle, theme->activeColor().name(), theme->darkActiveColor().name()); });