KWin
Loading...
Searching...
No Matches
output.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3 SPDX-FileCopyrightText: 2021 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7#include "output.h"
8#include "display.h"
9#include "display_p.h"
10#include "utils/resource.h"
11
12#include "core/output.h"
13
14#include "qwayland-server-wayland.h"
15
16#include <QList>
17#include <QPointer>
18#include <QTimer>
19
20#include <cmath>
21
22namespace KWin
23{
24static const int s_version = 4;
25
26class OutputInterfacePrivate : public QtWaylandServer::wl_output
27{
28public:
30
31 void sendScale(Resource *resource);
32 void sendGeometry(Resource *resource);
33 void sendMode(Resource *resource);
34 void sendDone(Resource *resource);
35
37 QPointer<Display> display;
38 QPointer<Output> handle;
41 QString manufacturer;
42 QString model;
43 int scale = 1;
46 QSize modeSize;
47 int refreshRate = 0;
48 QString name;
49 QString description;
50 QTimer doneTimer;
51
52private:
53 void output_destroy_global() override;
54 void output_bind_resource(Resource *resource) override;
55 void output_release(Resource *resource) override;
56};
57
59 : QtWaylandServer::wl_output(*display, s_version)
60 , q(q)
61 , display(display)
62 , handle(handle)
63{
64}
65
66void OutputInterfacePrivate::sendMode(Resource *resource)
67{
68 send_mode(resource->handle, mode_current, modeSize.width(), modeSize.height(), refreshRate);
69}
70
71void OutputInterfacePrivate::sendScale(Resource *resource)
72{
73 if (resource->version() >= WL_OUTPUT_SCALE_SINCE_VERSION) {
74 send_scale(resource->handle, scale);
75 }
76}
77
78static quint32 kwaylandServerTransformToWaylandTransform(OutputTransform transform)
79{
80 switch (transform.kind()) {
82 return OutputInterfacePrivate::transform_normal;
84 return OutputInterfacePrivate::transform_90;
86 return OutputInterfacePrivate::transform_180;
88 return OutputInterfacePrivate::transform_270;
90 return OutputInterfacePrivate::transform_flipped;
92 return OutputInterfacePrivate::transform_flipped_90;
94 return OutputInterfacePrivate::transform_flipped_180;
96 return OutputInterfacePrivate::transform_flipped_270;
97 default:
98 Q_UNREACHABLE();
99 }
100}
101
102static quint32 kwaylandServerSubPixelToWaylandSubPixel(Output::SubPixel subPixel)
103{
104 switch (subPixel) {
106 return OutputInterfacePrivate::subpixel_unknown;
108 return OutputInterfacePrivate::subpixel_none;
110 return OutputInterfacePrivate::subpixel_horizontal_rgb;
112 return OutputInterfacePrivate::subpixel_horizontal_bgr;
114 return OutputInterfacePrivate::subpixel_vertical_rgb;
116 return OutputInterfacePrivate::subpixel_vertical_bgr;
117 default:
118 Q_UNREACHABLE();
119 }
120}
121
123{
124 send_geometry(resource->handle,
125 globalPosition.x(),
126 globalPosition.y(),
127 physicalSize.width(),
128 physicalSize.height(),
129 kwaylandServerSubPixelToWaylandSubPixel(subPixel),
131 model,
132 kwaylandServerTransformToWaylandTransform(transform));
133}
134
135void OutputInterfacePrivate::sendDone(Resource *resource)
136{
137 if (resource->version() >= WL_OUTPUT_DONE_SINCE_VERSION) {
138 send_done(resource->handle);
139 }
140}
141
142void OutputInterfacePrivate::output_destroy_global()
143{
144 delete q;
145}
146
147void OutputInterfacePrivate::output_release(Resource *resource)
148{
149 wl_resource_destroy(resource->handle);
150}
151
152void OutputInterfacePrivate::output_bind_resource(Resource *resource)
153{
154 if (isGlobalRemoved()) {
155 return; // We are waiting for the wl_output global to be destroyed.
156 }
157
158 if (resource->version() >= WL_OUTPUT_NAME_SINCE_VERSION) {
159 send_name(resource->handle, name);
160 }
161 if (resource->version() >= WL_OUTPUT_DESCRIPTION_SINCE_VERSION) {
162 send_description(resource->handle, description);
163 }
164
165 sendMode(resource);
166 sendScale(resource);
167 sendGeometry(resource);
168 sendDone(resource);
169
170 Q_EMIT q->bound(display->getConnection(resource->client()), resource->handle);
171}
172
173OutputInterface::OutputInterface(Display *display, Output *handle, QObject *parent)
174 : QObject(parent)
175 , d(new OutputInterfacePrivate(display, this, handle))
176{
177 DisplayPrivate *displayPrivate = DisplayPrivate::get(display);
178 displayPrivate->outputs.append(this);
179
180 // Delay the done event to batch property updates.
181 d->doneTimer.setSingleShot(true);
182 d->doneTimer.setInterval(0);
183 connect(&d->doneTimer, &QTimer::timeout, this, [this]() {
184 const auto resources = d->resourceMap();
185 for (const auto &resource : resources) {
186 d->sendDone(resource);
187 }
188 });
189
190 d->name = handle->name();
191 d->description = handle->description();
192 d->transform = handle->transform();
193 d->manufacturer = handle->manufacturer();
194 d->model = handle->model();
195 d->physicalSize = handle->physicalSize();
196 d->globalPosition = handle->geometry().topLeft();
197 d->scale = std::ceil(handle->scale());
198 d->modeSize = handle->modeSize();
199 d->refreshRate = handle->refreshRate();
200 d->subPixel = handle->subPixel();
201
202 connect(handle, &Output::geometryChanged, this, [this]() {
203 const QPoint position = d->handle->geometry().topLeft();
204 if (d->globalPosition != position) {
205 d->globalPosition = position;
206 const auto resources = d->resourceMap();
207 for (const auto &resource : resources) {
208 d->sendGeometry(resource);
209 }
210 scheduleDone();
211 }
212 });
213
214 connect(handle, &Output::scaleChanged, this, [this]() {
215 const int scale = std::ceil(d->handle->scale());
216 if (d->scale != scale) {
217 d->scale = scale;
218 const auto resources = d->resourceMap();
219 for (const auto &resource : resources) {
220 d->sendScale(resource);
221 }
222 scheduleDone();
223 }
224 });
225
226 connect(handle, &Output::transformChanged, this, [this]() {
227 const OutputTransform transform = d->handle->transform();
228 if (d->transform != transform) {
229 d->transform = transform;
230 const auto resources = d->resourceMap();
231 for (const auto &resource : resources) {
232 d->sendGeometry(resource);
233 }
234 scheduleDone();
235 }
236 });
237
238 connect(handle, &Output::currentModeChanged, this, [this]() {
239 const QSize size = d->handle->modeSize();
240 const int refreshRate = d->handle->refreshRate();
241 if (d->modeSize != size || d->refreshRate != refreshRate) {
242 d->modeSize = size;
243 d->refreshRate = refreshRate;
244 const auto resources = d->resourceMap();
245 for (const auto &resource : resources) {
246 d->sendMode(resource);
247 }
248 scheduleDone();
249 }
250 });
251}
252
253OutputInterface::~OutputInterface()
254{
255 remove();
256}
257
258Display *OutputInterface::display() const
259{
260 return d->display;
261}
262
263Output *OutputInterface::handle() const
264{
265 return d->handle;
266}
267
268bool OutputInterface::isRemoved() const
269{
270 return d->isGlobalRemoved();
271}
272
273void OutputInterface::remove()
274{
275 if (d->isGlobalRemoved()) {
276 return;
277 }
278
279 d->doneTimer.stop();
280 if (d->handle) {
281 disconnect(d->handle, nullptr, this, nullptr);
282 }
283
284 if (d->display) {
285 DisplayPrivate *displayPrivate = DisplayPrivate::get(d->display);
286 displayPrivate->outputs.removeOne(this);
287 }
288
289 Q_EMIT removed();
290 d->globalRemove();
291}
292
293QList<wl_resource *> OutputInterface::clientResources(wl_client *client) const
294{
295 const auto outputResources = d->resourceMap().values(client);
296 QList<wl_resource *> ret;
297 ret.reserve(outputResources.count());
298
299 for (OutputInterfacePrivate::Resource *resource : outputResources) {
300 ret.append(resource->handle);
301 }
302
303 return ret;
304}
305
306void OutputInterface::scheduleDone()
307{
308 if (!d->isGlobalRemoved()) {
309 d->doneTimer.start();
310 }
311}
312
313void OutputInterface::done(wl_client *client)
314{
315 if (!d->isGlobalRemoved()) {
316 d->sendDone(d->resourceMap().value(client));
317 }
318}
319
320OutputInterface *OutputInterface::get(wl_resource *native)
321{
322 if (auto outputPrivate = resource_cast<OutputInterfacePrivate *>(native)) {
323 return outputPrivate->q;
324 }
325 return nullptr;
326}
327
328} // namespace KWin
329
330#include "wayland/moc_output.cpp"
Class holding the Wayland server display loop.
Definition display.h:34
static DisplayPrivate * get(Display *display)
Definition display.cpp:26
QList< OutputInterface * > outputs
Definition display_p.h:40
void geometryChanged()
void bound(ClientConnection *client, wl_resource *boundResource)
OutputInterface(Display *display, Output *handle, QObject *parent=nullptr)
Definition output.cpp:173
Display * display() const
Definition output.cpp:258
QPointer< Output > handle
Definition output.cpp:38
void sendMode(Resource *resource)
Definition output.cpp:66
void sendDone(Resource *resource)
Definition output.cpp:135
OutputInterfacePrivate(Display *display, OutputInterface *q, Output *handle)
Definition output.cpp:58
OutputInterface * q
Definition output.cpp:36
void sendGeometry(Resource *resource)
Definition output.cpp:122
OutputTransform transform
Definition output.cpp:45
Output::SubPixel subPixel
Definition output.cpp:44
void sendScale(Resource *resource)
Definition output.cpp:71
QPointer< Display > display
Definition output.cpp:37
Kind kind() const
Definition output.cpp:64