diff --git a/src/core/output.h b/src/core/output.h index 7e9af5833f..220435c556 100644 --- a/src/core/output.h +++ b/src/core/output.h @@ -29,6 +29,13 @@ class RenderLoop; class OutputConfiguration; class ColorTransformation; +enum class ContentType { + None = 0, + Photo = 1, + Video = 2, + Game = 3, +}; + class KWIN_EXPORT OutputMode { public: diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt index 2c8e618bb5..6299a6c4b8 100644 --- a/src/wayland/CMakeLists.txt +++ b/src/wayland/CMakeLists.txt @@ -189,6 +189,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml BASENAME xwayland-keyboard-grab-unstable-v1 ) +ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml + PROTOCOL ${WaylandProtocols_DATADIR}/staging/content-type/content-type-v1.xml + BASENAME content-type-v1 +) target_sources(kwin PRIVATE abstract_data_source.cpp @@ -199,6 +203,7 @@ target_sources(kwin PRIVATE clientbufferintegration.cpp clientconnection.cpp compositor_interface.cpp + contenttype_v1_interface.cpp contrast_interface.cpp datacontroldevice_v1_interface.cpp datacontroldevicemanager_v1_interface.cpp diff --git a/src/wayland/contenttype_v1_interface.cpp b/src/wayland/contenttype_v1_interface.cpp new file mode 100644 index 0000000000..68d7c35d20 --- /dev/null +++ b/src/wayland/contenttype_v1_interface.cpp @@ -0,0 +1,84 @@ +/* + SPDX-FileCopyrightText: 2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#include "contenttype_v1_interface.h" + +#include "display.h" +#include "surface_interface_p.h" + +namespace KWaylandServer +{ + +static constexpr uint32_t s_version = 1; + +static KWin::ContentType waylandToKwinContentType(uint32_t type) +{ + using Type = QtWaylandServer::wp_content_type_v1::type; + switch (type) { + case Type::type_photo: + return KWin::ContentType::Photo; + case Type::type_video: + return KWin::ContentType::Video; + case Type::type_game: + return KWin::ContentType::Game; + default: + return KWin::ContentType::None; + } +} + +ContentTypeManagerV1Interface::ContentTypeManagerV1Interface(Display *display, QObject *parent) + : QObject(parent) + , QtWaylandServer::wp_content_type_manager_v1(*display, s_version) +{ +} + +void ContentTypeManagerV1Interface::wp_content_type_manager_v1_destroy(Resource *resource) +{ + wl_resource_destroy(resource->handle); +} + +void ContentTypeManagerV1Interface::wp_content_type_manager_v1_get_surface_content_type(Resource *resource, uint32_t id, struct ::wl_resource *wlSurface) +{ + SurfaceInterface *surface = SurfaceInterface::get(wlSurface); + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface); + if (surfacePrivate->contentTypeInterface) { + wl_resource_post_error(resource->handle, error_already_constructed, "Surface already has a wp_content_type_v1"); + return; + } + surfacePrivate->contentTypeInterface = new ContentTypeV1Interface(surface, resource->client(), id); +} + +ContentTypeV1Interface::ContentTypeV1Interface(SurfaceInterface *surface, wl_client *client, uint32_t id) + : QtWaylandServer::wp_content_type_v1(client, id, s_version) + , m_surface(surface) +{ +} + +void ContentTypeV1Interface::wp_content_type_v1_set_content_type(Resource *, uint32_t content_type) +{ + if (!m_surface) { + return; + } + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); + surfacePrivate->pending.contentType = waylandToKwinContentType(content_type); + surfacePrivate->pending.contentTypeIsSet = true; +} + +void ContentTypeV1Interface::wp_content_type_v1_destroy(Resource *resource) +{ + if (m_surface) { + SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(m_surface); + surfacePrivate->pending.contentType = KWin::ContentType::None; + surfacePrivate->pending.contentTypeIsSet = true; + } + wl_resource_destroy(resource->handle); +} + +void ContentTypeV1Interface::wp_content_type_v1_destroy_resource(Resource *) +{ + delete this; +} + +} diff --git a/src/wayland/contenttype_v1_interface.h b/src/wayland/contenttype_v1_interface.h new file mode 100644 index 0000000000..dd51ea979e --- /dev/null +++ b/src/wayland/contenttype_v1_interface.h @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2022 Xaver Hugl + + SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL +*/ +#pragma once + +#include "surface_interface.h" + +#include "qwayland-server-content-type-v1.h" + +namespace KWaylandServer +{ + +class ContentTypeV1Interface; +class Display; + +class ContentTypeManagerV1Interface : public QObject, private QtWaylandServer::wp_content_type_manager_v1 +{ +public: + ContentTypeManagerV1Interface(Display *display, QObject *parent = nullptr); + +private: + void wp_content_type_manager_v1_destroy(QtWaylandServer::wp_content_type_manager_v1::Resource *resource) override; + void wp_content_type_manager_v1_get_surface_content_type(Resource *resource, uint32_t id, struct ::wl_resource *surface) override; +}; + +class ContentTypeV1Interface : public QObject, private QtWaylandServer::wp_content_type_v1 +{ + Q_OBJECT +public: + ContentTypeV1Interface(SurfaceInterface *surface, wl_client *client, uint32_t id); + +private: + void wp_content_type_v1_set_content_type(QtWaylandServer::wp_content_type_v1::Resource *resource, uint32_t content_type) override; + void wp_content_type_v1_destroy(QtWaylandServer::wp_content_type_v1::Resource *resource) override; + void wp_content_type_v1_destroy_resource(QtWaylandServer::wp_content_type_v1::Resource *resource) override; + + const QPointer m_surface; +}; + +} diff --git a/src/wayland/surface_interface.cpp b/src/wayland/surface_interface.cpp index 4f7e334f2d..ef0ff6a1db 100644 --- a/src/wayland/surface_interface.cpp +++ b/src/wayland/surface_interface.cpp @@ -8,6 +8,7 @@ #include "clientbuffer.h" #include "clientconnection.h" #include "compositor_interface.h" +#include "contenttype_v1_interface.h" #include "display.h" #include "idleinhibit_v1_interface_p.h" #include "linuxdmabufv1clientbuffer.h" @@ -536,6 +537,10 @@ void SurfaceState::mergeInto(SurfaceState *target) target->bufferTransform = bufferTransform; target->bufferTransformIsSet = true; } + if (contentTypeIsSet) { + target->contentType = contentType; + target->contentTypeIsSet = true; + } *this = SurfaceState{}; below = target->below; @@ -1025,6 +1030,11 @@ LinuxDmaBufV1Feedback *SurfaceInterface::dmabufFeedbackV1() const return d->dmabufFeedbackV1.get(); } +KWin::ContentType SurfaceInterface::contentType() const +{ + return d->current.contentType; +} + QPointF SurfaceInterface::mapToBuffer(const QPointF &point) const { return d->surfaceToBufferMatrix.map(point); diff --git a/src/wayland/surface_interface.h b/src/wayland/surface_interface.h index c56a0411f3..01371d14fe 100644 --- a/src/wayland/surface_interface.h +++ b/src/wayland/surface_interface.h @@ -6,6 +6,7 @@ */ #pragma once +#include "core/output.h" #include "output_interface.h" #include @@ -306,6 +307,11 @@ public: */ LinuxDmaBufV1Feedback *dmabufFeedbackV1() const; + /** + * @returns the current content type of this surface + */ + KWin::ContentType contentType() const; + /** * @returns The SurfaceInterface for the @p native resource. */ diff --git a/src/wayland/surface_interface_p.h b/src/wayland/surface_interface_p.h index 722f0885d6..89fc555a2a 100644 --- a/src/wayland/surface_interface_p.h +++ b/src/wayland/surface_interface_p.h @@ -19,6 +19,7 @@ namespace KWaylandServer class IdleInhibitorV1Interface; class SurfaceRole; class ViewportInterface; +class ContentTypeV1Interface; struct SurfaceState { @@ -38,6 +39,7 @@ struct SurfaceState bool childrenChanged = false; bool bufferScaleIsSet = false; bool bufferTransformIsSet = false; + bool contentTypeIsSet = false; qint32 bufferScale = 1; KWin::Output::Transform bufferTransform = KWin::Output::Transform::Normal; wl_list frameCallbacks; @@ -47,6 +49,7 @@ struct SurfaceState QPointer blur; QPointer contrast; QPointer slide; + KWin::ContentType contentType = KWin::ContentType::None; // Subsurfaces are stored in two lists. The below list contains subsurfaces that // are below their parent surface; the above list contains subsurfaces that are @@ -134,6 +137,7 @@ public: QVector idleInhibitors; ViewportInterface *viewportExtension = nullptr; std::unique_ptr dmabufFeedbackV1; + QPointer contentTypeInterface; ClientConnection *client = nullptr; protected: diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp index 326343dc40..c1cb89792d 100644 --- a/src/wayland_server.cpp +++ b/src/wayland_server.cpp @@ -25,6 +25,7 @@ #include "wayland/appmenu_interface.h" #include "wayland/blur_interface.h" #include "wayland/compositor_interface.h" +#include "wayland/contenttype_v1_interface.h" #include "wayland/datacontroldevicemanager_v1_interface.h" #include "wayland/datadevicemanager_interface.h" #include "wayland/datasource_interface.h" @@ -481,6 +482,8 @@ bool WaylandServer::init(InitializationFlags flags) w->setLockScreenOverlay(true); }); + m_contentTypeManager = new KWaylandServer::ContentTypeManagerV1Interface(m_display, m_display); + return true; } diff --git a/src/wayland_server.h b/src/wayland_server.h index d35867e32d..6d007e575b 100644 --- a/src/wayland_server.h +++ b/src/wayland_server.h @@ -49,6 +49,7 @@ class TabletManagerV2Interface; class KeyboardShortcutsInhibitManagerV1Interface; class XdgDecorationManagerV1Interface; class XWaylandKeyboardGrabManagerV1Interface; +class ContentTypeManagerV1Interface; } namespace KWin @@ -288,6 +289,7 @@ private: KWaylandServer::PrimaryOutputV1Interface *m_primary = nullptr; XdgActivationV1Integration *m_xdgActivationIntegration = nullptr; KWaylandServer::XWaylandKeyboardGrabManagerV1Interface *m_xWaylandKeyboardGrabManager = nullptr; + KWaylandServer::ContentTypeManagerV1Interface *m_contentTypeManager = nullptr; QList m_windows; InitializationFlags m_initFlags; QHash m_waylandOutputs;