File indexing completed on 2024-05-19 16:35:34

0001 /*
0002     SPDX-FileCopyrightText: 2022 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "xwaylandshell_v1_interface.h"
0008 
0009 #include "display.h"
0010 #include "surfacerole_p.h"
0011 #include "surface_interface.h"
0012 
0013 #include "qwayland-server-xwayland-shell-v1.h"
0014 
0015 namespace KWaylandServer
0016 {
0017 
0018 static const quint32 s_version = 1;
0019 
0020 class XwaylandShellV1InterfacePrivate : public QtWaylandServer::xwayland_shell_v1
0021 {
0022 public:
0023     XwaylandShellV1InterfacePrivate(Display *display, XwaylandShellV1Interface *q);
0024 
0025     XwaylandShellV1Interface *q;
0026     QList<XwaylandSurfaceV1Interface *> m_surfaces;
0027 
0028 protected:
0029     void xwayland_shell_v1_destroy(Resource *resource) override;
0030     void xwayland_shell_v1_get_xwayland_surface(Resource *resource, uint32_t id, struct ::wl_resource *surface) override;
0031 };
0032 
0033 struct XwaylandSurfaceV1State
0034 {
0035     std::optional<uint64_t> serial;
0036 };
0037 
0038 class XwaylandSurfaceV1InterfacePrivate : public SurfaceRole, public QtWaylandServer::xwayland_surface_v1
0039 {
0040 public:
0041     XwaylandSurfaceV1InterfacePrivate(XwaylandShellV1Interface *shell, SurfaceInterface *surface, wl_client *client, uint32_t id, int version, XwaylandSurfaceV1Interface *q);
0042 
0043     void commit() override;
0044 
0045     XwaylandSurfaceV1Interface *q;
0046     XwaylandShellV1Interface *shell;
0047 
0048     XwaylandSurfaceV1State current;
0049     XwaylandSurfaceV1State pending;
0050 
0051 protected:
0052     void xwayland_surface_v1_destroy_resource(Resource *resource) override;
0053     void xwayland_surface_v1_set_serial(Resource *resource, uint32_t serial_lo, uint32_t serial_hi) override;
0054     void xwayland_surface_v1_destroy(Resource *resource) override;
0055 };
0056 
0057 XwaylandShellV1InterfacePrivate::XwaylandShellV1InterfacePrivate(Display *display, XwaylandShellV1Interface *q)
0058     : QtWaylandServer::xwayland_shell_v1(*display, s_version)
0059     , q(q)
0060 {
0061 }
0062 
0063 void XwaylandShellV1InterfacePrivate::xwayland_shell_v1_destroy(Resource *resource)
0064 {
0065     wl_resource_destroy(resource->handle);
0066 }
0067 
0068 void XwaylandShellV1InterfacePrivate::xwayland_shell_v1_get_xwayland_surface(Resource *resource, uint32_t id, ::wl_resource *surface_resource)
0069 {
0070     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
0071     if (auto role = SurfaceRole::get(surface)) {
0072         wl_resource_post_error(resource->handle, error_role, "the surface already has a role assigned %s", role->name().constData());
0073         return;
0074     }
0075 
0076     auto xwaylandSurface = new XwaylandSurfaceV1Interface(q, surface, resource->client(), id, resource->version());
0077     m_surfaces.append(xwaylandSurface);
0078     QObject::connect(xwaylandSurface, &QObject::destroyed, q, [this, xwaylandSurface]() {
0079         m_surfaces.removeOne(xwaylandSurface);
0080     });
0081 }
0082 
0083 XwaylandSurfaceV1InterfacePrivate::XwaylandSurfaceV1InterfacePrivate(XwaylandShellV1Interface *shell, SurfaceInterface *surface, wl_client *client, uint32_t id, int version, XwaylandSurfaceV1Interface *q)
0084     : SurfaceRole(surface, QByteArrayLiteral("xwayland_surface_v1"))
0085     , QtWaylandServer::xwayland_surface_v1(client, id, version)
0086     , q(q)
0087     , shell(shell)
0088 {
0089 }
0090 
0091 void XwaylandSurfaceV1InterfacePrivate::commit()
0092 {
0093     if (pending.serial.has_value()) {
0094         current.serial = std::exchange(pending.serial, std::nullopt);
0095         Q_EMIT shell->surfaceAssociated(q);
0096     }
0097 }
0098 
0099 void XwaylandSurfaceV1InterfacePrivate::xwayland_surface_v1_destroy_resource(Resource *resource)
0100 {
0101     delete q;
0102 }
0103 
0104 void XwaylandSurfaceV1InterfacePrivate::xwayland_surface_v1_set_serial(Resource *resource, uint32_t serial_lo, uint32_t serial_hi)
0105 {
0106     const uint64_t serial = (uint64_t(serial_hi) << 32) | serial_lo;
0107     if (!serial) {
0108         wl_resource_post_error(resource->handle, error_invalid_serial, "given serial is 0");
0109         return;
0110     }
0111 
0112     if (current.serial.has_value()) {
0113         wl_resource_post_error(resource->handle, error_already_associated,
0114                                "xwayland_surface_v1 already has a serial assigned to it: %" PRIu64, current.serial.value());
0115         return;
0116     }
0117 
0118     pending.serial = serial;
0119 }
0120 
0121 void XwaylandSurfaceV1InterfacePrivate::xwayland_surface_v1_destroy(Resource *resource)
0122 {
0123     wl_resource_destroy(resource->handle);
0124 }
0125 
0126 XwaylandShellV1Interface::XwaylandShellV1Interface(Display *display, QObject *parent)
0127     : QObject(parent)
0128     , d(new XwaylandShellV1InterfacePrivate(display, this))
0129 {
0130 }
0131 
0132 XwaylandShellV1Interface::~XwaylandShellV1Interface()
0133 {
0134 }
0135 
0136 XwaylandSurfaceV1Interface *XwaylandShellV1Interface::findSurface(uint64_t serial) const
0137 {
0138     for (XwaylandSurfaceV1Interface *surface : std::as_const(d->m_surfaces)) {
0139         if (surface->serial() == serial) {
0140             return surface;
0141         }
0142     }
0143     return nullptr;
0144 }
0145 
0146 XwaylandSurfaceV1Interface::XwaylandSurfaceV1Interface(XwaylandShellV1Interface *shell, SurfaceInterface *surface, wl_client *client, uint32_t id, int version)
0147     : d(new XwaylandSurfaceV1InterfacePrivate(shell, surface, client, id, version, this))
0148 {
0149 }
0150 
0151 XwaylandSurfaceV1Interface::~XwaylandSurfaceV1Interface()
0152 {
0153 }
0154 
0155 SurfaceInterface *XwaylandSurfaceV1Interface::surface() const
0156 {
0157     return d->surface();
0158 }
0159 
0160 std::optional<uint64_t> XwaylandSurfaceV1Interface::serial() const
0161 {
0162     return d->current.serial;
0163 }
0164 
0165 } // namespace KWaylandServer