File indexing completed on 2024-04-28 05:30:14

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 // own
0011 #include "dbusinterface.h"
0012 #include "compositingadaptor.h"
0013 #include "pluginsadaptor.h"
0014 #include "virtualdesktopmanageradaptor.h"
0015 
0016 // kwin
0017 #include "compositor.h"
0018 #include "core/output.h"
0019 #include "core/renderbackend.h"
0020 #include "debug_console.h"
0021 #include "kwinadaptor.h"
0022 #include "main.h"
0023 #include "placement.h"
0024 #include "pluginmanager.h"
0025 #include "virtualdesktops.h"
0026 #include "window.h"
0027 #include "workspace.h"
0028 #if KWIN_BUILD_ACTIVITIES
0029 #include "activities.h"
0030 #endif
0031 
0032 // Qt
0033 #include <QDBusConnection>
0034 #include <QOpenGLContext>
0035 
0036 namespace KWin
0037 {
0038 
0039 DBusInterface::DBusInterface(QObject *parent)
0040     : QObject(parent)
0041     , m_serviceName(QStringLiteral("org.kde.KWin"))
0042 {
0043     (void)new KWinAdaptor(this);
0044 
0045     QDBusConnection dbus = QDBusConnection::sessionBus();
0046     dbus.registerObject(QStringLiteral("/KWin"), this);
0047     dbus.registerService(m_serviceName);
0048     dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"),
0049                  Workspace::self(), SLOT(slotReloadConfig()));
0050 
0051     connect(Workspace::self(), &Workspace::showingDesktopChanged, this, &DBusInterface::onShowingDesktopChanged);
0052 }
0053 
0054 DBusInterface::~DBusInterface()
0055 {
0056     QDBusConnection::sessionBus().unregisterService(m_serviceName);
0057 }
0058 
0059 bool DBusInterface::showingDesktop() const
0060 {
0061     return workspace()->showingDesktop();
0062 }
0063 
0064 void DBusInterface::reconfigure()
0065 {
0066     Workspace::self()->reconfigure();
0067 }
0068 
0069 void DBusInterface::killWindow()
0070 {
0071     Workspace::self()->slotKillWindow();
0072 }
0073 
0074 void DBusInterface::cascadeDesktop()
0075 {
0076     workspace()->placement()->cascadeDesktop();
0077 }
0078 
0079 void DBusInterface::unclutterDesktop()
0080 {
0081     workspace()->placement()->unclutterDesktop();
0082 }
0083 
0084 QString DBusInterface::supportInformation()
0085 {
0086     return Workspace::self()->supportInformation();
0087 }
0088 
0089 QString DBusInterface::activeOutputName()
0090 {
0091     return Workspace::self()->activeOutput()->name();
0092 }
0093 
0094 bool DBusInterface::startActivity(const QString &in0)
0095 {
0096 #if KWIN_BUILD_ACTIVITIES
0097     if (!Workspace::self()->activities()) {
0098         return false;
0099     }
0100     return Workspace::self()->activities()->start(in0);
0101 #else
0102     return false;
0103 #endif
0104 }
0105 
0106 bool DBusInterface::stopActivity(const QString &in0)
0107 {
0108 #if KWIN_BUILD_ACTIVITIES
0109     if (!Workspace::self()->activities()) {
0110         return false;
0111     }
0112     return Workspace::self()->activities()->stop(in0);
0113 #else
0114     return false;
0115 #endif
0116 }
0117 
0118 int DBusInterface::currentDesktop()
0119 {
0120     return VirtualDesktopManager::self()->current();
0121 }
0122 
0123 bool DBusInterface::setCurrentDesktop(int desktop)
0124 {
0125     return VirtualDesktopManager::self()->setCurrent(desktop);
0126 }
0127 
0128 void DBusInterface::nextDesktop()
0129 {
0130     VirtualDesktopManager::self()->moveTo(VirtualDesktopManager::Direction::Next);
0131 }
0132 
0133 void DBusInterface::previousDesktop()
0134 {
0135     VirtualDesktopManager::self()->moveTo(VirtualDesktopManager::Direction::Previous);
0136 }
0137 
0138 void DBusInterface::showDebugConsole()
0139 {
0140     DebugConsole *console = new DebugConsole;
0141     console->show();
0142 }
0143 
0144 void DBusInterface::replace()
0145 {
0146     QCoreApplication::exit(133);
0147 }
0148 
0149 namespace
0150 {
0151 QVariantMap clientToVariantMap(const Window *c)
0152 {
0153     return
0154     {
0155         {QStringLiteral("resourceClass"), c->resourceClass()},
0156             {QStringLiteral("resourceName"), c->resourceName()},
0157             {QStringLiteral("desktopFile"), c->desktopFileName()},
0158             {QStringLiteral("role"), c->windowRole()},
0159             {QStringLiteral("caption"), c->captionNormal()},
0160             {QStringLiteral("clientMachine"), c->wmClientMachine(true)},
0161             {QStringLiteral("localhost"), c->isLocalhost()},
0162             {QStringLiteral("type"), c->windowType()},
0163             {QStringLiteral("x"), c->x()},
0164             {QStringLiteral("y"), c->y()},
0165             {QStringLiteral("width"), c->width()},
0166             {QStringLiteral("height"), c->height()},
0167             {QStringLiteral("desktops"), c->desktopIds()},
0168             {QStringLiteral("minimized"), c->isMinimized()},
0169             {QStringLiteral("shaded"), c->isShade()},
0170             {QStringLiteral("fullscreen"), c->isFullScreen()},
0171             {QStringLiteral("keepAbove"), c->keepAbove()},
0172             {QStringLiteral("keepBelow"), c->keepBelow()},
0173             {QStringLiteral("noBorder"), c->noBorder()},
0174             {QStringLiteral("skipTaskbar"), c->skipTaskbar()},
0175             {QStringLiteral("skipPager"), c->skipPager()},
0176             {QStringLiteral("skipSwitcher"), c->skipSwitcher()},
0177             {QStringLiteral("maximizeHorizontal"), c->maximizeMode() & MaximizeHorizontal},
0178             {QStringLiteral("maximizeVertical"), c->maximizeMode() & MaximizeVertical},
0179             {QStringLiteral("uuid"), c->internalId().toString()},
0180 #if KWIN_BUILD_ACTIVITIES
0181             {QStringLiteral("activities"), c->activities()},
0182 #endif
0183             {QStringLiteral("layer"), c->layer()},
0184     };
0185 }
0186 }
0187 
0188 QVariantMap DBusInterface::queryWindowInfo()
0189 {
0190     m_replyQueryWindowInfo = message();
0191     setDelayedReply(true);
0192     kwinApp()->startInteractiveWindowSelection(
0193         [this](Window *t) {
0194             if (!t) {
0195                 QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createErrorReply(
0196                     QStringLiteral("org.kde.KWin.Error.UserCancel"),
0197                     QStringLiteral("User cancelled the query")));
0198                 return;
0199             }
0200             if (t->isClient()) {
0201                 QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createReply(clientToVariantMap(t)));
0202             } else {
0203                 QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createErrorReply(
0204                     QStringLiteral("org.kde.KWin.Error.InvalidWindow"),
0205                     QStringLiteral("Tried to query information about an unmanaged window")));
0206             }
0207         });
0208     return QVariantMap{};
0209 }
0210 
0211 QVariantMap DBusInterface::getWindowInfo(const QString &uuid)
0212 {
0213     const auto window = workspace()->findWindow(QUuid::fromString(uuid));
0214     if (window) {
0215         return clientToVariantMap(window);
0216     } else {
0217         return {};
0218     }
0219 }
0220 
0221 void DBusInterface::showDesktop(bool show)
0222 {
0223     workspace()->setShowingDesktop(show, true);
0224 
0225     auto m = message();
0226     if (m.service().isEmpty()) {
0227         return;
0228     }
0229 
0230     // Keep track of whatever D-Bus client asked to show the desktop. If
0231     // they disappear from the bus, cancel the show desktop state so we do
0232     // not end up in a state where we are stuck showing the desktop.
0233     static QPointer<QDBusServiceWatcher> watcher;
0234 
0235     if (show) {
0236         if (watcher) {
0237             // If we get a second call to `showDesktop(true)`, drop the previous
0238             // watcher and watch the new client. That way, we simply always
0239             // track the last state.
0240             watcher->deleteLater();
0241         }
0242 
0243         watcher = new QDBusServiceWatcher(m.service(), QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration, this);
0244         connect(watcher, &QDBusServiceWatcher::serviceUnregistered, []() {
0245             workspace()->setShowingDesktop(false, true);
0246             watcher->deleteLater();
0247         });
0248     } else if (watcher) {
0249         // Someone cancelled showing the desktop, so there's no more need to
0250         // watch to cancel the show desktop state.
0251         watcher->deleteLater();
0252     }
0253 }
0254 
0255 void DBusInterface::onShowingDesktopChanged(bool show, bool /*animated*/)
0256 {
0257     Q_EMIT showingDesktopChanged(show);
0258 }
0259 
0260 CompositorDBusInterface::CompositorDBusInterface(Compositor *parent)
0261     : QObject(parent)
0262     , m_compositor(parent)
0263 {
0264     connect(m_compositor, &Compositor::compositingToggled, this, &CompositorDBusInterface::compositingToggled);
0265     new CompositingAdaptor(this);
0266     QDBusConnection dbus = QDBusConnection::sessionBus();
0267     dbus.registerObject(QStringLiteral("/Compositor"), this);
0268     dbus.connect(QString(), QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"),
0269                  QStringLiteral("reinit"), this, SLOT(reinitialize()));
0270 }
0271 
0272 QString CompositorDBusInterface::compositingType() const
0273 {
0274     if (!m_compositor->compositing()) {
0275         return QStringLiteral("none");
0276     }
0277     switch (m_compositor->backend()->compositingType()) {
0278     case OpenGLCompositing:
0279         if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
0280             return QStringLiteral("gles");
0281         } else {
0282             return QStringLiteral("gl2");
0283         }
0284     case QPainterCompositing:
0285         return QStringLiteral("qpainter");
0286     case NoCompositing:
0287     default:
0288         return QStringLiteral("none");
0289     }
0290 }
0291 
0292 bool CompositorDBusInterface::isActive() const
0293 {
0294     return m_compositor->isActive();
0295 }
0296 
0297 bool CompositorDBusInterface::isCompositingPossible() const
0298 {
0299     return m_compositor->compositingPossible();
0300 }
0301 
0302 QString CompositorDBusInterface::compositingNotPossibleReason() const
0303 {
0304     return m_compositor->compositingNotPossibleReason();
0305 }
0306 
0307 bool CompositorDBusInterface::isOpenGLBroken() const
0308 {
0309     return m_compositor->openGLCompositingIsBroken();
0310 }
0311 
0312 bool CompositorDBusInterface::platformRequiresCompositing() const
0313 {
0314     return kwinApp()->operationMode() != Application::OperationModeX11; // TODO: Remove this property?
0315 }
0316 
0317 void CompositorDBusInterface::reinitialize()
0318 {
0319     m_compositor->reinitialize();
0320 }
0321 
0322 QStringList CompositorDBusInterface::supportedOpenGLPlatformInterfaces() const
0323 {
0324     QStringList interfaces;
0325     bool supportsGlx = false;
0326 #if HAVE_GLX
0327     supportsGlx = (kwinApp()->operationMode() == Application::OperationModeX11);
0328 #endif
0329     if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
0330         supportsGlx = false;
0331     }
0332     if (supportsGlx) {
0333         interfaces << QStringLiteral("glx");
0334     }
0335     interfaces << QStringLiteral("egl");
0336     return interfaces;
0337 }
0338 
0339 VirtualDesktopManagerDBusInterface::VirtualDesktopManagerDBusInterface(VirtualDesktopManager *parent)
0340     : QObject(parent)
0341     , m_manager(parent)
0342 {
0343     qDBusRegisterMetaType<KWin::DBusDesktopDataStruct>();
0344     qDBusRegisterMetaType<KWin::DBusDesktopDataVector>();
0345 
0346     new VirtualDesktopManagerAdaptor(this);
0347     QDBusConnection::sessionBus().registerObject(QStringLiteral("/VirtualDesktopManager"),
0348                                                  QStringLiteral("org.kde.KWin.VirtualDesktopManager"),
0349                                                  this);
0350 
0351     connect(m_manager, &VirtualDesktopManager::currentChanged, this, [this]() {
0352         Q_EMIT currentChanged(m_manager->currentDesktop()->id());
0353     });
0354 
0355     connect(m_manager, &VirtualDesktopManager::countChanged, this, [this](uint previousCount, uint newCount) {
0356         Q_EMIT countChanged(newCount);
0357         Q_EMIT desktopsChanged(desktops());
0358     });
0359 
0360     connect(m_manager, &VirtualDesktopManager::navigationWrappingAroundChanged, this, [this]() {
0361         Q_EMIT navigationWrappingAroundChanged(isNavigationWrappingAround());
0362     });
0363 
0364     connect(m_manager, &VirtualDesktopManager::rowsChanged, this, &VirtualDesktopManagerDBusInterface::rowsChanged);
0365 
0366     const QList<VirtualDesktop *> allDesks = m_manager->desktops();
0367     for (auto *vd : allDesks) {
0368         connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this, [this, vd]() {
0369             DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0370             Q_EMIT desktopDataChanged(vd->id(), data);
0371             Q_EMIT desktopsChanged(desktops());
0372         });
0373         connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() {
0374             DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0375             Q_EMIT desktopDataChanged(vd->id(), data);
0376             Q_EMIT desktopsChanged(desktops());
0377         });
0378     }
0379     connect(m_manager, &VirtualDesktopManager::desktopAdded, this, [this](VirtualDesktop *vd) {
0380         connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this, [this, vd]() {
0381             DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0382             Q_EMIT desktopDataChanged(vd->id(), data);
0383             Q_EMIT desktopsChanged(desktops());
0384         });
0385         connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() {
0386             DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0387             Q_EMIT desktopDataChanged(vd->id(), data);
0388             Q_EMIT desktopsChanged(desktops());
0389         });
0390         DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0391         Q_EMIT desktopCreated(vd->id(), data);
0392         Q_EMIT desktopsChanged(desktops());
0393     });
0394     connect(m_manager, &VirtualDesktopManager::desktopRemoved, this, [this](VirtualDesktop *vd) {
0395         Q_EMIT desktopRemoved(vd->id());
0396         Q_EMIT desktopsChanged(desktops());
0397     });
0398 }
0399 
0400 uint VirtualDesktopManagerDBusInterface::count() const
0401 {
0402     return m_manager->count();
0403 }
0404 
0405 void VirtualDesktopManagerDBusInterface::setRows(uint rows)
0406 {
0407     if (static_cast<uint>(m_manager->grid().height()) == rows) {
0408         return;
0409     }
0410 
0411     m_manager->setRows(rows);
0412     m_manager->save();
0413 }
0414 
0415 uint VirtualDesktopManagerDBusInterface::rows() const
0416 {
0417     return m_manager->rows();
0418 }
0419 
0420 void VirtualDesktopManagerDBusInterface::setCurrent(const QString &id)
0421 {
0422     if (m_manager->currentDesktop()->id() == id) {
0423         return;
0424     }
0425 
0426     auto *vd = m_manager->desktopForId(id);
0427     if (vd) {
0428         m_manager->setCurrent(vd);
0429     }
0430 }
0431 
0432 QString VirtualDesktopManagerDBusInterface::current() const
0433 {
0434     return m_manager->currentDesktop()->id();
0435 }
0436 
0437 void VirtualDesktopManagerDBusInterface::setNavigationWrappingAround(bool wraps)
0438 {
0439     if (m_manager->isNavigationWrappingAround() == wraps) {
0440         return;
0441     }
0442 
0443     m_manager->setNavigationWrappingAround(wraps);
0444 }
0445 
0446 bool VirtualDesktopManagerDBusInterface::isNavigationWrappingAround() const
0447 {
0448     return m_manager->isNavigationWrappingAround();
0449 }
0450 
0451 DBusDesktopDataVector VirtualDesktopManagerDBusInterface::desktops() const
0452 {
0453     const auto desks = m_manager->desktops();
0454     DBusDesktopDataVector desktopVect;
0455     desktopVect.reserve(m_manager->count());
0456 
0457     std::transform(desks.constBegin(), desks.constEnd(),
0458                    std::back_inserter(desktopVect),
0459                    [](const VirtualDesktop *vd) {
0460                        return DBusDesktopDataStruct{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()};
0461                    });
0462 
0463     return desktopVect;
0464 }
0465 
0466 void VirtualDesktopManagerDBusInterface::createDesktop(uint position, const QString &name)
0467 {
0468     m_manager->createVirtualDesktop(position, name);
0469 }
0470 
0471 void VirtualDesktopManagerDBusInterface::setDesktopName(const QString &id, const QString &name)
0472 {
0473     VirtualDesktop *vd = m_manager->desktopForId(id);
0474     if (!vd) {
0475         return;
0476     }
0477     if (vd->name() == name) {
0478         return;
0479     }
0480 
0481     vd->setName(name);
0482     m_manager->save();
0483 }
0484 
0485 void VirtualDesktopManagerDBusInterface::removeDesktop(const QString &id)
0486 {
0487     m_manager->removeVirtualDesktop(id);
0488 }
0489 
0490 PluginManagerDBusInterface::PluginManagerDBusInterface(PluginManager *manager)
0491     : QObject(manager)
0492     , m_manager(manager)
0493 {
0494     new PluginsAdaptor(this);
0495 
0496     QDBusConnection::sessionBus().registerObject(QStringLiteral("/Plugins"),
0497                                                  QStringLiteral("org.kde.KWin.Plugins"),
0498                                                  this);
0499 }
0500 
0501 QStringList PluginManagerDBusInterface::loadedPlugins() const
0502 {
0503     return m_manager->loadedPlugins();
0504 }
0505 
0506 QStringList PluginManagerDBusInterface::availablePlugins() const
0507 {
0508     return m_manager->availablePlugins();
0509 }
0510 
0511 bool PluginManagerDBusInterface::LoadPlugin(const QString &name)
0512 {
0513     return m_manager->loadPlugin(name);
0514 }
0515 
0516 void PluginManagerDBusInterface::UnloadPlugin(const QString &name)
0517 {
0518     m_manager->unloadPlugin(name);
0519 }
0520 
0521 } // namespace
0522 
0523 #include "moc_dbusinterface.cpp"