File indexing completed on 2024-02-18 16:19:52

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2011 Lionel Chauvin <megabigbug@yahoo.fr>
0006     SPDX-FileCopyrightText: 2011, 2012 Cédric Bellegarde <gnumdk@gmail.com>
0007     SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 #include "appmenu.h"
0012 #include "workspace.h"
0013 #include "x11window.h"
0014 #include <appmenu_interface.h>
0015 
0016 #include <QDBusObjectPath>
0017 #include <QDBusServiceWatcher>
0018 
0019 #include "decorations/decorationbridge.h"
0020 #include <KDecoration2/DecorationSettings>
0021 
0022 namespace KWin
0023 {
0024 
0025 static const QString s_viewService(QStringLiteral("org.kde.kappmenuview"));
0026 
0027 ApplicationMenu::ApplicationMenu()
0028     : m_appmenuInterface(new OrgKdeKappmenuInterface(QStringLiteral("org.kde.kappmenu"), QStringLiteral("/KAppMenu"), QDBusConnection::sessionBus(), this))
0029 {
0030     connect(m_appmenuInterface, &OrgKdeKappmenuInterface::showRequest, this, &ApplicationMenu::slotShowRequest);
0031     connect(m_appmenuInterface, &OrgKdeKappmenuInterface::menuShown, this, &ApplicationMenu::slotMenuShown);
0032     connect(m_appmenuInterface, &OrgKdeKappmenuInterface::menuHidden, this, &ApplicationMenu::slotMenuHidden);
0033 
0034     m_kappMenuWatcher = new QDBusServiceWatcher(QStringLiteral("org.kde.kappmenu"), QDBusConnection::sessionBus(),
0035                                                 QDBusServiceWatcher::WatchForRegistration | QDBusServiceWatcher::WatchForUnregistration, this);
0036 
0037     connect(m_kappMenuWatcher, &QDBusServiceWatcher::serviceRegistered, this, [this]() {
0038         m_applicationMenuEnabled = true;
0039         Q_EMIT applicationMenuEnabledChanged(true);
0040     });
0041     connect(m_kappMenuWatcher, &QDBusServiceWatcher::serviceUnregistered, this, [this]() {
0042         m_applicationMenuEnabled = false;
0043         Q_EMIT applicationMenuEnabledChanged(false);
0044     });
0045 
0046     m_applicationMenuEnabled = QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.kappmenu"));
0047 }
0048 
0049 bool ApplicationMenu::applicationMenuEnabled() const
0050 {
0051     return m_applicationMenuEnabled;
0052 }
0053 
0054 void ApplicationMenu::setViewEnabled(bool enabled)
0055 {
0056     if (enabled) {
0057         QDBusConnection::sessionBus().interface()->registerService(s_viewService,
0058                                                                    QDBusConnectionInterface::QueueService,
0059                                                                    QDBusConnectionInterface::DontAllowReplacement);
0060     } else {
0061         QDBusConnection::sessionBus().interface()->unregisterService(s_viewService);
0062     }
0063 }
0064 
0065 void ApplicationMenu::slotShowRequest(const QString &serviceName, const QDBusObjectPath &menuObjectPath, int actionId)
0066 {
0067     // Ignore show request when user has not configured the application menu title bar button
0068     auto decorationSettings = Workspace::self()->decorationBridge()->settings();
0069     if (decorationSettings && !decorationSettings->decorationButtonsLeft().contains(KDecoration2::DecorationButtonType::ApplicationMenu)
0070         && !decorationSettings->decorationButtonsRight().contains(KDecoration2::DecorationButtonType::ApplicationMenu)) {
0071         return;
0072     }
0073 
0074     if (Window *window = findWindowWithApplicationMenu(serviceName, menuObjectPath)) {
0075         window->showApplicationMenu(actionId);
0076     }
0077 }
0078 
0079 void ApplicationMenu::slotMenuShown(const QString &serviceName, const QDBusObjectPath &menuObjectPath)
0080 {
0081     if (Window *window = findWindowWithApplicationMenu(serviceName, menuObjectPath)) {
0082         window->setApplicationMenuActive(true);
0083     }
0084 }
0085 
0086 void ApplicationMenu::slotMenuHidden(const QString &serviceName, const QDBusObjectPath &menuObjectPath)
0087 {
0088     if (Window *window = findWindowWithApplicationMenu(serviceName, menuObjectPath)) {
0089         window->setApplicationMenuActive(false);
0090     }
0091 }
0092 
0093 void ApplicationMenu::showApplicationMenu(const QPoint &p, Window *c, int actionId)
0094 {
0095     if (!c->hasApplicationMenu()) {
0096         return;
0097     }
0098     m_appmenuInterface->showMenu(p.x(), p.y(), c->applicationMenuServiceName(), QDBusObjectPath(c->applicationMenuObjectPath()), actionId);
0099 }
0100 
0101 Window *ApplicationMenu::findWindowWithApplicationMenu(const QString &serviceName, const QDBusObjectPath &menuObjectPath)
0102 {
0103     if (serviceName.isEmpty() || menuObjectPath.path().isEmpty()) {
0104         return nullptr;
0105     }
0106 
0107     return Workspace::self()->findAbstractClient([&](const Window *window) {
0108         return window->applicationMenuServiceName() == serviceName
0109             && window->applicationMenuObjectPath() == menuObjectPath.path();
0110     });
0111 }
0112 
0113 } // namespace KWin