KWayland

outputdevice.cpp
1 /*
2  SPDX-FileCopyrightText: 2013 Martin Gräßlin <[email protected]>
3  SPDX-FileCopyrightText: 2018 Roman Gilg <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 #include "outputdevice.h"
8 #include "logging.h"
9 #include "wayland_pointer_p.h"
10 // Qt
11 #include <QDebug>
12 #include <QPoint>
13 #include <QRect>
14 // wayland
15 #include "wayland-org_kde_kwin_outputdevice-client-protocol.h"
16 #include <wayland-client-protocol.h>
17 
18 namespace KWayland
19 {
20 
21 namespace Client
22 {
23 
24 typedef QList<OutputDevice::Mode> Modes;
25 
26 class Q_DECL_HIDDEN OutputDevice::Private
27 {
28 public:
29  Private(OutputDevice *q);
30  void setup(org_kde_kwin_outputdevice *o);
31 
32  WaylandPointer<org_kde_kwin_outputdevice, org_kde_kwin_outputdevice_destroy> output;
33  EventQueue *queue = nullptr;
34  QSize physicalSize;
35  QPoint globalPosition;
36  QString manufacturer;
37  QString model;
38  qreal scale = 1.0;
39  QString serialNumber;
40  QString eisaId;
41  SubPixel subPixel = SubPixel::Unknown;
42  Transform transform = Transform::Normal;
43  Modes modes;
44  Modes::iterator currentMode = modes.end();
45 
46  QByteArray edid;
47  OutputDevice::Enablement enabled = OutputDevice::Enablement::Enabled;
48  QByteArray uuid;
49 
50  ColorCurves colorCurves;
51 
52  bool done = false;
53 
54 private:
55  static void geometryCallback(void *data, org_kde_kwin_outputdevice *output, int32_t x, int32_t y,
56  int32_t physicalWidth, int32_t physicalHeight, int32_t subPixel,
57  const char *make, const char *model, int32_t transform);
58  static void modeCallback(void *data, org_kde_kwin_outputdevice *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id);
59  static void doneCallback(void *data, org_kde_kwin_outputdevice *output);
60  static void scaleCallback(void *data, org_kde_kwin_outputdevice *output, int32_t scale);
61  static void scaleFCallback(void *data, org_kde_kwin_outputdevice *output, wl_fixed_t scale);
62 
63  static void edidCallback(void *data, org_kde_kwin_outputdevice *output, const char *raw);
64  static void enabledCallback(void *data, org_kde_kwin_outputdevice *output, int32_t enabled);
65  static void uuidCallback(void *data, org_kde_kwin_outputdevice *output, const char *uuid);
66 
67  static void colorcurvesCallback(void *data, org_kde_kwin_outputdevice *output,
68  wl_array *red, wl_array *green, wl_array *blue);
69 
70  static void serialNumberCallback(void *data, org_kde_kwin_outputdevice *output, const char *serialNumber);
71  static void eisaIdCallback(void *data, org_kde_kwin_outputdevice *output, const char *eisa);
72 
73  void setPhysicalSize(const QSize &size);
74  void setGlobalPosition(const QPoint &pos);
75  void setManufacturer(const QString &manufacturer);
76  void setModel(const QString &model);
77  void setScale(qreal scale);
78  void setSerialNumber(const QString &serialNumber);
79  void setEisaId(const QString &eisaId);
80  void setSubPixel(SubPixel subPixel);
81  void setTransform(Transform transform);
82  void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id);
83 
84  OutputDevice *q;
85  static struct org_kde_kwin_outputdevice_listener s_outputListener;
86 };
87 
88 OutputDevice::Private::Private(OutputDevice *q)
89  : q(q)
90 {
91 }
92 
93 void OutputDevice::Private::setup(org_kde_kwin_outputdevice *o)
94 {
95  Q_ASSERT(o);
96  Q_ASSERT(!output);
97  output.setup(o);
98  org_kde_kwin_outputdevice_add_listener(output, &s_outputListener, this);
99 }
100 
101 bool OutputDevice::Mode::operator==(const OutputDevice::Mode &m) const
102 {
103  return size == m.size
104  && refreshRate == m.refreshRate
105  && flags == m.flags
106  && output == m.output;
107 }
108 
109 bool OutputDevice::ColorCurves::operator==(const OutputDevice::ColorCurves &cc) const
110 {
111  return red == cc.red && green == cc.green && blue == cc.blue;
112 }
113 bool OutputDevice::ColorCurves::operator!=(const ColorCurves &cc) const {
114  return !operator==(cc);
115 }
116 
117 OutputDevice::OutputDevice(QObject *parent)
118  : QObject(parent)
119  , d(new Private(this))
120 {
121 }
122 
123 OutputDevice::~OutputDevice()
124 {
125  d->output.release();
126 }
127 
128 org_kde_kwin_outputdevice_listener OutputDevice::Private::s_outputListener = {
129  geometryCallback,
130  modeCallback,
131  doneCallback,
132  scaleCallback,
133  edidCallback,
134  enabledCallback,
135  uuidCallback,
136  scaleFCallback,
137  colorcurvesCallback,
138  serialNumberCallback,
139  eisaIdCallback
140 };
141 
142 void OutputDevice::Private::geometryCallback(void *data, org_kde_kwin_outputdevice *output,
143  int32_t x, int32_t y,
144  int32_t physicalWidth, int32_t physicalHeight,
145  int32_t subPixel, const char *make, const char *model, int32_t transform)
146 {
147  Q_UNUSED(transform)
148  auto o = reinterpret_cast<OutputDevice::Private*>(data);
149  Q_ASSERT(o->output == output);
150  o->setGlobalPosition(QPoint(x, y));
151  o->setManufacturer(make);
152  o->setModel(model);
153  o->setPhysicalSize(QSize(physicalWidth, physicalHeight));
154  auto toSubPixel = [subPixel]() {
155  switch (subPixel) {
156  case WL_OUTPUT_SUBPIXEL_NONE:
157  return SubPixel::None;
158  case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
159  return SubPixel::HorizontalRGB;
160  case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
161  return SubPixel::HorizontalBGR;
162  case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
163  return SubPixel::VerticalRGB;
164  case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
165  return SubPixel::VerticalBGR;
166  case WL_OUTPUT_SUBPIXEL_UNKNOWN:
167  default:
168  return SubPixel::Unknown;
169  }
170  };
171  o->setSubPixel(toSubPixel());
172  auto toTransform = [transform]() {
173  switch (transform) {
174  case WL_OUTPUT_TRANSFORM_90:
175  return Transform::Rotated90;
176  case WL_OUTPUT_TRANSFORM_180:
177  return Transform::Rotated180;
178  case WL_OUTPUT_TRANSFORM_270:
179  return Transform::Rotated270;
180  case WL_OUTPUT_TRANSFORM_FLIPPED:
181  return Transform::Flipped;
182  case WL_OUTPUT_TRANSFORM_FLIPPED_90:
183  return Transform::Flipped90;
184  case WL_OUTPUT_TRANSFORM_FLIPPED_180:
185  return Transform::Flipped180;
186  case WL_OUTPUT_TRANSFORM_FLIPPED_270:
187  return Transform::Flipped270;
188  case WL_OUTPUT_TRANSFORM_NORMAL:
189  default:
190  return Transform::Normal;
191  }
192  };
193  o->setTransform(toTransform());
194 }
195 
196 void OutputDevice::Private::modeCallback(void *data, org_kde_kwin_outputdevice *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id)
197 {
198  auto o = reinterpret_cast<OutputDevice::Private*>(data);
199  Q_ASSERT(o->output == output);
200  o->addMode(flags, width, height, refresh, mode_id);
201 }
202 
203 void OutputDevice::Private::addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh, int32_t mode_id)
204 {
205  Mode mode;
206  mode.output = QPointer<OutputDevice>(q);
207  mode.refreshRate = refresh;
208  mode.size = QSize(width, height);
209  mode.id = mode_id;
210  if (flags & WL_OUTPUT_MODE_CURRENT) {
211  mode.flags |= Mode::Flag::Current;
212  }
213  if (flags & WL_OUTPUT_MODE_PREFERRED) {
214  mode.flags |= Mode::Flag::Preferred;
215  }
216 
217  bool existing = false;
218  if (flags & WL_OUTPUT_MODE_CURRENT) {
219  auto it = modes.begin();
220  while (it != modes.end()) {
221  auto &m = (*it);
222  if (m.flags.testFlag(Mode::Flag::Current)) {
223  m.flags &= ~Mode::Flags(Mode::Flag::Current);
224  Q_EMIT q->modeChanged(m);
225  }
226  if (m.refreshRate == mode.refreshRate && m.size == mode.size) {
227  it = modes.erase(it);
228  existing = true;
229  } else {
230  it++;
231  }
232  }
233  }
234 
235  // insert new mode after erase all repeat old mode
236  const auto last = modes.insert(modes.end(), mode);
237  if (flags & WL_OUTPUT_MODE_CURRENT) {
238  currentMode = last;
239  }
240 
241  if (existing) {
242  Q_EMIT q->modeChanged(mode);
243  } else {
244  Q_EMIT q->modeAdded(mode);
245  }
246 }
247 
248 KWayland::Client::OutputDevice::Mode OutputDevice::currentMode() const
249 {
250  for (const auto &m: modes()) {
251  if (m.flags.testFlag(KWayland::Client::OutputDevice::Mode::Flag::Current)) {
252  return m;
253  }
254  }
255  qCWarning(KWAYLAND_CLIENT) << "current mode not found";
256  return Mode();
257 }
258 
259 void OutputDevice::Private::scaleCallback(void *data, org_kde_kwin_outputdevice *output, int32_t scale)
260 {
261  auto o = reinterpret_cast<OutputDevice::Private*>(data);
262  Q_ASSERT(o->output == output);
263  o->setScale(scale);
264 }
265 
266 void OutputDevice::Private::scaleFCallback(void *data, org_kde_kwin_outputdevice *output, wl_fixed_t scale_fixed)
267 {
268  auto o = reinterpret_cast<OutputDevice::Private*>(data);
269  Q_ASSERT(o->output == output);
270  o->setScale(wl_fixed_to_double(scale_fixed));
271 }
272 
273 void OutputDevice::Private::doneCallback(void *data, org_kde_kwin_outputdevice *output)
274 {
275  auto o = reinterpret_cast<OutputDevice::Private*>(data);
276  Q_ASSERT(o->output == output);
277  o->done = true;
278  Q_EMIT o->q->changed();
279  Q_EMIT o->q->done();
280 }
281 
282 void OutputDevice::Private::edidCallback(void* data, org_kde_kwin_outputdevice* output, const char* raw)
283 {
284  Q_UNUSED(output);
285  auto o = reinterpret_cast<OutputDevice::Private*>(data);
286  o->edid = QByteArray::fromBase64(raw);
287 }
288 
289 void OutputDevice::Private::enabledCallback(void* data, org_kde_kwin_outputdevice* output, int32_t enabled)
290 {
291  Q_UNUSED(output);
292  auto o = reinterpret_cast<OutputDevice::Private*>(data);
293 
294  OutputDevice::Enablement _enabled = OutputDevice::Enablement::Disabled;
295  if (enabled == ORG_KDE_KWIN_OUTPUTDEVICE_ENABLEMENT_ENABLED) {
296  _enabled = OutputDevice::Enablement::Enabled;
297  }
298  if (o->enabled != _enabled) {
299  o->enabled = _enabled;
300  Q_EMIT o->q->enabledChanged(o->enabled);
301  if (o->done) {
302  Q_EMIT o->q->changed();
303  }
304  }
305 }
306 
307 void OutputDevice::Private::uuidCallback(void* data, org_kde_kwin_outputdevice* output, const char *uuid)
308 {
309  Q_UNUSED(output);
310  auto o = reinterpret_cast<OutputDevice::Private*>(data);
311  if (o->uuid != uuid) {
312  o->uuid = uuid;
313  Q_EMIT o->q->uuidChanged(o->uuid);
314  if (o->done) {
315  Q_EMIT o->q->changed();
316  }
317  }
318 }
319 
320 void OutputDevice::Private::colorcurvesCallback(void *data, org_kde_kwin_outputdevice *output,
321  wl_array *red,
322  wl_array *green,
323  wl_array *blue)
324 {
325  Q_UNUSED(output);
326  auto o = reinterpret_cast<OutputDevice::Private*>(data);
327 
328  auto cc = ColorCurves();
329 
330  auto setCurve = [](const wl_array *curve, QVector<quint16> *destination) {
331  destination->resize(curve->size / sizeof(uint16_t));
332  memcpy(destination->data(), curve->data, curve->size);
333  };
334  setCurve(red, &cc.red);
335  setCurve(green, &cc.green);
336  setCurve(blue, &cc.blue);
337 
338  if (o->colorCurves != cc) {
339  o->colorCurves = cc;
340  Q_EMIT o->q->colorCurvesChanged();
341  if (o->done) {
342  Q_EMIT o->q->changed();
343  }
344  }
345 }
346 
347 void OutputDevice::Private::serialNumberCallback(void *data, org_kde_kwin_outputdevice *output, const char *raw)
348 {
349  auto o = reinterpret_cast<OutputDevice::Private*>(data);
350  Q_UNUSED(output);
351  o->setSerialNumber(raw);
352 }
353 
354 void OutputDevice::Private::eisaIdCallback(void *data, org_kde_kwin_outputdevice *output, const char *raw)
355 {
356  auto o = reinterpret_cast<OutputDevice::Private*>(data);
357  Q_UNUSED(output);
358  o->setEisaId(raw);
359 }
360 
361 void OutputDevice::setup(org_kde_kwin_outputdevice *output)
362 {
363  d->setup(output);
364 }
365 
367 {
368  return d->queue;
369 }
370 
372 {
373  d->queue = queue;
374 }
375 
376 void OutputDevice::Private::setGlobalPosition(const QPoint &pos)
377 {
378  globalPosition = pos;
379 }
380 
381 void OutputDevice::Private::setManufacturer(const QString &m)
382 {
383  manufacturer = m;
384 }
385 
386 void OutputDevice::Private::setModel(const QString &m)
387 {
388  model = m;
389 }
390 
391 void OutputDevice::Private::setSerialNumber(const QString &sn)
392 {
393  serialNumber = sn;
394 }
395 
396 void OutputDevice::Private::setEisaId(const QString &e)
397 {
398  eisaId = e;
399 }
400 
401 void OutputDevice::Private::setPhysicalSize(const QSize &size)
402 {
403  physicalSize = size;
404 }
405 
406 void OutputDevice::Private::setScale(qreal s)
407 {
408  scale = s;
409 }
410 
412 {
413  if (d->currentMode == d->modes.end()) {
414  return QRect();
415  }
416  return QRect(d->globalPosition, pixelSize());
417 }
418 
419 void OutputDevice::Private::setSubPixel(OutputDevice::SubPixel s)
420 {
421  subPixel = s;
422 }
423 
424 void OutputDevice::Private::setTransform(OutputDevice::Transform t)
425 {
426  transform = t;
427 }
428 
430 {
431  return d->globalPosition;
432 }
433 
435 {
436  return d->manufacturer;
437 }
438 
440 {
441  return d->model;
442 }
443 
445 {
446  return d->serialNumber;
447 }
448 
450 {
451  return d->eisaId;
452 }
453 
454 org_kde_kwin_outputdevice *OutputDevice::output()
455 {
456  return d->output;
457 }
458 
460 {
461  return d->physicalSize;
462 }
463 
465 {
466  if (d->currentMode == d->modes.end()) {
467  return QSize();
468  }
469  return (*d->currentMode).size;
470 }
471 
473 {
474  if (d->currentMode == d->modes.end()) {
475  return 0;
476  }
477  return (*d->currentMode).refreshRate;
478 }
479 
481 {
482  return qRound(d->scale);
483 }
484 
485 qreal OutputDevice::scaleF() const
486 {
487  return d->scale;
488 }
489 
490 
492 {
493  return d->output.isValid();
494 }
495 
496 OutputDevice::SubPixel OutputDevice::subPixel() const
497 {
498  return d->subPixel;
499 }
500 
501 OutputDevice::Transform OutputDevice::transform() const
502 {
503  return d->transform;
504 }
505 
507 {
508  return d->modes;
509 }
510 
511 OutputDevice::operator org_kde_kwin_outputdevice*() {
512  return d->output;
513 }
514 
515 OutputDevice::operator org_kde_kwin_outputdevice*() const {
516  return d->output;
517 }
518 
520 {
521  return d->edid;
522 }
523 
524 OutputDevice::Enablement OutputDevice::enabled() const
525 {
526  return d->enabled;
527 }
528 
530 {
531  return d->uuid;
532 }
533 
534 OutputDevice::ColorCurves OutputDevice::colorCurves() const
535 {
536  return d->colorCurves;
537 }
538 
540 {
541  d->output.destroy();
542 
543 }
544 
545 }
546 }
QList< Mode > modes() const
QSize physicalSize() const
Size in millimeters.
QString::iterator end()
Wrapper class for wl_event_queue interface.
Definition: event_queue.h:55
int scale() const
Scaling factor of this output.
QRect geometry() const
The geometry of this OutputDevice in pixels.
QString serialNumber() const
Textual representation of serial number.
Transform transform() const
Transform that maps framebuffer to OutputDevice.
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QVector< const char * > &params=QVector< const char * >())
bool operator==(const Qt3DRender::QGraphicsApiFilter &reference, const Qt3DRender::QGraphicsApiFilter &sample)
QString manufacturer() const
Textual description of the manufacturer.
QString eisaId() const
Textual representation of EISA identifier.
void destroy()
Destroys the data hold by this OutputDevice.
void setEventQueue(EventQueue *queue)
Sets the queue to use for bound proxies.
SubPixel subPixel() const
Subpixel orientation of this OutputDevice.
QByteArray fromBase64(const QByteArray &base64, QByteArray::Base64Options options)
EventQueue * eventQueue() const
QSize pixelSize() const
Size in the current mode.
int refreshRate() const
Refresh rate in mHz of the current mode.
QPoint globalPosition() const
Position within the global compositor space.
qreal scaleF() const
Scaling factor of this output.
QObject * parent() const const
ColorCurves colorCurves() const
Color curves.
OutputDevice::Enablement enabled() const
void setup(org_kde_kwin_outputdevice *output)
Setup this Compositor to manage the output.
QString model() const
Textual description of the model.
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Apr 9 2021 22:50:08 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.