fix: 修复部分托盘服务对应进程状态异常时导致任务栏卡死问题

fcitx进程异常时,其statusnotifieritem服务被任务栏调用会导致任务栏卡死

Log: 解决部分情况下任务栏卡死问题
Influence: 托盘服务
Bug: https://pms.uniontech.com/bug-view-121947.html
Change-Id: Ia7bc9cf077b3b707677a5fe5388b483600ba0de8
This commit is contained in:
范朋程 2022-09-16 13:10:35 +08:00 committed by donghualin
parent c7826edd46
commit 7ac4592ebb
5 changed files with 44 additions and 96 deletions

View File

@ -29,6 +29,9 @@
#include <QPainter>
#include <QApplication>
#include <QDBusPendingCall>
#include <QtConcurrent>
#include <QFuture>
#include <xcb/xproto.h>
@ -86,6 +89,7 @@ SNITrayItemWidget::SNITrayItemWidget(const QString &sniServicePath, QWidget *par
setOwnerPID(conn.interface()->servicePid(m_dbusService));
m_sniInter = new StatusNotifierItem(m_dbusService, m_dbusPath, QDBusConnection::sessionBus(), this);
m_sniInter->setSync(false);
if (!m_sniInter->isValid()) {
qDebug() << "SNI dbus interface is invalid!" << m_dbusService << m_dbusPath << m_sniInter->lastError();
@ -147,30 +151,11 @@ SNITrayItemWidget::SNITrayItemWidget(const QString &sniServicePath, QWidget *par
connect(m_sniInter, &StatusNotifierItem::NewStatus, [ = ] {
onSNIStatusChanged(m_sniInter->status());
});
initSNIPropertys();
}
QString SNITrayItemWidget::itemKeyForConfig()
{
QString key;
do {
key = m_sniId;
if (!key.isEmpty()) {
break;
}
key = QDBusInterface(m_dbusService, m_dbusPath, StatusNotifierItem::staticInterfaceName())
.property("Id").toString();
if (!key.isEmpty()) {
break;
}
key = m_sniServicePath;
} while (false);
return QString("sni:%1").arg(key);
return QString("sni:%1").arg(m_sniId.isEmpty() ? m_sniServicePath : m_sniId);
}
void SNITrayItemWidget::updateIcon()
@ -181,13 +166,18 @@ void SNITrayItemWidget::updateIcon()
void SNITrayItemWidget::sendClick(uint8_t mouseButton, int x, int y)
{
switch (mouseButton) {
case XCB_BUTTON_INDEX_1:
// left button click invalid
if (LeftClickInvalidIdList.contains(m_sniId)) {
showContextMenu(x, y);
} else {
m_sniInter->Activate(x, y);
}
case XCB_BUTTON_INDEX_1: {
QFuture<void> future = QtConcurrent::run([ = ] {
StatusNotifierItem inter(m_dbusService, m_dbusPath, QDBusConnection::sessionBus());
QDBusPendingReply<> reply = inter.Activate(x, y);
// try to invoke context menu while calling activate get a error.
// primarily work for apps using libappindicator.
reply.waitForFinished();
if (reply.isError()) {
showContextMenu(x,y);
}
});
}
break;
case XCB_BUTTON_INDEX_2:
m_sniInter->SecondaryActivate(x, y);
@ -256,24 +246,6 @@ uint SNITrayItemWidget::servicePID(const QString &servicePath)
return conn.interface()->servicePid(serviceName);
}
void SNITrayItemWidget::initSNIPropertys()
{
m_sniAttentionIconName = m_sniInter->attentionIconName();
m_sniAttentionIconPixmap = m_sniInter->attentionIconPixmap();
m_sniAttentionMovieName = m_sniInter->attentionMovieName();
m_sniCategory = m_sniInter->category();
m_sniIconName = m_sniInter->iconName();
m_sniIconPixmap = m_sniInter->iconPixmap();
m_sniIconThemePath = m_sniInter->iconThemePath();
m_sniId = m_sniInter->id();
m_sniMenuPath = m_sniInter->menu();
m_sniOverlayIconName = m_sniInter->overlayIconName();
m_sniOverlayIconPixmap = m_sniInter->overlayIconPixmap();
m_sniStatus = m_sniInter->status();
m_updateIconTimer->start();
}
void SNITrayItemWidget::initMenu()
{
const QString &sniMenuPath = m_sniMenuPath.path();

View File

@ -81,7 +81,6 @@ Q_SIGNALS:
void statusChanged(SNITrayItemWidget::ItemStatus status);
private Q_SLOTS:
void initSNIPropertys();
void initMenu();
void refreshIcon();
void refreshOverlayIcon();

View File

@ -30,6 +30,9 @@
#include <QPainter>
#include <QApplication>
#include <QDBusPendingCall>
#include <QtConcurrent>
#include <QFuture>
#include <xcb/xproto.h>
@ -39,7 +42,6 @@ DGUI_USE_NAMESPACE
const QStringList ItemCategoryList {"ApplicationStatus", "Communications", "SystemServices", "Hardware"};
const QStringList ItemStatusList {"Passive", "Active", "NeedsAttention"};
const QStringList LeftClickInvalidIdList {"sogou-qimpanel",};
QPointer<DockPopupWindow> SNITrayWidget::PopupWindow = nullptr;
Dock::Position SNITrayWidget::DockPosition = Dock::Position::Top;
using namespace Dock;
@ -93,7 +95,7 @@ SNITrayWidget::SNITrayWidget(const QString &sniServicePath, QWidget *parent)
setOwnerPID(conn.interface()->servicePid(m_dbusService));
m_sniInter = new StatusNotifierItem(m_dbusService, m_dbusPath, QDBusConnection::sessionBus(), this);
m_sniInter->setSync(false);
if (!m_sniInter->isValid()) {
qDebug() << "SNI dbus interface is invalid!" << m_dbusService << m_dbusPath << m_sniInter->lastError();
return;
@ -154,30 +156,11 @@ SNITrayWidget::SNITrayWidget(const QString &sniServicePath, QWidget *parent)
connect(m_sniInter, &StatusNotifierItem::NewStatus, [ = ] {
onSNIStatusChanged(m_sniInter->status());
});
initSNIPropertys();
}
QString SNITrayWidget::itemKeyForConfig()
{
QString key;
do {
key = m_sniId;
if (!key.isEmpty()) {
break;
}
key = QDBusInterface(m_dbusService, m_dbusPath, StatusNotifierItem::staticInterfaceName())
.property("Id").toString();
if (!key.isEmpty()) {
break;
}
key = m_sniServicePath;
} while (false);
return QString("sni:%1").arg(key);
return QString("sni:%1").arg(m_sniId.isEmpty() ? m_sniServicePath : m_sniId);
}
void SNITrayWidget::updateIcon()
@ -188,13 +171,18 @@ void SNITrayWidget::updateIcon()
void SNITrayWidget::sendClick(uint8_t mouseButton, int x, int y)
{
switch (mouseButton) {
case XCB_BUTTON_INDEX_1:
// left button click invalid
if (LeftClickInvalidIdList.contains(m_sniId)) {
showContextMenu(x, y);
} else {
m_sniInter->Activate(x, y);
}
case XCB_BUTTON_INDEX_1: {
QFuture<void> future = QtConcurrent::run([ = ] {
StatusNotifierItem inter(m_dbusService, m_dbusPath, QDBusConnection::sessionBus());
QDBusPendingReply<> reply = inter.Activate(x, y);
// try to invoke context menu while calling activate get a error.
// primarily work for apps using libappindicator.
reply.waitForFinished();
if (reply.isError()) {
showContextMenu(x,y);
}
});
}
break;
case XCB_BUTTON_INDEX_2:
m_sniInter->SecondaryActivate(x, y);
@ -263,26 +251,6 @@ uint SNITrayWidget::servicePID(const QString &servicePath)
return conn.interface()->servicePid(serviceName);
}
void SNITrayWidget::initSNIPropertys()
{
m_sniAttentionIconName = m_sniInter->attentionIconName();
m_sniAttentionIconPixmap = m_sniInter->attentionIconPixmap();
m_sniAttentionMovieName = m_sniInter->attentionMovieName();
m_sniCategory = m_sniInter->category();
m_sniIconName = m_sniInter->iconName();
m_sniIconPixmap = m_sniInter->iconPixmap();
m_sniIconThemePath = m_sniInter->iconThemePath();
m_sniId = m_sniInter->id();
m_sniMenuPath = m_sniInter->menu();
m_sniOverlayIconName = m_sniInter->overlayIconName();
m_sniOverlayIconPixmap = m_sniInter->overlayIconPixmap();
m_sniStatus = m_sniInter->status();
m_updateIconTimer->start();
// m_updateOverlayIconTimer->start();
// m_updateAttentionIconTimer->start();
}
void SNITrayWidget::initMenu()
{
const QString &sniMenuPath = m_sniMenuPath.path();

View File

@ -79,7 +79,6 @@ Q_SIGNALS:
void statusChanged(SNITrayWidget::ItemStatus status);
private Q_SLOTS:
void initSNIPropertys();
void initMenu();
void refreshIcon();
void refreshOverlayIcon();

View File

@ -480,12 +480,22 @@ void TrayPlugin::traySNIAdded(const QString &itemKey, const QString &sniServiceP
return false;
}
// 1、确保服务有效
QDBusInterface sniItemDBus(sniServerName, "/" + list.last());
if (!sniItemDBus.isValid()) {
qDebug() << "sni dbus service error : " << sniServerName;
return false;
}
// 部分服务虽然有效但是在dbus总线上只能看到服务其他信息都无法获取,这里通过Ping进行二次确认
// 参考: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces
// 2、通过Ping接口确认服务是否正常
QDBusInterface peerInter(sniServerName, "/" + list.last(), "org.freedesktop.DBus.Peer");
QDBusReply<void> reply = peerInter.call("Ping");
if (!reply.isValid())
return false;
return true;
});