托盘 sniWatcher 增加查询pid接口,合并ukui-sni方案

This commit is contained in:
cxc 2024-01-24 14:26:07 +08:00 committed by 卜萧庆
parent 45c643d87b
commit 3a3f70f27c
4 changed files with 99 additions and 36 deletions

View File

@ -20,6 +20,7 @@
#include "statusnotifieritem_interface.h"
SniDaemon::SniDaemon()
{
qDBusRegisterMetaType<UintList>();
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()<<m_registeredServices;
while (it != m_registeredServices.end()) {
if (it->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<uint> 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

View File

@ -20,14 +20,21 @@
#define SNIDAEMON_H
#include <QtDBus/QtDBus>
#include <QMetaType>
#include <QStringList>
#include <QDBusAbstractInterface>
#include <QList>
typedef QList<quint32> 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<QString, QString> m_registeredServices;
QSet<QString> 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);

View File

@ -100,13 +100,24 @@ SNIProxy::SNIProxy(xcb_window_t wid, QObject* parent):
qDBusRegisterMetaType<KDbusImageStruct>();
qRegisterMetaType<KDbusImageVector>("KDbusImageVector");
qDBusRegisterMetaType<KDbusImageVector>();
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 = " <<m_dbus.baseService();
auto reply = statusNotifierWatcher->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;
}

View File

@ -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<uint, uint> m_pidToProxyCount;
};
#endif // SNIPROXY_H