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