File indexing completed on 2024-11-10 04:57:37
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"