File indexing completed on 2024-05-05 17:43:31

0001 /*
0002     SPDX-FileCopyrightText: 2011 Lionel Chauvin <megabigbug@yahoo.fr>
0003     SPDX-FileCopyrightText: 2011, 2012 Cédric Bellegarde <gnumdk@gmail.com>
0004     SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de>
0005 
0006     SPDX-License-Identifier: MIT
0007 */
0008 
0009 #include "menuimporter.h"
0010 #include "dbusmenutypes_p.h"
0011 #include "menuimporteradaptor.h"
0012 
0013 #include <QDBusMessage>
0014 #include <QDBusServiceWatcher>
0015 
0016 #include <KWindowInfo>
0017 #include <KWindowSystem>
0018 
0019 static const char *DBUS_SERVICE = "com.canonical.AppMenu.Registrar";
0020 static const char *DBUS_OBJECT_PATH = "/com/canonical/AppMenu/Registrar";
0021 
0022 MenuImporter::MenuImporter(QObject *parent)
0023     : QObject(parent)
0024     , m_serviceWatcher(new QDBusServiceWatcher(this))
0025 {
0026     qDBusRegisterMetaType<DBusMenuLayoutItem>();
0027     m_serviceWatcher->setConnection(QDBusConnection::sessionBus());
0028     m_serviceWatcher->setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
0029     connect(m_serviceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &MenuImporter::slotServiceUnregistered);
0030 }
0031 
0032 MenuImporter::~MenuImporter()
0033 {
0034     QDBusConnection::sessionBus().unregisterService(DBUS_SERVICE);
0035 }
0036 
0037 bool MenuImporter::connectToBus()
0038 {
0039     if (!QDBusConnection::sessionBus().registerService(DBUS_SERVICE)) {
0040         return false;
0041     }
0042     new MenuImporterAdaptor(this);
0043     QDBusConnection::sessionBus().registerObject(DBUS_OBJECT_PATH, this);
0044 
0045     return true;
0046 }
0047 
0048 void MenuImporter::RegisterWindow(WId id, const QDBusObjectPath &path)
0049 {
0050     KWindowInfo info(id, NET::WMWindowType, NET::WM2WindowClass);
0051     NET::WindowTypes mask = NET::AllTypesMask;
0052     auto type = info.windowType(mask);
0053 
0054     // Menu can try to register, right click in gimp for example
0055     if (type != NET::Unknown && (type & (NET::Menu | NET::DropdownMenu | NET::PopupMenu))) {
0056         return;
0057     }
0058 
0059     if (path.path().isEmpty()) // prevent bad dbusmenu usage
0060         return;
0061 
0062     QString service = message().service();
0063 
0064     QString classClass = info.windowClassClass();
0065     m_windowClasses.insert(id, classClass);
0066     m_menuServices.insert(id, service);
0067     m_menuPaths.insert(id, path);
0068 
0069     if (!m_serviceWatcher->watchedServices().contains(service)) {
0070         m_serviceWatcher->addWatchedService(service);
0071     }
0072 
0073     Q_EMIT WindowRegistered(id, service, path);
0074 }
0075 
0076 void MenuImporter::UnregisterWindow(WId id)
0077 {
0078     m_menuServices.remove(id);
0079     m_menuPaths.remove(id);
0080     m_windowClasses.remove(id);
0081 
0082     Q_EMIT WindowUnregistered(id);
0083 }
0084 
0085 QString MenuImporter::GetMenuForWindow(WId id, QDBusObjectPath &path)
0086 {
0087     path = m_menuPaths.value(id);
0088     return m_menuServices.value(id);
0089 }
0090 
0091 void MenuImporter::slotServiceUnregistered(const QString &service)
0092 {
0093     WId id = m_menuServices.key(service);
0094     m_menuServices.remove(id);
0095     m_menuPaths.remove(id);
0096     m_windowClasses.remove(id);
0097     Q_EMIT WindowUnregistered(id);
0098     m_serviceWatcher->removeWatchedService(service);
0099 }