File indexing completed on 2023-05-30 12:24:36
0001 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0002 // SPDX-FileCopyrightText: 2022-2023 Harald Sitter <sitter@kde.org> 0003 0004 #include <chrono> 0005 0006 #include <QDebug> 0007 #include <QGuiApplication> 0008 #include <QJsonDocument> 0009 #include <QJsonObject> 0010 #include <QTimer> 0011 0012 #include <KWayland/Client/connection_thread.h> 0013 #include <KWayland/Client/plasmawindowmanagement.h> 0014 #include <KWayland/Client/registry.h> 0015 0016 #include <KWindowInfo> 0017 #include <KWindowSystem> 0018 #include <KX11Extras> 0019 0020 using namespace std::chrono_literals; 0021 0022 class WaylandLister : public QObject 0023 { 0024 Q_OBJECT 0025 public: 0026 explicit WaylandLister(QObject *parent = nullptr) 0027 : QObject(parent) 0028 { 0029 m_connection.reset(KWayland::Client::ConnectionThread::fromApplication()); 0030 if (!m_connection) { 0031 qWarning() << "no connection"; 0032 return; 0033 } 0034 0035 m_registry.create(m_connection.get()); 0036 0037 QObject::connect(&m_registry, 0038 &KWayland::Client::Registry::plasmaWindowManagementAnnounced, 0039 this, 0040 [this](quint32 name, quint32 version) { 0041 m_windowManagement.reset(m_registry.createPlasmaWindowManagement(name, version)); 0042 }); 0043 0044 m_registry.setup(); 0045 0046 // We'll need 3 because getting the registry is async, getting the window management interface is another, 0047 // then we'll have requested information about every window. By the 3rd sync it should have sent everything. 0048 static constexpr auto syncTimes = 3; 0049 for (auto i = 0; i < syncTimes; i++) { 0050 QCoreApplication::processEvents(); 0051 m_connection->roundtrip(); 0052 QCoreApplication::processEvents(); 0053 } 0054 QCoreApplication::processEvents(); 0055 Q_ASSERT(m_windowManagement); 0056 const auto windows = m_windowManagement->windows(); 0057 for (const auto &window : windows) { 0058 insert(window); 0059 } 0060 } 0061 0062 void insert(KWayland::Client::PlasmaWindow *window) 0063 { 0064 m_pidsToAppIds.insert(QString::number(window->pid()), window->appId()); 0065 } 0066 0067 QVariantHash data() const 0068 { 0069 return m_pidsToAppIds; 0070 } 0071 0072 private: 0073 QVariantHash m_pidsToAppIds; 0074 std::unique_ptr<KWayland::Client::ConnectionThread> m_connection; 0075 KWayland::Client::Registry m_registry; 0076 std::unique_ptr<KWayland::Client::PlasmaWindowManagement> m_windowManagement; 0077 }; 0078 0079 QVariantHash waylandPidsToAppIds() 0080 { 0081 WaylandLister lister; 0082 return lister.data(); 0083 } 0084 0085 QVariantHash x11PidsToAppIds() 0086 { 0087 QVariantHash pidsToAppIds; 0088 const auto wids = KX11Extras::windows(); 0089 for (const auto &wid : wids) { 0090 const KWindowInfo info(wid, NET::WMPid, NET::WM2DesktopFileName | NET::WM2GTKApplicationId); 0091 if (!info.desktopFileName().isEmpty()) { 0092 pidsToAppIds.insert(QString::number(info.pid()), info.desktopFileName()); 0093 } 0094 if (!info.gtkApplicationId().isEmpty()) { 0095 pidsToAppIds.insert(QString::number(info.pid()), info.gtkApplicationId()); 0096 } 0097 } 0098 return pidsToAppIds; 0099 } 0100 0101 int main(int argc, char **argv) 0102 { 0103 const QGuiApplication app(argc, argv); 0104 0105 QVariantHash pidsToAppIds; 0106 0107 if (KWindowSystem::isPlatformX11()) { 0108 pidsToAppIds.insert(x11PidsToAppIds()); 0109 } else if (KWindowSystem::isPlatformWayland()) { 0110 pidsToAppIds.insert(waylandPidsToAppIds()); 0111 } else { 0112 qFatal("unsupported platform"); 0113 return 1; 0114 } 0115 0116 // Always append .desktop for convenience. Means we can do straight forward string matching in the python side. 0117 for (auto it = pidsToAppIds.begin(); it != pidsToAppIds.end(); ++it) { 0118 static const QLatin1String suffix(".desktop"); 0119 const QString value = it.value().toString(); 0120 if (!value.endsWith(suffix)) { 0121 it->setValue(QString(value + suffix)); 0122 } 0123 } 0124 0125 const QJsonDocument doc(QJsonObject::fromVariantHash(pidsToAppIds)); 0126 printf("%s\n", doc.toJson().constData()); 0127 return 0; 0128 } 0129 0130 #include "main.moc"