diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 25ecf2b6fc..bdbf688d06 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -7,6 +7,7 @@ set(SERVER_LIB_SRCS dataoffer_interface.cpp datasource_interface.cpp display.cpp + dpms_interface.cpp global.cpp idle_interface.cpp fakeinput_interface.cpp @@ -59,6 +60,10 @@ ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/shadow.xml BASENAME shadow ) +ecm_add_wayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/dpms.xml + BASENAME dpms +) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWAYLAND_SOURCE_DIR}/src/client/protocols/blur.xml @@ -120,6 +125,7 @@ install(FILES dataoffer_interface.h datasource_interface.h display.h + dpms_interface.h fakeinput_interface.h global.h idle_interface.h diff --git a/src/wayland/display.cpp b/src/wayland/display.cpp index c7cfa0ad2c..019991a6e7 100644 --- a/src/wayland/display.cpp +++ b/src/wayland/display.cpp @@ -20,6 +20,7 @@ License along with this library. If not, see . #include "display.h" #include "compositor_interface.h" #include "datadevicemanager_interface.h" +#include "dpms_interface.h" #include "idle_interface.h" #include "fakeinput_interface.h" #include "logging_p.h" @@ -295,6 +296,13 @@ SlideManagerInterface *Display::createSlideManager(QObject *parent) return b; } +DpmsManagerInterface *Display::createDpmsManager(QObject *parent) +{ + auto d = new DpmsManagerInterface(this, parent); + connect(this, &Display::aboutToTerminate, d, [this, d] { delete d; }); + return d; +} + void Display::createShm() { Q_ASSERT(d->display); diff --git a/src/wayland/display.h b/src/wayland/display.h index fc885a5dbf..677c0313c7 100644 --- a/src/wayland/display.h +++ b/src/wayland/display.h @@ -38,6 +38,7 @@ namespace Server class CompositorInterface; class DataDeviceManagerInterface; +class DpmsManagerInterface; class IdleInterface; class FakeInputInterface; class OutputInterface; @@ -137,6 +138,7 @@ public: BlurManagerInterface *createBlurManager(QObject *parent = nullptr); ContrastManagerInterface *createContrastManager(QObject *parent = nullptr); SlideManagerInterface *createSlideManager(QObject *parent = nullptr); + DpmsManagerInterface *createDpmsManager(QObject *parent = nullptr); /** * Gets the ClientConnection for the given @p client. diff --git a/src/wayland/dpms_interface.cpp b/src/wayland/dpms_interface.cpp new file mode 100644 index 0000000000..fa299f30f5 --- /dev/null +++ b/src/wayland/dpms_interface.cpp @@ -0,0 +1,184 @@ +/******************************************************************** +Copyright 2015 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#include "dpms_interface_p.h" +#include "display.h" +#include "output_interface.h" + +namespace KWayland +{ +namespace Server +{ + +static const quint32 s_version = 1; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct org_kde_kwin_dpms_manager_interface DpmsManagerInterface::Private::s_interface = { + getDpmsCallback +}; +#endif + +DpmsManagerInterface::Private::Private(DpmsManagerInterface *q, Display *d) + : Global::Private(d, &org_kde_kwin_dpms_manager_interface, s_version) + , q(q) +{ +} + +void DpmsManagerInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + wl_resource *dpms = c->createResource(&org_kde_kwin_dpms_manager_interface, qMin(version, s_version), id); + if (!dpms) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(dpms, &s_interface, this, nullptr); +} + +void DpmsManagerInterface::Private::getDpmsCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *output) +{ + auto p = Private::cast(resource); + auto c = p->display->getConnection(client); + OutputInterface *o = OutputInterface::get(output); + DpmsInterface *dpms = new DpmsInterface(o, resource, p->q); + dpms->create(c, wl_resource_get_version(resource), id); + if (!dpms->resource()) { + wl_resource_post_no_memory(resource); + return; + } + dpms->sendSupported(); + dpms->sendMode(); + dpms->sendDone(); +} + +DpmsManagerInterface::DpmsManagerInterface(Display *display, QObject *parent) + : Global(new Private(this, display), parent) +{ +} + +DpmsManagerInterface::~DpmsManagerInterface() = default; + + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct org_kde_kwin_dpms_interface DpmsInterface::Private::s_interface = { + setCallback, + releaseCallback +}; +#endif + +DpmsInterface::Private::Private(DpmsInterface *q, DpmsManagerInterface *g, wl_resource *parentResource, OutputInterface *output) + : Resource::Private(q, g, parentResource, &org_kde_kwin_dpms_interface, &s_interface) + , output(output) +{ +} + +void DpmsInterface::Private::setCallback(wl_client *client, wl_resource *resource, uint32_t mode) +{ + Q_UNUSED(client) + OutputInterface::DpmsMode dpmsMode; + switch (mode) { + case ORG_KDE_KWIN_DPMS_MODE_ON: + dpmsMode = OutputInterface::DpmsMode::On; + break; + case ORG_KDE_KWIN_DPMS_MODE_STANDBY: + dpmsMode = OutputInterface::DpmsMode::Standby; + break; + case ORG_KDE_KWIN_DPMS_MODE_SUSPEND: + dpmsMode = OutputInterface::DpmsMode::Suspend; + break; + case ORG_KDE_KWIN_DPMS_MODE_OFF: + dpmsMode = OutputInterface::DpmsMode::Off; + break; + default: + return; + } + emit cast(resource)->output->dpmsModeRequested(dpmsMode); +} + +void DpmsInterface::Private::releaseCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + Private *p = reinterpret_cast(wl_resource_get_user_data(resource)); + wl_resource_destroy(resource); + p->q->deleteLater(); +} + +DpmsInterface::DpmsInterface(OutputInterface *output, wl_resource *parentResource, DpmsManagerInterface *manager) + : Resource(new Private(this, manager, parentResource, output), manager) +{ + connect(output, &OutputInterface::dpmsSupportedChanged, this, + [this] { + sendSupported(); + sendDone(); + } + ); + connect(output, &OutputInterface::dpmsModeChanged, this, + [this] { + sendMode(); + sendDone(); + } + ); +} + +DpmsInterface::~DpmsInterface() = default; + +void DpmsInterface::sendSupported() +{ + Q_D(); + org_kde_kwin_dpms_send_supported(d->resource, d->output->isDpmsSupported() ? 1 : 0); +} + +void DpmsInterface::sendMode() +{ + Q_D(); + const auto mode = d->output->dpmsMode(); + org_kde_kwin_dpms_mode wlMode; + switch (mode) { + case OutputInterface::DpmsMode::On: + wlMode = ORG_KDE_KWIN_DPMS_MODE_ON; + break; + case OutputInterface::DpmsMode::Standby: + wlMode = ORG_KDE_KWIN_DPMS_MODE_STANDBY; + break; + case OutputInterface::DpmsMode::Suspend: + wlMode = ORG_KDE_KWIN_DPMS_MODE_SUSPEND; + break; + case OutputInterface::DpmsMode::Off: + wlMode = ORG_KDE_KWIN_DPMS_MODE_OFF; + break; + default: + Q_UNREACHABLE(); + } + org_kde_kwin_dpms_send_mode(d->resource, wlMode); +} + +void DpmsInterface::sendDone() +{ + Q_D(); + org_kde_kwin_dpms_send_done(d->resource); + client()->flush(); +} + +DpmsInterface::Private *DpmsInterface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +} +} diff --git a/src/wayland/dpms_interface.h b/src/wayland/dpms_interface.h new file mode 100644 index 0000000000..cb3045ea4a --- /dev/null +++ b/src/wayland/dpms_interface.h @@ -0,0 +1,81 @@ +/******************************************************************** +Copyright 2015 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#ifndef WAYLAND_SERVER_DPMS_INTERFACE_H +#define WAYLAND_SERVER_DPMS_INTERFACE_H + +#include + +#include +#include "global.h" + +namespace KWayland +{ +namespace Server +{ + +class Display; + +/** + * @brief Global for the org_kde_kwin_dpms_manager interface. + * + * If the DpmsManagerInterface is created it allows a client to + * query the Dpms state on a given OutputInterface and request + * changes for it. The code interaction happens only via the + * OutputInterface. + * + * To create a DpmsManagerInterface use: + * @code + * auto manager = display->createDpmsManager(); + * manager->create(); + * @endcode + * + * To interact with Dpms use one needs to mark it as enabled and set the + * proper mode on the OutputInterface. + * @code + * // We have our OutputInterface called output. + * output->setDpmsSupported(true); + * output->setDpmsMode(OutputInterface::DpmsMode::On); + * @endcode + * + * To connect to Dpms change requests use: + * @code + * connect(output, &OutputInterface::dpmsModeRequested, + * [] (KWayland::Server::OutputInterface::DpmsMode requestedMode) { qDebug() << "Mode change requested"; }); + * @endcode + * + * @see Display + * @see OutputInterface + **/ +class KWAYLANDSERVER_EXPORT DpmsManagerInterface : public Global +{ + Q_OBJECT +public: + virtual ~DpmsManagerInterface(); + +private: + explicit DpmsManagerInterface(Display *display, QObject *parent = nullptr); + friend class Display; + class Private; +}; + +} +} + +#endif diff --git a/src/wayland/dpms_interface_p.h b/src/wayland/dpms_interface_p.h new file mode 100644 index 0000000000..9e156b2816 --- /dev/null +++ b/src/wayland/dpms_interface_p.h @@ -0,0 +1,84 @@ +/******************************************************************** +Copyright 2015 Martin Gräßlin + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +*********************************************************************/ +#ifndef WAYLAND_SERVER_DPMS_INTERFACE_P_H +#define WAYLAND_SERVER_DPMS_INTERFACE_P_H + +#include "dpms_interface.h" +#include "global_p.h" +#include "resource_p.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class OutputInterface; + +class DpmsManagerInterface::Private : public Global::Private +{ +public: + Private(DpmsManagerInterface *q, Display *d); + +private: + static void getDpmsCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *output); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + void bind(wl_client *client, uint32_t version, uint32_t id) override; + + DpmsManagerInterface *q; + static const struct org_kde_kwin_dpms_manager_interface s_interface; +}; + +class DpmsInterface : public Resource +{ + Q_OBJECT +public: + explicit DpmsInterface(OutputInterface *output, wl_resource *parentResource, DpmsManagerInterface *manager); + virtual ~DpmsInterface(); + + void sendSupported(); + void sendMode(); + void sendDone(); + +private: + class Private; + Private *d_func() const; +}; + +class DpmsInterface::Private : public Resource::Private +{ +public: + explicit Private(DpmsInterface *q, DpmsManagerInterface *g, wl_resource *parentResource, OutputInterface *output); + + OutputInterface *output; + +private: + static void setCallback(wl_client *client, wl_resource *resource, uint32_t mode); + static void releaseCallback(wl_client *client, wl_resource *resource); + static const struct org_kde_kwin_dpms_interface s_interface; +}; + +} +} + +#endif diff --git a/src/wayland/output_interface.cpp b/src/wayland/output_interface.cpp index e295eb6ab7..707ceb17a6 100644 --- a/src/wayland/output_interface.cpp +++ b/src/wayland/output_interface.cpp @@ -55,6 +55,10 @@ public: Transform transform = Transform::Normal; QList modes; QList resources; + struct { + DpmsMode mode = DpmsMode::On; + bool supported = false; + } dpms; static OutputInterface *get(wl_resource *native); @@ -458,6 +462,38 @@ QList< OutputInterface::Mode > OutputInterface::modes() const return d->modes; } +void OutputInterface::setDpmsMode(OutputInterface::DpmsMode mode) +{ + Q_D(); + if (d->dpms.mode == mode) { + return; + } + d->dpms.mode = mode; + emit dpmsModeChanged(); +} + +void OutputInterface::setDpmsSupported(bool supported) +{ + Q_D(); + if (d->dpms.supported == supported) { + return; + } + d->dpms.supported = supported; + emit dpmsSupportedChanged(); +} + +OutputInterface::DpmsMode OutputInterface::dpmsMode() const +{ + Q_D(); + return d->dpms.mode; +} + +bool OutputInterface::isDpmsSupported() const +{ + Q_D(); + return d->dpms.supported; +} + OutputInterface *OutputInterface::get(wl_resource* native) { return Private::get(native); diff --git a/src/wayland/output_interface.h b/src/wayland/output_interface.h index 56a8845e4c..b40f2a9a53 100644 --- a/src/wayland/output_interface.h +++ b/src/wayland/output_interface.h @@ -77,6 +77,12 @@ public: int refreshRate = 60000; ModeFlags flags; }; + enum class DpmsMode { + On, + Standby, + Suspend, + Off + }; virtual ~OutputInterface(); QSize physicalSize() const; @@ -89,6 +95,8 @@ public: SubPixel subPixel() const; Transform transform() const; QList modes() const; + bool isDpmsSupported() const; + DpmsMode dpmsMode() const; void setPhysicalSize(const QSize &size); void setGlobalPosition(const QPoint &pos); @@ -100,6 +108,19 @@ public: void addMode(const QSize &size, ModeFlags flags = ModeFlags(), int refreshRate = 60000); void setCurrentMode(const QSize &size, int refreshRate = 60000); + /** + * Sets whether Dpms is supported for this output. + * Default is @c false. + * @since 5.5 + **/ + void setDpmsSupported(bool supported); + /** + * Sets the currently used dpms mode. + * Default is @c DpmsMode::On. + * @since 5.5 + **/ + void setDpmsMode(DpmsMode mode); + static OutputInterface *get(wl_resource *native); Q_SIGNALS: @@ -114,6 +135,15 @@ Q_SIGNALS: void transformChanged(Transform); void modesChanged(); void currentModeChanged(); + void dpmsModeChanged(); + void dpmsSupportedChanged(); + + /** + * Change of dpms @p mode is requested. + * A server is free to ignore this request. + * @since 5.5 + **/ + void dpmsModeRequested(KWayland::Server::OutputInterface::DpmsMode mode); private: friend class Display; @@ -128,5 +158,6 @@ private: Q_DECLARE_OPERATORS_FOR_FLAGS(KWayland::Server::OutputInterface::ModeFlags) Q_DECLARE_METATYPE(KWayland::Server::OutputInterface::SubPixel) Q_DECLARE_METATYPE(KWayland::Server::OutputInterface::Transform) +Q_DECLARE_METATYPE(KWayland::Server::OutputInterface::DpmsMode) #endif