File indexing completed on 2024-05-19 05:32:47

0001 /*
0002     SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
0003     SPDX-FileCopyrightText: 2020 David Edmundson <kde@davidedmundson.co.uk>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 #include "xdgoutput_v1.h"
0008 #include "clientconnection.h"
0009 #include "display.h"
0010 #include "output.h"
0011 
0012 #include "qwayland-server-xdg-output-unstable-v1.h"
0013 
0014 #include "core/output.h"
0015 
0016 #include <QDebug>
0017 #include <QHash>
0018 #include <QPointer>
0019 #include <cmath>
0020 
0021 namespace KWin
0022 {
0023 static const quint32 s_version = 3;
0024 
0025 class XdgOutputV1Interface : public QObject, public QtWaylandServer::zxdg_output_v1
0026 {
0027 public:
0028     explicit XdgOutputV1Interface(OutputInterface *wlOutput);
0029 
0030     void resend();
0031     void update();
0032 
0033     QPointF pos;
0034     QSizeF size;
0035     QString name;
0036     QString description;
0037     QPointer<OutputInterface> output;
0038 
0039     void sendLogicalPosition(Resource *resource);
0040     void sendLogicalSize(Resource *resource);
0041     void sendDone(Resource *resource);
0042 
0043 protected:
0044     void zxdg_output_v1_bind_resource(Resource *resource) override;
0045     void zxdg_output_v1_destroy(Resource *resource) override;
0046 };
0047 
0048 class XdgOutputManagerV1InterfacePrivate : public QtWaylandServer::zxdg_output_manager_v1
0049 {
0050 public:
0051     explicit XdgOutputManagerV1InterfacePrivate(Display *display);
0052 
0053     QHash<OutputInterface *, XdgOutputV1Interface *> outputs;
0054 
0055 protected:
0056     void zxdg_output_manager_v1_destroy(Resource *resource) override;
0057     void zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, wl_resource *output) override;
0058 };
0059 
0060 XdgOutputManagerV1Interface::XdgOutputManagerV1Interface(Display *display, QObject *parent)
0061     : QObject(parent)
0062     , d(new XdgOutputManagerV1InterfacePrivate(display))
0063 {
0064 }
0065 
0066 XdgOutputManagerV1Interface::~XdgOutputManagerV1Interface()
0067 {
0068 }
0069 
0070 void XdgOutputManagerV1Interface::offer(OutputInterface *output)
0071 {
0072     Q_ASSERT_X(!d->outputs.contains(output), "offer", "An XdgOuputInterface already exists for this output");
0073 
0074     auto xdgOutput = new XdgOutputV1Interface(output);
0075     d->outputs[output] = xdgOutput;
0076     connect(output, &QObject::destroyed, this, [this, output]() {
0077         delete d->outputs.take(output);
0078     });
0079 }
0080 
0081 XdgOutputManagerV1InterfacePrivate::XdgOutputManagerV1InterfacePrivate(Display *d)
0082     : QtWaylandServer::zxdg_output_manager_v1(*d, s_version)
0083 {
0084 }
0085 
0086 void XdgOutputManagerV1InterfacePrivate::zxdg_output_manager_v1_get_xdg_output(Resource *resource, uint32_t id, wl_resource *outputResource)
0087 {
0088     auto output = OutputInterface::get(outputResource);
0089     if (!output) { // output client is requesting XdgOutput for an Output that doesn't exist
0090         return;
0091     }
0092     auto xdgOutput = outputs.value(output);
0093     if (!xdgOutput) {
0094         return; // client is requesting XdgOutput for an Output that doesn't exist
0095     }
0096     xdgOutput->add(resource->client(), id, resource->version());
0097 }
0098 
0099 void XdgOutputManagerV1InterfacePrivate::zxdg_output_manager_v1_destroy(Resource *resource)
0100 {
0101     wl_resource_destroy(resource->handle);
0102 }
0103 
0104 XdgOutputV1Interface::XdgOutputV1Interface(OutputInterface *output)
0105     : output(output)
0106 {
0107     const Output *handle = output->handle();
0108 
0109     name = handle->name();
0110     description = handle->description();
0111     pos = handle->geometryF().topLeft();
0112     size = handle->geometryF().size();
0113 
0114     connect(handle, &Output::geometryChanged, this, &XdgOutputV1Interface::update);
0115 }
0116 
0117 void XdgOutputV1Interface::update()
0118 {
0119     if (!output || output->isRemoved()) {
0120         return;
0121     }
0122 
0123     const QRectF geometry = output->handle()->geometryF();
0124     const auto resources = resourceMap();
0125 
0126     if (pos != geometry.topLeft()) {
0127         pos = geometry.topLeft();
0128         for (auto resource : resources) {
0129             sendLogicalPosition(resource);
0130         }
0131     }
0132 
0133     if (size != geometry.size()) {
0134         size = geometry.size();
0135         for (auto resource : resources) {
0136             sendLogicalSize(resource);
0137         }
0138     }
0139 
0140     for (auto resource : resources) {
0141         if (wl_resource_get_version(resource->handle) < 3) {
0142             send_done(resource->handle);
0143         }
0144     }
0145 
0146     output->scheduleDone();
0147 }
0148 
0149 void XdgOutputV1Interface::zxdg_output_v1_destroy(Resource *resource)
0150 {
0151     wl_resource_destroy(resource->handle);
0152 }
0153 
0154 void XdgOutputV1Interface::zxdg_output_v1_bind_resource(Resource *resource)
0155 {
0156     if (!output || output->isRemoved()) {
0157         return;
0158     }
0159 
0160     sendLogicalPosition(resource);
0161     sendLogicalSize(resource);
0162     if (resource->version() >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
0163         send_name(resource->handle, name);
0164     }
0165     if (resource->version() >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION) {
0166         send_description(resource->handle, description);
0167     }
0168 
0169     sendDone(resource);
0170 
0171     ClientConnection *connection = output->display()->getConnection(resource->client());
0172     connect(connection, &ClientConnection::scaleOverrideChanged, this, &XdgOutputV1Interface::resend, Qt::UniqueConnection);
0173 }
0174 
0175 void XdgOutputV1Interface::sendLogicalSize(Resource *resource)
0176 {
0177     ClientConnection *connection = output->display()->getConnection(resource->client());
0178     qreal scaleOverride = connection->scaleOverride();
0179 
0180     send_logical_size(resource->handle, std::round(size.width() * scaleOverride), std::round(size.height() * scaleOverride));
0181 }
0182 
0183 void XdgOutputV1Interface::sendLogicalPosition(Resource *resource)
0184 {
0185     ClientConnection *connection = output->display()->getConnection(resource->client());
0186     qreal scaleOverride = connection->scaleOverride();
0187 
0188     send_logical_position(resource->handle, pos.x() * scaleOverride, pos.y() * scaleOverride);
0189 }
0190 
0191 void XdgOutputV1Interface::sendDone(Resource *resource)
0192 {
0193     if (wl_resource_get_version(resource->handle) >= 3) {
0194         output->done(resource->client());
0195     } else {
0196         send_done(resource->handle);
0197     }
0198 }
0199 
0200 void XdgOutputV1Interface::resend()
0201 {
0202     if (!output || output->isRemoved()) {
0203         return;
0204     }
0205 
0206     auto changedConnection = qobject_cast<ClientConnection *>(sender());
0207     const auto outputResources = resourceMap();
0208     for (auto resource : outputResources) {
0209         ClientConnection *connection = output->display()->getConnection(resource->client());
0210         if (connection == changedConnection) {
0211             sendLogicalPosition(resource);
0212             sendLogicalSize(resource);
0213             sendDone(resource);
0214         }
0215     }
0216 }
0217 }
0218 
0219 #include "moc_xdgoutput_v1.cpp"