KWayland

output.cpp
1 /*
2  SPDX-FileCopyrightText: 2013 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "output.h"
7 #include "wayland_pointer_p.h"
8 // Qt
9 #include <QPoint>
10 #include <QRect>
11 #include <QVector>
12 // wayland
13 #include <wayland-client-protocol.h>
14 
15 namespace KWayland
16 {
17 namespace Client
18 {
19 namespace
20 {
21 typedef QList<Output::Mode> Modes;
22 }
23 
24 class Q_DECL_HIDDEN Output::Private
25 {
26 public:
27  Private(Output *q);
28  ~Private();
29  void setup(wl_output *o);
30 
31  WaylandPointer<wl_output, wl_output_release> output;
32  EventQueue *queue = nullptr;
33  QSize physicalSize;
34  QPoint globalPosition;
35  QString manufacturer;
36  QString model;
37  int scale = 1;
38  SubPixel subPixel = SubPixel::Unknown;
39  Transform transform = Transform::Normal;
40  Modes modes;
41  Modes::iterator currentMode = modes.end();
42 
43  static Output *get(wl_output *o);
44 
45 private:
46  static void geometryCallback(void *data,
47  wl_output *output,
48  int32_t x,
49  int32_t y,
50  int32_t physicalWidth,
51  int32_t physicalHeight,
52  int32_t subPixel,
53  const char *make,
54  const char *model,
55  int32_t transform);
56  static void modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh);
57  static void doneCallback(void *data, wl_output *output);
58  static void scaleCallback(void *data, wl_output *output, int32_t scale);
59  void setPhysicalSize(const QSize &size);
60  void setGlobalPosition(const QPoint &pos);
61  void setManufacturer(const QString &manufacturer);
62  void setModel(const QString &model);
63  void setScale(int scale);
64  void setSubPixel(SubPixel subPixel);
65  void setTransform(Transform transform);
66  void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh);
67 
68  Output *q;
69  static struct wl_output_listener s_outputListener;
70 
71  static QVector<Private *> s_allOutputs;
72 };
73 
74 QVector<Output::Private *> Output::Private::s_allOutputs;
75 
76 Output::Private::Private(Output *q)
77  : q(q)
78 {
79  s_allOutputs << this;
80 }
81 
82 Output::Private::~Private()
83 {
84  s_allOutputs.removeOne(this);
85 }
86 
87 Output *Output::Private::get(wl_output *o)
88 {
89  auto it = std::find_if(s_allOutputs.constBegin(), s_allOutputs.constEnd(), [o](Private *p) {
90  const wl_output *reference = p->output;
91  return reference == o;
92  });
93  if (it != s_allOutputs.constEnd()) {
94  return (*it)->q;
95  }
96  return nullptr;
97 }
98 
99 void Output::Private::setup(wl_output *o)
100 {
101  Q_ASSERT(o);
102  Q_ASSERT(!output);
103  output.setup(o);
104  wl_output_add_listener(output, &s_outputListener, this);
105 }
106 
107 bool Output::Mode::operator==(const Output::Mode &m) const
108 {
109  return size == m.size && refreshRate == m.refreshRate && flags == m.flags && output == m.output;
110 }
111 
112 Output::Output(QObject *parent)
113  : QObject(parent)
114  , d(new Private(this))
115 {
116 }
117 
118 Output::~Output()
119 {
120  d->output.release();
121 }
122 
123 wl_output_listener Output::Private::s_outputListener = {geometryCallback, modeCallback, doneCallback, scaleCallback};
124 
125 void Output::Private::geometryCallback(void *data,
126  wl_output *output,
127  int32_t x,
128  int32_t y,
129  int32_t physicalWidth,
130  int32_t physicalHeight,
131  int32_t subPixel,
132  const char *make,
133  const char *model,
134  int32_t transform)
135 {
136  Q_UNUSED(transform)
137  auto o = reinterpret_cast<Output::Private *>(data);
138  Q_ASSERT(o->output == output);
139  o->setGlobalPosition(QPoint(x, y));
140  o->setManufacturer(make);
141  o->setModel(model);
142  o->setPhysicalSize(QSize(physicalWidth, physicalHeight));
143  auto toSubPixel = [subPixel]() {
144  switch (subPixel) {
145  case WL_OUTPUT_SUBPIXEL_NONE:
146  return SubPixel::None;
147  case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
148  return SubPixel::HorizontalRGB;
149  case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
150  return SubPixel::HorizontalBGR;
151  case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
152  return SubPixel::VerticalRGB;
153  case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
154  return SubPixel::VerticalBGR;
155  case WL_OUTPUT_SUBPIXEL_UNKNOWN:
156  default:
157  return SubPixel::Unknown;
158  }
159  };
160  o->setSubPixel(toSubPixel());
161  auto toTransform = [transform]() {
162  switch (transform) {
163  case WL_OUTPUT_TRANSFORM_90:
164  return Transform::Rotated90;
165  case WL_OUTPUT_TRANSFORM_180:
166  return Transform::Rotated180;
167  case WL_OUTPUT_TRANSFORM_270:
168  return Transform::Rotated270;
169  case WL_OUTPUT_TRANSFORM_FLIPPED:
170  return Transform::Flipped;
171  case WL_OUTPUT_TRANSFORM_FLIPPED_90:
172  return Transform::Flipped90;
173  case WL_OUTPUT_TRANSFORM_FLIPPED_180:
174  return Transform::Flipped180;
175  case WL_OUTPUT_TRANSFORM_FLIPPED_270:
176  return Transform::Flipped270;
177  case WL_OUTPUT_TRANSFORM_NORMAL:
178  default:
179  return Transform::Normal;
180  }
181  };
182  o->setTransform(toTransform());
183 }
184 
185 void Output::Private::modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
186 {
187  auto o = reinterpret_cast<Output::Private *>(data);
188  Q_ASSERT(o->output == output);
189  o->addMode(flags, width, height, refresh);
190 }
191 
192 void Output::Private::addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh)
193 {
194  Mode mode;
195  mode.output = QPointer<Output>(q);
196  mode.refreshRate = refresh;
197  mode.size = QSize(width, height);
198  if (flags & WL_OUTPUT_MODE_CURRENT) {
199  mode.flags |= Mode::Flag::Current;
200  }
201  if (flags & WL_OUTPUT_MODE_PREFERRED) {
202  mode.flags |= Mode::Flag::Preferred;
203  }
204  auto currentIt = modes.insert(modes.end(), mode);
205  bool existing = false;
206  if (flags & WL_OUTPUT_MODE_CURRENT) {
207  auto it = modes.begin();
208  while (it != currentIt) {
209  auto &m = (*it);
210  if (m.flags.testFlag(Mode::Flag::Current)) {
211  m.flags &= ~Mode::Flags(Mode::Flag::Current);
212  Q_EMIT q->modeChanged(m);
213  }
214  if (m.refreshRate == mode.refreshRate && m.size == mode.size) {
215  it = modes.erase(it);
216  existing = true;
217  } else {
218  it++;
219  }
220  }
221  currentMode = currentIt;
222  }
223  if (existing) {
224  Q_EMIT q->modeChanged(mode);
225  } else {
226  Q_EMIT q->modeAdded(mode);
227  }
228 }
229 
230 void Output::Private::scaleCallback(void *data, wl_output *output, int32_t scale)
231 {
232  auto o = reinterpret_cast<Output::Private *>(data);
233  Q_ASSERT(o->output == output);
234  o->setScale(scale);
235 }
236 
237 void Output::Private::doneCallback(void *data, wl_output *output)
238 {
239  auto o = reinterpret_cast<Output::Private *>(data);
240  Q_ASSERT(o->output == output);
241  Q_EMIT o->q->changed();
242 }
243 
244 void Output::setup(wl_output *output)
245 {
246  d->setup(output);
247 }
248 
249 EventQueue *Output::eventQueue() const
250 {
251  return d->queue;
252 }
253 
254 void Output::setEventQueue(EventQueue *queue)
255 {
256  d->queue = queue;
257 }
258 
259 void Output::Private::setGlobalPosition(const QPoint &pos)
260 {
261  globalPosition = pos;
262 }
263 
264 void Output::Private::setManufacturer(const QString &m)
265 {
266  manufacturer = m;
267 }
268 
269 void Output::Private::setModel(const QString &m)
270 {
271  model = m;
272 }
273 
274 void Output::Private::setPhysicalSize(const QSize &size)
275 {
276  physicalSize = size;
277 }
278 
279 void Output::Private::setScale(int s)
280 {
281  scale = s;
282 }
283 
284 QRect Output::geometry() const
285 {
286  if (d->currentMode == d->modes.end()) {
287  return QRect();
288  }
289  return QRect(d->globalPosition, pixelSize());
290 }
291 
292 void Output::Private::setSubPixel(Output::SubPixel s)
293 {
294  subPixel = s;
295 }
296 
297 void Output::Private::setTransform(Output::Transform t)
298 {
299  transform = t;
300 }
301 
302 QPoint Output::globalPosition() const
303 {
304  return d->globalPosition;
305 }
306 
307 QString Output::manufacturer() const
308 {
309  return d->manufacturer;
310 }
311 
312 QString Output::model() const
313 {
314  return d->model;
315 }
316 
317 wl_output *Output::output()
318 {
319  return d->output;
320 }
321 
322 QSize Output::physicalSize() const
323 {
324  return d->physicalSize;
325 }
326 
327 QSize Output::pixelSize() const
328 {
329  if (d->currentMode == d->modes.end()) {
330  return QSize();
331  }
332  return (*d->currentMode).size;
333 }
334 
335 int Output::refreshRate() const
336 {
337  if (d->currentMode == d->modes.end()) {
338  return 0;
339  }
340  return (*d->currentMode).refreshRate;
341 }
342 
343 int Output::scale() const
344 {
345  return d->scale;
346 }
347 
348 bool Output::isValid() const
349 {
350  return d->output.isValid();
351 }
352 
353 Output::SubPixel Output::subPixel() const
354 {
355  return d->subPixel;
356 }
357 
358 Output::Transform Output::transform() const
359 {
360  return d->transform;
361 }
362 
363 QList<Output::Mode> Output::modes() const
364 {
365  return d->modes;
366 }
367 
368 Output::operator wl_output *()
369 {
370  return d->output;
371 }
372 
373 Output::operator wl_output *() const
374 {
375  return d->output;
376 }
377 
378 Output *Output::get(wl_output *o)
379 {
380  return Private::get(o);
381 }
382 
383 void Output::destroy()
384 {
385  d->output.destroy();
386 }
387 
388 }
389 }
Wrapper class for wl_event_queue interface.
Definition: event_queue.h:54
KDOCTOOLS_EXPORT QString transform(const QString &file, const QString &stylesheet, const QVector< const char * > &params=QVector< const char * >())
Wrapper for the wl_output interface.
Definition: output.h:54
QList::iterator end()
QObject * parent() const const
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Thu Sep 23 2021 22:51:08 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.