diff --git a/backends/kwayland/CMakeLists.txt b/backends/kwayland/CMakeLists.txt --- a/backends/kwayland/CMakeLists.txt +++ b/backends/kwayland/CMakeLists.txt @@ -6,12 +6,14 @@ waylandscreen.cpp ../utils.cpp ) +qt5_add_dbus_interface(wayland_SRCS org.kde.KWin.TabletModeManager.xml tabletmodemanager_interface) add_library(KSC_KWayland MODULE ${wayland_SRCS}) set_target_properties(KSC_KWayland PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/kf5/kscreen") set_target_properties(KSC_KWayland PROPERTIES PREFIX "") target_link_libraries(KSC_KWayland Qt5::Core + Qt5::DBus Qt5::Gui KF5::Screen KF5::WaylandClient diff --git a/backends/kwayland/org.kde.KWin.TabletModeManager.xml b/backends/kwayland/org.kde.KWin.TabletModeManager.xml new file mode 100644 --- /dev/null +++ b/backends/kwayland/org.kde.KWin.TabletModeManager.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/backends/kwayland/waylandconfig.h b/backends/kwayland/waylandconfig.h --- a/backends/kwayland/waylandconfig.h +++ b/backends/kwayland/waylandconfig.h @@ -80,6 +80,7 @@ void checkInitialized(); void disconnected(); + void initKWinTabletMode(); void initConnection(); void addOutput(quint32 name, quint32 version); @@ -109,6 +110,9 @@ KScreen::ConfigPtr m_kscreenConfig; KScreen::ConfigPtr m_kscreenPendingConfig; WaylandScreen *m_screen; + + bool m_tabletModeAvailable; + bool m_tabletModeEngaged; }; } diff --git a/backends/kwayland/waylandconfig.cpp b/backends/kwayland/waylandconfig.cpp --- a/backends/kwayland/waylandconfig.cpp +++ b/backends/kwayland/waylandconfig.cpp @@ -22,6 +22,8 @@ #include "waylandoutput.h" #include "waylandscreen.h" +#include "tabletmodemanager_interface.h" + #include #include @@ -43,6 +45,8 @@ , m_kscreenConfig(new Config) , m_kscreenPendingConfig(nullptr) , m_screen(new WaylandScreen(this)) + , m_tabletModeAvailable(false) + , m_tabletModeEngaged(false) { connect(this, &WaylandConfig::initialized, &m_syncLoop, &QEventLoop::quit); @@ -56,6 +60,7 @@ } }); + initKWinTabletMode(); initConnection(); m_syncLoop.exec(); } @@ -67,6 +72,43 @@ m_syncLoop.quit(); } +void WaylandConfig::initKWinTabletMode() +{ + auto *interface = new OrgKdeKWinTabletModeManagerInterface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin"), + QDBusConnection::sessionBus(), this); + if (!interface->isValid()) { + m_tabletModeAvailable = false; + m_tabletModeEngaged = false; + return; + } + + m_tabletModeAvailable = interface->tabletModeAvailable(); + m_tabletModeEngaged = interface->tabletMode(); + + connect(interface, &OrgKdeKWinTabletModeManagerInterface::tabletModeChanged, + this, [this](bool tabletMode) { + if (m_tabletModeEngaged == tabletMode) { + return; + } + m_tabletModeEngaged = tabletMode; + if (!m_blockSignals && m_initializingOutputs.empty()) { + Q_EMIT configChanged(); + } + } + ); + connect(interface, &OrgKdeKWinTabletModeManagerInterface::tabletModeAvailableChanged, + this, [this](bool available) { + if (m_tabletModeAvailable == available) { + return; + } + m_tabletModeAvailable = available; + if (!m_blockSignals && m_initializingOutputs.empty()) { + Q_EMIT configChanged(); + } + }); +} + void WaylandConfig::initConnection() { m_thread = new QThread(this); @@ -227,6 +269,9 @@ m_kscreenConfig->setScreen(m_screen->toKScreenScreen(m_kscreenConfig)); auto features = Config::Feature::Writable | Config::Feature::PerOutputScaling; + // TODO: enable new features when all patches have landed +// const auto features = Config::Feature::Writable | Config::Feature::PerOutputScaling +// | Config::Feature::AutoRotation | Config::Feature::TabletMode; m_kscreenConfig->setSupportedFeatures(features); m_kscreenConfig->setValid(m_connection->display()); @@ -258,6 +303,9 @@ } m_kscreenConfig->setOutputs(kscreenOutputs); + m_kscreenConfig->setTabletModeAvailable(m_tabletModeAvailable); + m_kscreenConfig->setTabletModeEngaged(m_tabletModeEngaged); + return m_kscreenConfig; } diff --git a/src/config.h b/src/config.h --- a/src/config.h +++ b/src/config.h @@ -67,6 +67,8 @@ Writable = 1 << 1, ///< The backend supports setting the config, it's not read-only. PerOutputScaling = 1 << 2, ///< The backend supports scaling each output individually. OutputReplication = 1 << 3, ///< The backend supports replication of outputs. + AutoRotation = 1 << 4, ///< The backend supports automatic rotation of outputs. + TabletMode = 1 << 5, ///< The backend supports querying if a device is in tablet mode. }; Q_DECLARE_FLAGS(Features, Feature) @@ -165,6 +167,42 @@ */ void setSupportedFeatures(const Features &features); + /** + * Indicates that the device supports switching between a default and a tablet mode. This is + * common for convertibles. + * + * @return true when tablet mode is available, otherwise false + * @see setTabletModeAvailable + * @since 5.18 + */ + bool tabletModeAvailable() const; + + /** Sets if the device supports a tablet mode. This should not be called by the + * user, but by the backend. + * + * @see tabletModeAvailable + * @since 5.18 + */ + void setTabletModeAvailable(bool available); + + /** + * Indicates that the device is currently in tablet mode. + * + * @return true when in tablet mode, otherwise false + * @see setTabletModeEngaged + * @since 5.18 + */ + bool tabletModeEngaged() const; + + /** + * Sets if the device is currently in tablet mode. This should not be called by the + * user, but by the backend. + * + * @see tabletModeEngaged + * @since 5.18 + */ + void setTabletModeEngaged(bool engaged); + Q_SIGNALS: void outputAdded(const KScreen::OutputPtr &output); void outputRemoved(int outputId); diff --git a/src/config.cpp b/src/config.cpp --- a/src/config.cpp +++ b/src/config.cpp @@ -38,6 +38,8 @@ : QObject(parent) , valid(true) , supportedFeatures(Config::Feature::None) + , tabletModeAvailable(false) + , tabletModeEngaged(false) , q(parent) { } @@ -90,6 +92,8 @@ OutputPtr primaryOutput; OutputList outputs; Features supportedFeatures; + bool tabletModeAvailable; + bool tabletModeEngaged; private: Config *q; @@ -260,6 +264,26 @@ d->supportedFeatures = features; } +bool Config::tabletModeAvailable() const +{ + return d->tabletModeAvailable; +} + +void Config::setTabletModeAvailable(bool available) +{ + d->tabletModeAvailable = available; +} + +bool Config::tabletModeEngaged() const +{ + return d->tabletModeEngaged; +} + +void Config::setTabletModeEngaged(bool engaged) +{ + d->tabletModeEngaged = engaged; +} + OutputList Config::outputs() const { return d->outputs;