From 7c9af838ad192e19ab534181130adc3a9a82c2f6 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Wed, 11 Mar 2026 12:21:31 +0800 Subject: [PATCH] feat: refactor SNI tray initialization to use thread pool MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Changed SNI tray item initialization from synchronous to asynchronous using QThreadPool 2. Added pending items tracking to handle concurrent creation and cancellation 3. Delayed QLabel creation for tooltip to ensure proper thread context 4. Set DBus timeout to 2000ms to prevent blocking 5. Removed async DBus calls that caused data inconsistency issues Log: Improved application tray startup performance and stability Influence: 1. Test tray icon loading with multiple applications simultaneously 2. Verify tray icons appear correctly without delays or missing icons 3. Test tooltip display functionality for SNI tray items 4. Verify tray removal when applications close 5. Test concurrent tray item addition and removal scenarios 6. Check memory usage during rapid tray updates 7. Verify no DBus-related crashes or data inconsistencies feat: 重构SNI托盘初始化改用线程池 1. 将SNI托盘项初始化从同步改为异步,使用QThreadPool 2. 添加待处理项跟踪以处理并发创建和取消 3. 延迟创建QLabel工具提示,确保正确的线程上下文 4. 设置DBus超时为2000ms以防止阻塞 5. 移除导致数据不一致问题的异步DBus调用 Log: 提升应用托盘启动性能和稳定性 Influence: 1. 测试同时加载多个应用程序时的托盘图标 2. 验证托盘图标正确显示,无延迟或缺失图标 3. 测试SNI托盘项的工具提示显示功能 4. 验证应用程序关闭时托盘项正确移除 5. 测试并发托盘项添加和移除场景 6. 检查快速托盘更新时的内存使用情况 7. 验证无DBus相关崩溃或数据不一致问题 PMS: BUG-351735 BUG-351739 --- .../application-tray/sniprotocolhandler.cpp | 64 +++++++++++++++---- plugins/application-tray/sniprotocolhandler.h | 3 +- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/plugins/application-tray/sniprotocolhandler.cpp b/plugins/application-tray/sniprotocolhandler.cpp index dd277ac6..1517afc2 100644 --- a/plugins/application-tray/sniprotocolhandler.cpp +++ b/plugins/application-tray/sniprotocolhandler.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include @@ -75,20 +77,38 @@ void SniTrayProtocol::registedItemChanged() return; } - for (auto currentRegistedItem : currentRegistedItems) { - if (!m_registedItem.contains(currentRegistedItem)) { - auto trayHandler = QSharedPointer(new SniTrayProtocolHandler(currentRegistedItem)); - uint pid = QDBusConnection::sessionBus().interface()->servicePid(SniTrayProtocolHandler::serviceAndPath(currentRegistedItem).first).value(); - m_item2Pid[currentRegistedItem] = pid; - if (registeredMap[pid] != SNI) - emit removeXEmbedItemByPid(pid); - registeredMap[pid] = SNI; - m_registedItem.insert(currentRegistedItem, trayHandler); - Q_EMIT AbstractTrayProtocol::trayCreated(trayHandler.get()); + // 处理新增的items:在子线程创建 Handler(init() 阻塞在此) + for (const auto ¤tRegistedItem : currentRegistedItems) { + if (!m_registedItem.contains(currentRegistedItem) && !m_pendingItems.contains(currentRegistedItem)) { + m_pendingItems.insert(currentRegistedItem); + + QThreadPool::globalInstance()->start([this, currentRegistedItem]() { + auto pair = SniTrayProtocolHandler::serviceAndPath(currentRegistedItem); + const uint pid = QDBusConnection::sessionBus().interface()->servicePid(pair.first).value(); + + auto trayHandler = QSharedPointer( + new SniTrayProtocolHandler(currentRegistedItem)); + trayHandler->moveToThread(this->thread()); + + QMetaObject::invokeMethod(this, [this, currentRegistedItem, pid, trayHandler]() { + if (!m_pendingItems.contains(currentRegistedItem)) { + return; // item 已被取消,不添加 + } + m_pendingItems.remove(currentRegistedItem); + + m_item2Pid[currentRegistedItem] = pid; + if (registeredMap[pid] != SNI) + emit removeXEmbedItemByPid(pid); + registeredMap[pid] = SNI; + m_registedItem.insert(currentRegistedItem, trayHandler); + Q_EMIT AbstractTrayProtocol::trayCreated(trayHandler.get()); + }, Qt::QueuedConnection); + }); } } - for (auto alreadyRegistedItem : m_registedItem.keys()) { + // 处理移除的items + for (const auto &alreadyRegistedItem : m_registedItem.keys()) { if (!currentRegistedItems.contains(alreadyRegistedItem)) { if (auto value = m_registedItem.value(alreadyRegistedItem, nullptr)) { uint pid = m_item2Pid[alreadyRegistedItem]; @@ -98,11 +118,22 @@ void SniTrayProtocol::registedItemChanged() } } } + + // 移除pending中但不在当前列表的items(取消异步创建) + QSet toRemoveFromPending; + for (const auto &pendingItem : m_pendingItems) { + if (!currentRegistedItems.contains(pendingItem)) { + toRemoveFromPending.insert(pendingItem); + } + } + for (const auto &item : toRemoveFromPending) { + m_pendingItems.remove(item); + } } SniTrayProtocolHandler::SniTrayProtocolHandler(const QString &sniServicePath, QObject *parent) : AbstractTrayProtocolHandler(parent) - , m_tooltip (new QLabel()) + , m_tooltip(nullptr) // 延迟创建,在tooltip()方法中创建 , m_ignoreFirstAttention(true) , m_dbusMenuImporter(nullptr) { @@ -111,9 +142,8 @@ SniTrayProtocolHandler::SniTrayProtocolHandler(const QString &sniServicePath, QO // will get a unique dbus name (number like x.xxxx) and dbus path m_dbusUniqueName = pair.first.mid(1); m_sniInter = new StatusNotifierItem(pair.first, pair.second, QDBusConnection::sessionBus(), this); + m_sniInter->setTimeout(2000); init(); - m_sniInter->setSync(false); - m_tooltip->setForegroundRole(QPalette::BrightText); connect(m_sniInter, &StatusNotifierItem::NewIcon, this, &SniTrayProtocolHandler::iconChanged); connect(m_sniInter, &StatusNotifierItem::NewOverlayIcon, this, &SniTrayProtocolHandler::overlayIconChanged); @@ -183,6 +213,12 @@ QString SniTrayProtocolHandler::status() const QWidget* SniTrayProtocolHandler::tooltip() const { + // 延迟创建label,确保在主线程创建 + if (!m_tooltip) { + const_cast(this)->m_tooltip = new QLabel(); + m_tooltip->setForegroundRole(QPalette::BrightText); + } + if (!m_sniInter->toolTip().title.isEmpty()) { m_tooltip->setText(m_sniInter->toolTip().title); return m_tooltip; diff --git a/plugins/application-tray/sniprotocolhandler.h b/plugins/application-tray/sniprotocolhandler.h index 97bcd4b4..3a6d5cd4 100644 --- a/plugins/application-tray/sniprotocolhandler.h +++ b/plugins/application-tray/sniprotocolhandler.h @@ -39,6 +39,7 @@ private Q_SLOTS: QHash> m_registedItem; QHash m_item2Pid; + QSet m_pendingItems; // 跟踪正在异步创建的items }; class SniTrayProtocolHandler : public AbstractTrayProtocolHandler @@ -46,7 +47,7 @@ class SniTrayProtocolHandler : public AbstractTrayProtocolHandler Q_OBJECT public: - SniTrayProtocolHandler(const QString &sniServicePath, QObject *parent= nullptr); + SniTrayProtocolHandler(const QString &sniServicePath, QObject *parent = nullptr); ~SniTrayProtocolHandler(); virtual uint32_t windowId() const override;