From d9ff963a859bc6f12d903f33c25a6c4661d36f3c Mon Sep 17 00:00:00 2001 From: cxc Date: Wed, 24 Jan 2024 14:26:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=98=E7=9B=98=20sniWatcher=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9F=A5=E8=AF=A2pid=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E5=90=88=E5=B9=B6ukui-sni=E6=96=B9=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sni-daemon/snidaemon.cpp | 86 ++++++++++++++++++++++------------- sni-daemon/snidaemon.h | 14 +++++- sni-xembed-proxy/sniproxy.cpp | 31 +++++++++++-- sni-xembed-proxy/sniproxy.h | 4 ++ 4 files changed, 99 insertions(+), 36 deletions(-) diff --git a/sni-daemon/snidaemon.cpp b/sni-daemon/snidaemon.cpp index ba4d41e..2076f83 100644 --- a/sni-daemon/snidaemon.cpp +++ b/sni-daemon/snidaemon.cpp @@ -20,6 +20,7 @@ #include "statusnotifieritem_interface.h" SniDaemon::SniDaemon() { + qDBusRegisterMetaType(); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/StatusNotifierWatcher"),"org.kde.StatusNotifierWatcher",this,QDBusConnection::ExportAllContents); dbus.registerService(QStringLiteral("org.kde.StatusNotifierWatcher")); @@ -38,59 +39,70 @@ SniDaemon::~SniDaemon() dbus.unregisterService(QStringLiteral("org.kde.StatusNotifierWatcher")); } - void SniDaemon::serviceUnregistered(const QString& name) { qDebug()<<"Service "<< name << "unregistered"; m_serviceWatcher->removeWatchedService(name); QString match = name + QLatin1Char('/'); - QStringList::Iterator it = m_registeredServices.begin(); - qDebug()<startsWith(match)) { - QString name = *it; - it = m_registeredServices.erase(it); - emit StatusNotifierItemUnregistered(name); - } else { - ++it; + for(const QString &servicePath : m_registeredServices.keys()) { + if(servicePath.startsWith(match)) { + QString pid = m_registeredServices.take(servicePath); + Q_EMIT StatusNotifierItemUnregistered(servicePath); + if(!m_registeredServices.values().contains(pid) && pid.toUInt() > 0) { + Q_EMIT StatusNotifierItemUnregistered(pid.toUInt()); + } } } if (m_statusNotifierHostServices.contains(name)) { m_statusNotifierHostServices.remove(name); - emit StatusNotifierHostUnregistered(); + Q_EMIT StatusNotifierHostUnregistered(); } } -void SniDaemon::RegisterStatusNotifierItem(const QString &serviceOrPath) +void SniDaemon::RegisterStatusNotifierItem(const QString &service) { - QString service; + QString realService; QString path; - if (serviceOrPath.startsWith(QLatin1Char('/'))) { - service = message().service(); - path = serviceOrPath; + int slash = service.indexOf('/'); + if (slash == 0) { + realService = message().service(); + path = service; + } else if (slash > 0){ + realService = service.left(slash); + path = service.mid(slash); } else { - service = serviceOrPath; + realService = service; path = QStringLiteral("/StatusNotifierItem"); } - QString notifierItemId = service + path; + QString notifierItemId = realService + path; if (m_registeredServices.contains(notifierItemId)) { return; } - m_serviceWatcher->addWatchedService(service); - if (QDBusConnection::sessionBus().interface()->isServiceRegistered(service).value()) { - //check if the service has registered a SystemTray object - org::kde::StatusNotifierItem trayclient(service, path, QDBusConnection::sessionBus()); - if (trayclient.isValid()) { + if (QDBusConnection::sessionBus().interface()->isServiceRegistered(realService).value()) { + org::kde::StatusNotifierItem item(realService, path, QDBusConnection::sessionBus()); + if (item.isValid()) { qDebug() << "Registering" << notifierItemId << "to system tray"; - m_registeredServices.append(notifierItemId); - emit StatusNotifierItemRegistered(notifierItemId); - } else { - m_serviceWatcher->removeWatchedService(service); + m_serviceWatcher->addWatchedService(service); + QString pid = "0"; + if (realService.contains(QStringLiteral("org.ukui.proxy.StatusNotifierItem"))) { + QString pidStr = realService.section("-", 1, 1); + if (!pidStr.isEmpty()) { + pid = pidStr; + } + } else { + QDBusReply pidReply = connection().interface()->servicePid(message().service()); + if (pidReply.isValid()) { + pid = QString::number(pidReply.value()); + } + } + m_registeredServices.insert(notifierItemId, pid); + Q_EMIT StatusNotifierItemRegistered(notifierItemId); + if (pid.toUInt() > 0) { + Q_EMIT StatusNotifierItemRegistered(pid.toUInt()); + } } - } else { - m_serviceWatcher->removeWatchedService(service); } } @@ -103,13 +115,25 @@ void SniDaemon::RegisterStatusNotifierHost(const QString &service) m_statusNotifierHostServices.insert(service); m_serviceWatcher->addWatchedService(service); - emit StatusNotifierHostRegistered(); + Q_EMIT StatusNotifierHostRegistered(); } } QStringList SniDaemon::RegisteredStatusNotifierItems() const { - return m_registeredServices; + return m_registeredServices.keys(); +} + +UintList SniDaemon::RegisteredStatusNotifierItemPids() const +{ + QStringList pidList = m_registeredServices.values(); + pidList.removeDuplicates(); + pidList.removeAll("0"); + UintList pids; + for (const QString &pid : pidList) { + pids.append(pid.toInt()); + } + return pids; } bool SniDaemon::IsStatusNotifierHostRegistered() const diff --git a/sni-daemon/snidaemon.h b/sni-daemon/snidaemon.h index cc1f3fc..3b69f65 100644 --- a/sni-daemon/snidaemon.h +++ b/sni-daemon/snidaemon.h @@ -20,14 +20,21 @@ #define SNIDAEMON_H #include +#include #include #include +#include + +typedef QList UintList; +Q_DECLARE_METATYPE(UintList) + class SniDaemon : public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.StatusNotifierWatcher") Q_PROPERTY(QStringList RegisteredStatusNotifierItems READ RegisteredStatusNotifierItems) + Q_PROPERTY(UintList RegisteredStatusNotifierItemPids READ RegisteredStatusNotifierItemPids) Q_PROPERTY(bool IsStatusNotifierHostRegistered READ IsStatusNotifierHostRegistered) Q_PROPERTY(int ProtocolVersion READ ProtocolVersion) public: @@ -35,7 +42,7 @@ public: ~SniDaemon(); QStringList RegisteredStatusNotifierItems() const; - + UintList RegisteredStatusNotifierItemPids() const; bool IsStatusNotifierHostRegistered() const; int ProtocolVersion() const; @@ -46,7 +53,8 @@ public Q_SLOTS: private: QDBusServiceWatcher *m_serviceWatcher = nullptr; - QStringList m_registeredServices; +// QStringList m_registeredServices; + QMultiMap m_registeredServices; QSet m_statusNotifierHostServices; Q_SIGNALS: @@ -54,6 +62,8 @@ Q_SIGNALS: void StatusNotifierItemUnregistered(const QString &service); void StatusNotifierHostRegistered(); void StatusNotifierHostUnregistered(); + void StatusNotifierItemRegistered(quint32 pid); + void StatusNotifierItemUnregistered(quint32 pid); protected Q_SLOTS: void serviceUnregistered(const QString& name); diff --git a/sni-xembed-proxy/sniproxy.cpp b/sni-xembed-proxy/sniproxy.cpp index e12d0a9..6e8edaf 100755 --- a/sni-xembed-proxy/sniproxy.cpp +++ b/sni-xembed-proxy/sniproxy.cpp @@ -100,13 +100,24 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent): qDBusRegisterMetaType(); qRegisterMetaType("KDbusImageVector"); qDBusRegisterMetaType(); - + uint pid = getPid(m_windowId); + QString serviceName; + if(pid > 0) { + uint count = 0; + if(m_pidToProxyCount.contains(pid)) { + count = m_pidToProxyCount.value(pid) + 1; + m_pidToProxyCount.insert(pid, count); + } else { + m_pidToProxyCount.insert(pid, 1); + } + serviceName = QStringLiteral("org.ukui.proxy.StatusNotifierItem-") + QString::number(pid) + QStringLiteral("-") + QString::number(count); + m_dbus.registerService(serviceName); + } m_dbus.registerObject(QStringLiteral("/StatusNotifierItem"), this,QDBusConnection::ExportAllContents); - auto statusNotifierWatcher = new org::kde::StatusNotifierWatcher(QStringLiteral(SNI_WATCHER_SERVICE_NAME), QStringLiteral(SNI_WATCHER_PATH), QDBusConnection::sessionBus(), this); qDebug()<<"sni-proxy:RegisterStatusNotifierItem = " <RegisterStatusNotifierItem(m_dbus.baseService()); + auto reply = statusNotifierWatcher->RegisterStatusNotifierItem(serviceName.isEmpty()? m_dbus.baseService() : serviceName); reply.waitForFinished(); if (reply.isError()) { qWarning() << "could not register SNI:" << reply.error().message(); @@ -673,3 +684,17 @@ void SNIProxy::sendClick(uint8_t mouseButton, int x, int y) sendingClickEvent = false; } + +uint SNIProxy::getPid(const xcb_window_t windowId) +{ + xcb_intern_atom_cookie_t cookie1 = xcb_intern_atom(QX11Info::connection(), false, 11, "_NET_WM_PID"); + xcb_intern_atom_reply_t *reply1 = xcb_intern_atom_reply(QX11Info::connection(), cookie1, nullptr); + m_pidAtom = reply1->atom; + free(reply1); + xcb_get_property_cookie_t cookie2 = xcb_get_property(QX11Info::connection(), false, windowId, m_pidAtom, XCB_ATOM_CARDINAL, 0, 1); + xcb_get_property_reply_t *reply2 = xcb_get_property_reply(QX11Info::connection(), cookie2, nullptr); + uint pid = 0; + pid = *(uint *)xcb_get_property_value(reply2); + free(reply2); + return pid; +} diff --git a/sni-xembed-proxy/sniproxy.h b/sni-xembed-proxy/sniproxy.h index f26dfd3..3bf7d0e 100755 --- a/sni-xembed-proxy/sniproxy.h +++ b/sni-xembed-proxy/sniproxy.h @@ -159,6 +159,8 @@ private: void stackContainerWindow(const uint32_t stackMode) const; QString winidtoDesktopFileName(const WId& wid) const; + uint getPid(const xcb_window_t windowId); + QDBusConnection m_dbus; xcb_window_t m_windowId; xcb_window_t m_containerWid; @@ -166,6 +168,8 @@ private: QPixmap m_pixmap; bool sendingClickEvent; InjectMode m_injectMode; + xcb_atom_t m_pidAtom; + QMap m_pidToProxyCount; }; #endif // SNIPROXY_H