File indexing completed on 2024-05-19 16:35:22
0001 /* 0002 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org> 0003 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 #include "output_interface.h" 0008 #include "display.h" 0009 #include "display_p.h" 0010 #include "utils.h" 0011 0012 #include "core/output.h" 0013 0014 #include "qwayland-server-wayland.h" 0015 0016 #include <QPointer> 0017 #include <QTimer> 0018 #include <QVector> 0019 0020 namespace KWaylandServer 0021 { 0022 static const int s_version = 4; 0023 0024 class OutputInterfacePrivate : public QtWaylandServer::wl_output 0025 { 0026 public: 0027 explicit OutputInterfacePrivate(Display *display, OutputInterface *q, KWin::Output *handle); 0028 0029 void sendScale(Resource *resource); 0030 void sendGeometry(Resource *resource); 0031 void sendMode(Resource *resource); 0032 void sendDone(Resource *resource); 0033 0034 OutputInterface *q; 0035 QPointer<Display> display; 0036 QPointer<KWin::Output> handle; 0037 QSize physicalSize; 0038 QPoint globalPosition; 0039 QString manufacturer; 0040 QString model; 0041 int scale = 1; 0042 KWin::Output::SubPixel subPixel = KWin::Output::SubPixel::Unknown; 0043 KWin::Output::Transform transform = KWin::Output::Transform::Normal; 0044 QSize modeSize; 0045 int refreshRate = 0; 0046 QString name; 0047 QString description; 0048 QTimer doneTimer; 0049 0050 private: 0051 void output_destroy_global() override; 0052 void output_bind_resource(Resource *resource) override; 0053 void output_release(Resource *resource) override; 0054 }; 0055 0056 OutputInterfacePrivate::OutputInterfacePrivate(Display *display, OutputInterface *q, KWin::Output *handle) 0057 : QtWaylandServer::wl_output(*display, s_version) 0058 , q(q) 0059 , display(display) 0060 , handle(handle) 0061 { 0062 } 0063 0064 void OutputInterfacePrivate::sendMode(Resource *resource) 0065 { 0066 send_mode(resource->handle, mode_current, modeSize.width(), modeSize.height(), refreshRate); 0067 } 0068 0069 void OutputInterfacePrivate::sendScale(Resource *resource) 0070 { 0071 if (resource->version() >= WL_OUTPUT_SCALE_SINCE_VERSION) { 0072 send_scale(resource->handle, scale); 0073 } 0074 } 0075 0076 static quint32 kwaylandServerTransformToWaylandTransform(KWin::Output::Transform transform) 0077 { 0078 switch (transform) { 0079 case KWin::Output::Transform::Normal: 0080 return OutputInterfacePrivate::transform_normal; 0081 case KWin::Output::Transform::Rotated90: 0082 return OutputInterfacePrivate::transform_90; 0083 case KWin::Output::Transform::Rotated180: 0084 return OutputInterfacePrivate::transform_180; 0085 case KWin::Output::Transform::Rotated270: 0086 return OutputInterfacePrivate::transform_270; 0087 case KWin::Output::Transform::Flipped: 0088 return OutputInterfacePrivate::transform_flipped; 0089 case KWin::Output::Transform::Flipped90: 0090 return OutputInterfacePrivate::transform_flipped_90; 0091 case KWin::Output::Transform::Flipped180: 0092 return OutputInterfacePrivate::transform_flipped_180; 0093 case KWin::Output::Transform::Flipped270: 0094 return OutputInterfacePrivate::transform_flipped_270; 0095 default: 0096 Q_UNREACHABLE(); 0097 } 0098 } 0099 0100 static quint32 kwaylandServerSubPixelToWaylandSubPixel(KWin::Output::SubPixel subPixel) 0101 { 0102 switch (subPixel) { 0103 case KWin::Output::SubPixel::Unknown: 0104 return OutputInterfacePrivate::subpixel_unknown; 0105 case KWin::Output::SubPixel::None: 0106 return OutputInterfacePrivate::subpixel_none; 0107 case KWin::Output::SubPixel::Horizontal_RGB: 0108 return OutputInterfacePrivate::subpixel_horizontal_rgb; 0109 case KWin::Output::SubPixel::Horizontal_BGR: 0110 return OutputInterfacePrivate::subpixel_horizontal_bgr; 0111 case KWin::Output::SubPixel::Vertical_RGB: 0112 return OutputInterfacePrivate::subpixel_vertical_rgb; 0113 case KWin::Output::SubPixel::Vertical_BGR: 0114 return OutputInterfacePrivate::subpixel_vertical_bgr; 0115 default: 0116 Q_UNREACHABLE(); 0117 } 0118 } 0119 0120 void OutputInterfacePrivate::sendGeometry(Resource *resource) 0121 { 0122 send_geometry(resource->handle, 0123 globalPosition.x(), 0124 globalPosition.y(), 0125 physicalSize.width(), 0126 physicalSize.height(), 0127 kwaylandServerSubPixelToWaylandSubPixel(subPixel), 0128 manufacturer, 0129 model, 0130 kwaylandServerTransformToWaylandTransform(transform)); 0131 } 0132 0133 void OutputInterfacePrivate::sendDone(Resource *resource) 0134 { 0135 if (resource->version() >= WL_OUTPUT_DONE_SINCE_VERSION) { 0136 send_done(resource->handle); 0137 } 0138 } 0139 0140 void OutputInterfacePrivate::output_destroy_global() 0141 { 0142 delete q; 0143 } 0144 0145 void OutputInterfacePrivate::output_release(Resource *resource) 0146 { 0147 wl_resource_destroy(resource->handle); 0148 } 0149 0150 void OutputInterfacePrivate::output_bind_resource(Resource *resource) 0151 { 0152 if (isGlobalRemoved()) { 0153 return; // We are waiting for the wl_output global to be destroyed. 0154 } 0155 0156 if (resource->version() >= WL_OUTPUT_NAME_SINCE_VERSION) { 0157 send_name(resource->handle, name); 0158 } 0159 if (resource->version() >= WL_OUTPUT_DESCRIPTION_SINCE_VERSION) { 0160 send_description(resource->handle, description); 0161 } 0162 0163 sendMode(resource); 0164 sendScale(resource); 0165 sendGeometry(resource); 0166 sendDone(resource); 0167 0168 Q_EMIT q->bound(display->getConnection(resource->client()), resource->handle); 0169 } 0170 0171 OutputInterface::OutputInterface(Display *display, KWin::Output *handle, QObject *parent) 0172 : QObject(parent) 0173 , d(new OutputInterfacePrivate(display, this, handle)) 0174 { 0175 DisplayPrivate *displayPrivate = DisplayPrivate::get(display); 0176 displayPrivate->outputs.append(this); 0177 0178 // Delay the done event to batch property updates. 0179 d->doneTimer.setSingleShot(true); 0180 d->doneTimer.setInterval(0); 0181 connect(&d->doneTimer, &QTimer::timeout, this, [this]() { 0182 const auto resources = d->resourceMap(); 0183 for (const auto &resource : resources) { 0184 d->sendDone(resource); 0185 } 0186 }); 0187 0188 d->name = handle->name(); 0189 d->description = handle->description(); 0190 d->transform = handle->transform(); 0191 d->manufacturer = handle->manufacturer(); 0192 d->model = handle->model(); 0193 d->physicalSize = handle->physicalSize(); 0194 d->globalPosition = handle->geometry().topLeft(); 0195 d->scale = std::ceil(handle->scale()); 0196 d->modeSize = handle->modeSize(); 0197 d->refreshRate = handle->refreshRate(); 0198 d->subPixel = handle->subPixel(); 0199 0200 connect(handle, &KWin::Output::geometryChanged, this, [this]() { 0201 const QPoint position = d->handle->geometry().topLeft(); 0202 if (d->globalPosition != position) { 0203 d->globalPosition = position; 0204 const auto resources = d->resourceMap(); 0205 for (const auto &resource : resources) { 0206 d->sendGeometry(resource); 0207 } 0208 scheduleDone(); 0209 } 0210 }); 0211 0212 connect(handle, &KWin::Output::scaleChanged, this, [this]() { 0213 const int scale = std::ceil(d->handle->scale()); 0214 if (d->scale != scale) { 0215 d->scale = scale; 0216 const auto resources = d->resourceMap(); 0217 for (const auto &resource : resources) { 0218 d->sendScale(resource); 0219 } 0220 scheduleDone(); 0221 } 0222 }); 0223 0224 connect(handle, &KWin::Output::transformChanged, this, [this]() { 0225 const KWin::Output::Transform transform = d->handle->transform(); 0226 if (d->transform != transform) { 0227 d->transform = transform; 0228 const auto resources = d->resourceMap(); 0229 for (const auto &resource : resources) { 0230 d->sendGeometry(resource); 0231 } 0232 scheduleDone(); 0233 } 0234 }); 0235 0236 connect(handle, &KWin::Output::currentModeChanged, this, [this]() { 0237 const QSize size = d->handle->modeSize(); 0238 const int refreshRate = d->handle->refreshRate(); 0239 if (d->modeSize != size || d->refreshRate != refreshRate) { 0240 d->modeSize = size; 0241 d->refreshRate = refreshRate; 0242 const auto resources = d->resourceMap(); 0243 for (const auto &resource : resources) { 0244 d->sendMode(resource); 0245 } 0246 scheduleDone(); 0247 } 0248 }); 0249 } 0250 0251 OutputInterface::~OutputInterface() 0252 { 0253 remove(); 0254 } 0255 0256 Display *OutputInterface::display() const 0257 { 0258 return d->display; 0259 } 0260 0261 KWin::Output *OutputInterface::handle() const 0262 { 0263 return d->handle; 0264 } 0265 0266 bool OutputInterface::isRemoved() const 0267 { 0268 return d->isGlobalRemoved(); 0269 } 0270 0271 void OutputInterface::remove() 0272 { 0273 if (d->isGlobalRemoved()) { 0274 return; 0275 } 0276 0277 d->doneTimer.stop(); 0278 if (d->handle) { 0279 disconnect(d->handle, nullptr, this, nullptr); 0280 } 0281 0282 if (d->display) { 0283 DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display); 0284 displayPrivate->outputs.removeOne(this); 0285 } 0286 0287 Q_EMIT removed(); 0288 d->globalRemove(); 0289 } 0290 0291 QVector<wl_resource *> OutputInterface::clientResources(ClientConnection *client) const 0292 { 0293 const auto outputResources = d->resourceMap().values(client->client()); 0294 QVector<wl_resource *> ret; 0295 ret.reserve(outputResources.count()); 0296 0297 for (OutputInterfacePrivate::Resource *resource : outputResources) { 0298 ret.append(resource->handle); 0299 } 0300 0301 return ret; 0302 } 0303 0304 void OutputInterface::scheduleDone() 0305 { 0306 if (!d->isGlobalRemoved()) { 0307 d->doneTimer.start(); 0308 } 0309 } 0310 0311 void OutputInterface::done(wl_client *client) 0312 { 0313 if (!d->isGlobalRemoved()) { 0314 d->sendDone(d->resourceMap().value(client)); 0315 } 0316 } 0317 0318 OutputInterface *OutputInterface::get(wl_resource *native) 0319 { 0320 if (auto outputPrivate = resource_cast<OutputInterfacePrivate *>(native)) { 0321 return outputPrivate->q; 0322 } 0323 return nullptr; 0324 } 0325 0326 } // namespace KWaylandServer