diff --git a/dbusinterface.cpp b/dbusinterface.cpp index 89d3d1f5c..31c82c987 100644 --- a/dbusinterface.cpp +++ b/dbusinterface.cpp @@ -1,544 +1,544 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ // own #include "dbusinterface.h" #include "compositingadaptor.h" #include "virtualdesktopmanageradaptor.h" // kwin #include "abstract_client.h" #include "atoms.h" #include "composite.h" #include "debug_console.h" #include "main.h" #include "placement.h" #include "platform.h" #include "kwinadaptor.h" #include "scene.h" #include "workspace.h" #include "virtualdesktops.h" #ifdef KWIN_BUILD_ACTIVITIES #include "activities.h" #endif // Qt #include #include // Marshall the DBusDesktopDataStruct data into a D-BUS argument const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataStruct &desk) { argument.beginStructure(); - argument << desk.x11DesktopNumber; + argument << desk.position; argument << desk.id; argument << desk.name; argument.endStructure(); return argument; } // Retrieve const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataStruct &desk) { argument.beginStructure(); - argument >> desk.x11DesktopNumber; + argument >> desk.position; argument >> desk.id; argument >> desk.name; argument.endStructure(); return argument; } const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataVector &deskVector) { argument.beginArray(qMetaTypeId()); for (int i = 0; i < deskVector.size(); ++i) { argument << deskVector[i]; } argument.endArray(); return argument; } const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataVector &deskVector) { argument.beginArray(); deskVector.clear(); while (!argument.atEnd()) { KWin::DBusDesktopDataStruct element; argument >> element; deskVector.append(element); } argument.endArray(); return argument; } namespace KWin { DBusInterface::DBusInterface(QObject *parent) : QObject(parent) , m_serviceName(QStringLiteral("org.kde.KWin")) { (void) new KWinAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/KWin"), this); const QByteArray dBusSuffix = qgetenv("KWIN_DBUS_SERVICE_SUFFIX"); if (!dBusSuffix.isNull()) { m_serviceName = m_serviceName + QLatin1Char('.') + dBusSuffix; } if (!dbus.registerService(m_serviceName)) { QDBusServiceWatcher *dog = new QDBusServiceWatcher(m_serviceName, dbus, QDBusServiceWatcher::WatchForUnregistration, this); connect (dog, SIGNAL(serviceUnregistered(QString)), SLOT(becomeKWinService(QString))); } else { announceService(); } dbus.connect(QString(), QStringLiteral("/KWin"), QStringLiteral("org.kde.KWin"), QStringLiteral("reloadConfig"), Workspace::self(), SLOT(slotReloadConfig())); connect(kwinApp(), &Application::x11ConnectionChanged, this, &DBusInterface::announceService); } void DBusInterface::becomeKWinService(const QString &service) { // TODO: this watchdog exists to make really safe that we at some point get the service // but it's probably no longer needed since we explicitly unregister the service with the deconstructor if (service == m_serviceName && QDBusConnection::sessionBus().registerService(m_serviceName) && sender()) { sender()->deleteLater(); // bye doggy :'( announceService(); } } DBusInterface::~DBusInterface() { QDBusConnection::sessionBus().unregisterService(m_serviceName); // KApplication automatically also grabs org.kde.kwin, so it's often been used externally - ensure to free it as well QDBusConnection::sessionBus().unregisterService(QStringLiteral("org.kde.kwin")); if (kwinApp()->x11Connection()) { xcb_delete_property(kwinApp()->x11Connection(), kwinApp()->x11RootWindow(), atoms->kwin_dbus_service); } } void DBusInterface::announceService() { if (!kwinApp()->x11Connection()) { return; } const QByteArray service = m_serviceName.toUtf8(); xcb_change_property(kwinApp()->x11Connection(), XCB_PROP_MODE_REPLACE, kwinApp()->x11RootWindow(), atoms->kwin_dbus_service, atoms->utf8_string, 8, service.size(), service.constData()); } // wrap void methods with no arguments to Workspace #define WRAP(name) \ void DBusInterface::name() \ {\ Workspace::self()->name();\ } WRAP(reconfigure) #undef WRAP void DBusInterface::killWindow() { Workspace::self()->slotKillWindow(); } #define WRAP(name) \ void DBusInterface::name() \ {\ Placement::self()->name();\ } WRAP(cascadeDesktop) WRAP(unclutterDesktop) #undef WRAP // wrap returning methods with no arguments to Workspace #define WRAP( rettype, name ) \ rettype DBusInterface::name( ) \ {\ return Workspace::self()->name(); \ } WRAP(QString, supportInformation) #undef WRAP bool DBusInterface::startActivity(const QString &in0) { #ifdef KWIN_BUILD_ACTIVITIES if (!Activities::self()) { return false; } return Activities::self()->start(in0); #else Q_UNUSED(in0) return false; #endif } bool DBusInterface::stopActivity(const QString &in0) { #ifdef KWIN_BUILD_ACTIVITIES if (!Activities::self()) { return false; } return Activities::self()->stop(in0); #else Q_UNUSED(in0) return false; #endif } int DBusInterface::currentDesktop() { return VirtualDesktopManager::self()->current(); } bool DBusInterface::setCurrentDesktop(int desktop) { return VirtualDesktopManager::self()->setCurrent(desktop); } void DBusInterface::nextDesktop() { VirtualDesktopManager::self()->moveTo(); } void DBusInterface::previousDesktop() { VirtualDesktopManager::self()->moveTo(); } void DBusInterface::showDebugConsole() { DebugConsole *console = new DebugConsole; console->show(); } QVariantMap DBusInterface::queryWindowInfo() { m_replyQueryWindowInfo = message(); setDelayedReply(true); kwinApp()->platform()->startInteractiveWindowSelection( [this] (Toplevel *t) { if (auto c = qobject_cast(t)) { const QVariantMap ret{ {QStringLiteral("resourceClass"), c->resourceClass()}, {QStringLiteral("resourceName"), c->resourceName()}, {QStringLiteral("desktopFile"), c->desktopFileName()}, {QStringLiteral("role"), c->windowRole()}, {QStringLiteral("caption"), c->captionNormal()}, {QStringLiteral("clientMachine"), c->wmClientMachine(true)}, {QStringLiteral("type"), c->windowType()}, {QStringLiteral("x"), c->x()}, {QStringLiteral("y"), c->y()}, {QStringLiteral("width"), c->width()}, {QStringLiteral("height"), c->height()}, {QStringLiteral("x11DesktopNumber"), c->desktop()}, {QStringLiteral("minimized"), c->isMinimized()}, {QStringLiteral("shaded"), c->isShade()}, {QStringLiteral("fullscreen"), c->isFullScreen()}, {QStringLiteral("keepAbove"), c->keepAbove()}, {QStringLiteral("keepBelow"), c->keepBelow()}, {QStringLiteral("noBorder"), c->noBorder()}, {QStringLiteral("skipTaskbar"), c->skipTaskbar()}, {QStringLiteral("skipPager"), c->skipPager()}, {QStringLiteral("skipSwitcher"), c->skipSwitcher()}, {QStringLiteral("maximizeHorizontal"), c->maximizeMode() & MaximizeHorizontal}, {QStringLiteral("maximizeVertical"), c->maximizeMode() & MaximizeVertical} }; QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createReply(ret)); } else { QDBusConnection::sessionBus().send(m_replyQueryWindowInfo.createErrorReply(QString(), QString())); } } ); return QVariantMap{}; } CompositorDBusInterface::CompositorDBusInterface(Compositor *parent) : QObject(parent) , m_compositor(parent) { connect(m_compositor, &Compositor::compositingToggled, this, &CompositorDBusInterface::compositingToggled); new CompositingAdaptor(this); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/Compositor"), this); dbus.connect(QString(), QStringLiteral("/Compositor"), QStringLiteral("org.kde.kwin.Compositing"), QStringLiteral("reinit"), m_compositor, SLOT(slotReinitialize())); } QString CompositorDBusInterface::compositingNotPossibleReason() const { return kwinApp()->platform()->compositingNotPossibleReason(); } QString CompositorDBusInterface::compositingType() const { if (!m_compositor->hasScene()) { return QStringLiteral("none"); } switch (m_compositor->scene()->compositingType()) { case XRenderCompositing: return QStringLiteral("xrender"); case OpenGL2Compositing: if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { return QStringLiteral("gles"); } else { return QStringLiteral("gl2"); } case QPainterCompositing: return QStringLiteral("qpainter"); case NoCompositing: default: return QStringLiteral("none"); } } bool CompositorDBusInterface::isActive() const { return m_compositor->isActive(); } bool CompositorDBusInterface::isCompositingPossible() const { return kwinApp()->platform()->compositingPossible(); } bool CompositorDBusInterface::isOpenGLBroken() const { return kwinApp()->platform()->openGLCompositingIsBroken(); } bool CompositorDBusInterface::platformRequiresCompositing() const { return kwinApp()->platform()->requiresCompositing(); } void CompositorDBusInterface::resume() { m_compositor->resume(Compositor::ScriptSuspend); } void CompositorDBusInterface::suspend() { m_compositor->suspend(Compositor::ScriptSuspend); } QStringList CompositorDBusInterface::supportedOpenGLPlatformInterfaces() const { QStringList interfaces; bool supportsGlx = false; #if HAVE_EPOXY_GLX supportsGlx = (kwinApp()->operationMode() == Application::OperationModeX11); #endif if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { supportsGlx = false; } if (supportsGlx) { interfaces << QStringLiteral("glx"); } interfaces << QStringLiteral("egl"); return interfaces; } VirtualDesktopManagerDBusInterface::VirtualDesktopManagerDBusInterface(VirtualDesktopManager *parent) : QObject(parent) , m_manager(parent) { qDBusRegisterMetaType(); qDBusRegisterMetaType(); new VirtualDesktopManagerAdaptor(this); QDBusConnection::sessionBus().registerObject(QStringLiteral("/VirtualDesktopManager"), QStringLiteral("org.kde.KWin.VirtualDesktopManager"), this ); connect(m_manager, &VirtualDesktopManager::currentChanged, this, [this](uint previousDesktop, uint newDesktop) { Q_UNUSED(previousDesktop); Q_UNUSED(newDesktop); emit currentChanged(m_manager->currentDesktop()->id()); } ); connect(m_manager, &VirtualDesktopManager::countChanged, this, [this](uint previousCount, uint newCount) { Q_UNUSED(previousCount); emit countChanged(newCount); emit desktopsChanged(desktops()); } ); connect(m_manager, &VirtualDesktopManager::navigationWrappingAroundChanged, this, [this]() { emit navigationWrappingAroundChanged(isNavigationWrappingAround()); } ); connect(m_manager, &VirtualDesktopManager::rowsChanged, this, &VirtualDesktopManagerDBusInterface::rowsChanged); for (auto *vd : m_manager->desktops()) { connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this, [this, vd]() { - DBusDesktopDataStruct data{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; emit desktopDataChanged(vd->id(), data); emit desktopsChanged(desktops()); } ); connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() { - DBusDesktopDataStruct data{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; emit desktopDataChanged(vd->id(), data); emit desktopsChanged(desktops()); } ); } connect(m_manager, &VirtualDesktopManager::desktopCreated, this, [this](VirtualDesktop *vd) { connect(vd, &VirtualDesktop::x11DesktopNumberChanged, this, [this, vd]() { - DBusDesktopDataStruct data{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; emit desktopDataChanged(vd->id(), data); emit desktopsChanged(desktops()); } ); connect(vd, &VirtualDesktop::nameChanged, this, [this, vd]() { - DBusDesktopDataStruct data{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; emit desktopDataChanged(vd->id(), data); emit desktopsChanged(desktops()); } ); - DBusDesktopDataStruct data{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + DBusDesktopDataStruct data{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; emit desktopCreated(vd->id(), data); emit desktopsChanged(desktops()); } ); connect(m_manager, &VirtualDesktopManager::desktopRemoved, this, [this](VirtualDesktop *vd) { emit desktopRemoved(vd->id()); emit desktopsChanged(desktops()); } ); } uint VirtualDesktopManagerDBusInterface::count() const { return m_manager->count(); } void VirtualDesktopManagerDBusInterface::setRows(uint rows) { if (static_cast(m_manager->grid().height()) == rows) { return; } m_manager->setRows(rows); m_manager->save(); } uint VirtualDesktopManagerDBusInterface::rows() const { return m_manager->rows(); } void VirtualDesktopManagerDBusInterface::setCurrent(const QString &id) { if (m_manager->currentDesktop()->id() == id) { return; } auto *vd = m_manager->desktopForId(id.toUtf8()); if (vd) { m_manager->setCurrent(vd); } } QString VirtualDesktopManagerDBusInterface::current() const { return m_manager->currentDesktop()->id(); } void VirtualDesktopManagerDBusInterface::setNavigationWrappingAround(bool wraps) { if (m_manager->isNavigationWrappingAround() == wraps) { return; } m_manager->setNavigationWrappingAround(wraps); } bool VirtualDesktopManagerDBusInterface::isNavigationWrappingAround() const { return m_manager->isNavigationWrappingAround(); } DBusDesktopDataVector VirtualDesktopManagerDBusInterface::desktops() const { const auto desks = m_manager->desktops(); DBusDesktopDataVector desktopVect; desktopVect.reserve(m_manager->count()); std::transform(desks.constBegin(), desks.constEnd(), std::back_inserter(desktopVect), [] (const VirtualDesktop *vd) { - return DBusDesktopDataStruct{.x11DesktopNumber = vd->x11DesktopNumber(), .id = vd->id(), .name = vd->name()}; + return DBusDesktopDataStruct{.position = vd->x11DesktopNumber() - 1, .id = vd->id(), .name = vd->name()}; } ); return desktopVect; } void VirtualDesktopManagerDBusInterface::createDesktop(uint position, const QString &name) { m_manager->createVirtualDesktop(position, name); } void VirtualDesktopManagerDBusInterface::setDesktopName(const QString &id, const QString &name) { VirtualDesktop *vd = m_manager->desktopForId(id.toUtf8()); if (!vd) { return; } if (vd->name() == name) { return; } vd->setName(name); m_manager->save(); } void VirtualDesktopManagerDBusInterface::removeDesktop(const QString &id) { m_manager->removeVirtualDesktop(id.toUtf8()); } } // namespace diff --git a/dbusinterface.h b/dbusinterface.h index 8d40df814..0e5ec39ed 100644 --- a/dbusinterface.h +++ b/dbusinterface.h @@ -1,262 +1,262 @@ /******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 Martin Gräßlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ #ifndef KWIN_DBUS_INTERFACE_H #define KWIN_DBUS_INTERFACE_H #include #include namespace KWin { class Compositor; class VirtualDesktopManager; /** * @brief This class is a wrapper for the org.kde.KWin D-Bus interface. * * The main purpose of this class is to be exported on the D-Bus as object /KWin. * It is a pure wrapper to provide the deprecated D-Bus methods which have been * removed from Workspace which used to implement the complete D-Bus interface. * * Nowadays the D-Bus interfaces are distributed, parts of it are exported on * /Compositor, parts on /Effects and parts on /KWin. The implementation in this * class just delegates the method calls to the actual implementation in one of the * three singletons. * * @author Martin Gräßlin **/ class DBusInterface: public QObject, protected QDBusContext { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin") public: explicit DBusInterface(QObject *parent); virtual ~DBusInterface(); public: // PROPERTIES public Q_SLOTS: // METHODS Q_NOREPLY void cascadeDesktop(); int currentDesktop(); Q_NOREPLY void killWindow(); void nextDesktop(); void previousDesktop(); Q_NOREPLY void reconfigure(); bool setCurrentDesktop(int desktop); bool startActivity(const QString &in0); bool stopActivity(const QString &in0); QString supportInformation(); Q_NOREPLY void unclutterDesktop(); Q_NOREPLY void showDebugConsole(); QVariantMap queryWindowInfo(); private Q_SLOTS: void becomeKWinService(const QString &service); private: void announceService(); QString m_serviceName; QDBusMessage m_replyQueryWindowInfo; }; class CompositorDBusInterface : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.kwin.Compositing") /** * @brief Whether the Compositor is active. That is a Scene is present and the Compositor is * not shutting down itself. **/ Q_PROPERTY(bool active READ isActive) /** * @brief Whether compositing is possible. Mostly means whether the required X extensions * are available. **/ Q_PROPERTY(bool compositingPossible READ isCompositingPossible) /** * @brief The reason why compositing is not possible. Empty String if compositing is possible. **/ Q_PROPERTY(QString compositingNotPossibleReason READ compositingNotPossibleReason) /** * @brief Whether OpenGL has failed badly in the past (crash) and is considered as broken. **/ Q_PROPERTY(bool openGLIsBroken READ isOpenGLBroken) /** * The type of the currently used Scene: * @li @c none No Compositing * @li @c xrender XRender * @li @c gl1 OpenGL 1 * @li @c gl2 OpenGL 2 * @li @c gles OpenGL ES 2 **/ Q_PROPERTY(QString compositingType READ compositingType) /** * @brief All currently supported OpenGLPlatformInterfaces. * * Possible values: * @li glx * @li egl * * Values depend on operation mode and compile time options. **/ Q_PROPERTY(QStringList supportedOpenGLPlatformInterfaces READ supportedOpenGLPlatformInterfaces) Q_PROPERTY(bool platformRequiresCompositing READ platformRequiresCompositing) public: explicit CompositorDBusInterface(Compositor *parent); virtual ~CompositorDBusInterface() = default; bool isActive() const; bool isCompositingPossible() const; QString compositingNotPossibleReason() const; bool isOpenGLBroken() const; QString compositingType() const; QStringList supportedOpenGLPlatformInterfaces() const; bool platformRequiresCompositing() const; public Q_SLOTS: /** * @brief Suspends the Compositor if it is currently active. * * Note: it is possible that the Compositor is not able to suspend. Use @link isActive to check * whether the Compositor has been suspended. * * @return void * @see resume * @see isActive **/ void suspend(); /** * @brief Resumes the Compositor if it is currently suspended. * * Note: it is possible that the Compositor cannot be resumed, that is there might be Clients * blocking the usage of Compositing or the Scene might be broken. Use @link isActive to check * whether the Compositor has been resumed. Also check @link isCompositingPossible and * @link isOpenGLBroken. * * Note: The starting of the Compositor can require some time and is partially done threaded. * After this method returns the setup may not have been completed. * * @return void * @see suspend * @see isActive * @see isCompositingPossible * @see isOpenGLBroken **/ void resume(); Q_SIGNALS: void compositingToggled(bool active); private: Compositor *m_compositor; }; //TODO: disable all of this in case of kiosk? struct DBusDesktopDataStruct { - uint x11DesktopNumber; + uint position; QString id; QString name; }; typedef QVector DBusDesktopDataVector; class VirtualDesktopManagerDBusInterface : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KWin.VirtualDesktopManager") /** * The number of virtual desktops currently available. * The ids of the virtual desktops are in the range [1, VirtualDesktopManager::maximum()]. **/ Q_PROPERTY(uint count READ count NOTIFY countChanged) /** * The number of rows the virtual desktops will be laid out in **/ Q_PROPERTY(uint rows READ rows WRITE setRows NOTIFY rowsChanged) /** * The id of the virtual desktop which is currently in use. **/ Q_PROPERTY(QString current READ current WRITE setCurrent NOTIFY currentChanged) /** * Whether navigation in the desktop layout wraps around at the borders. **/ Q_PROPERTY(bool navigationWrappingAround READ isNavigationWrappingAround WRITE setNavigationWrappingAround NOTIFY navigationWrappingAroundChanged) /** * list of key/value pairs which every one of them is representing a desktop */ Q_PROPERTY(KWin::DBusDesktopDataVector desktops READ desktops NOTIFY desktopsChanged); public: VirtualDesktopManagerDBusInterface(VirtualDesktopManager *parent); ~VirtualDesktopManagerDBusInterface() = default; uint count() const; void setRows(uint rows); uint rows() const; void setCurrent(const QString &id); QString current() const; void setNavigationWrappingAround(bool wraps); bool isNavigationWrappingAround() const; KWin::DBusDesktopDataVector desktops() const; Q_SIGNALS: void countChanged(uint count); void rowsChanged(uint rows); void currentChanged(const QString &id); void navigationWrappingAroundChanged(bool wraps); void desktopsChanged(KWin::DBusDesktopDataVector); void desktopDataChanged(const QString &id, KWin::DBusDesktopDataStruct); void desktopCreated(const QString &id, KWin::DBusDesktopDataStruct); void desktopRemoved(const QString &id); public Q_SLOTS: /** * Create a desktop with a new name at a given position * note: the position starts from 1 */ void createDesktop(uint position, const QString &name); void setDesktopName(const QString &id, const QString &name); void removeDesktop(const QString &id); private: VirtualDesktopManager *m_manager; }; } // namespace const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataStruct &desk); const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataStruct &desk); Q_DECLARE_METATYPE(KWin::DBusDesktopDataStruct) const QDBusArgument &operator<<(QDBusArgument &argument, const KWin::DBusDesktopDataVector &deskVector); const QDBusArgument &operator>>(const QDBusArgument &argument, KWin::DBusDesktopDataVector &deskVector); Q_DECLARE_METATYPE(KWin::DBusDesktopDataVector) #endif // KWIN_DBUS_INTERFACE_H