6 #include "output_interface.h"
12 #include <wayland-server.h>
18 class OutputInterface::Private :
public Global::Private
22 wl_resource *resource;
25 Private(OutputInterface *q, Display *d);
27 void sendMode(wl_resource *resource,
const Mode &mode);
28 void sendDone(
const ResourceData &data);
29 void updateGeometry();
34 QString manufacturer = QStringLiteral(
"org.kde.kwin");
35 QString model = QStringLiteral(
"none");
37 SubPixel subPixel = SubPixel::Unknown;
42 DpmsMode mode = DpmsMode::On;
43 bool supported =
false;
46 static OutputInterface *
get(wl_resource *native);
49 static Private *cast(wl_resource *native);
50 static void releaseCallback(wl_client *client, wl_resource *resource);
51 static void unbind(wl_resource *resource);
52 void bind(wl_client *client, uint32_t version, uint32_t
id)
override;
53 int32_t toTransform()
const;
54 int32_t toSubPixel()
const;
55 void sendGeometry(wl_resource *resource);
56 void sendScale(
const ResourceData &data);
60 static const struct wl_output_interface s_interface;
61 static const quint32 s_version;
65 const quint32 OutputInterface::Private::s_version = 3;
67 OutputInterface::Private::Private(OutputInterface *q, Display *d)
68 : Global::Private(d, &wl_output_interface, s_version)
74 OutputInterface::Private::~Private()
76 s_privates.removeAll(
this);
80 const struct wl_output_interface OutputInterface::Private::s_interface = {releaseCallback};
83 void OutputInterface::Private::releaseCallback(wl_client *client, wl_resource *resource)
91 if (Private *p = cast(native)) {
97 OutputInterface::Private *OutputInterface::Private::cast(wl_resource *native)
99 for (
auto it = s_privates.constBegin(); it != s_privates.constEnd(); ++it) {
100 const auto &resources = (*it)->resources;
101 auto rit = std::find_if(resources.constBegin(), resources.constEnd(), [native](
const ResourceData &data) {
102 return data.resource == native;
104 if (rit != resources.constEnd()) {
111 OutputInterface::OutputInterface(Display *display,
QObject *parent)
112 : Global(new Private(this, display), parent)
115 connect(
this, &OutputInterface::currentModeChanged,
this, [
this] {
117 auto currentModeIt = std::find_if(d->modes.constBegin(), d->modes.constEnd(), [](
const Mode &mode) {
118 return mode.flags.testFlag(ModeFlag::Current);
120 if (currentModeIt == d->modes.constEnd()) {
123 for (
auto it = d->resources.constBegin(); it != d->resources.constEnd(); ++it) {
124 d->sendMode((*it).resource, *currentModeIt);
127 wl_display_flush_clients(*(d->display));
129 connect(
this, &OutputInterface::subPixelChanged,
this, [d] {
132 connect(
this, &OutputInterface::transformChanged,
this, [d] {
135 connect(
this, &OutputInterface::globalPositionChanged,
this, [d] {
138 connect(
this, &OutputInterface::modelChanged,
this, [d] {
141 connect(
this, &OutputInterface::manufacturerChanged,
this, [d] {
144 connect(
this, &OutputInterface::scaleChanged,
this, [d] {
149 OutputInterface::~OutputInterface() =
default;
151 QSize OutputInterface::pixelSize()
const
154 auto it = std::find_if(d->modes.constBegin(), d->modes.constEnd(), [](
const Mode &mode) {
155 return mode.flags.testFlag(ModeFlag::Current);
157 if (it == d->modes.constEnd()) {
163 int OutputInterface::refreshRate()
const
166 auto it = std::find_if(d->modes.constBegin(), d->modes.constEnd(), [](
const Mode &mode) {
167 return mode.flags.testFlag(ModeFlag::Current);
169 if (it == d->modes.constEnd()) {
172 return (*it).refreshRate;
175 void OutputInterface::addMode(
const QSize &size, OutputInterface::ModeFlags flags,
int refreshRate)
180 auto currentModeIt = std::find_if(d->modes.begin(), d->modes.end(), [](
const Mode &mode) {
181 return mode.flags.testFlag(ModeFlag::Current);
183 if (currentModeIt == d->modes.end() && !flags.testFlag(ModeFlag::Current)) {
185 flags |= ModeFlag::Current;
187 if (currentModeIt != d->modes.end() && flags.testFlag(ModeFlag::Current)) {
189 (*currentModeIt).flags &= ~uint(ModeFlag::Current);
192 if (flags.testFlag(ModeFlag::Preferred)) {
194 auto preferredIt = std::find_if(d->modes.begin(), d->modes.end(), [](
const Mode &mode) {
195 return mode.flags.testFlag(ModeFlag::Preferred);
197 if (preferredIt != d->modes.end()) {
198 (*preferredIt).flags &= ~uint(ModeFlag::Preferred);
202 auto existingModeIt = std::find_if(d->modes.begin(), d->modes.end(), [size, refreshRate](
const Mode &mode) {
203 return mode.size == size && mode.refreshRate == refreshRate;
205 auto emitChanges = [
this, flags, size, refreshRate] {
206 Q_EMIT modesChanged();
207 if (flags.testFlag(ModeFlag::Current)) {
208 Q_EMIT refreshRateChanged(refreshRate);
209 Q_EMIT pixelSizeChanged(size);
210 Q_EMIT currentModeChanged();
213 if (existingModeIt != d->modes.end()) {
214 if ((*existingModeIt).flags == flags) {
218 (*existingModeIt).flags = flags;
224 mode.refreshRate = refreshRate;
230 void OutputInterface::setCurrentMode(
const QSize &size,
int refreshRate)
233 auto currentModeIt = std::find_if(d->modes.begin(), d->modes.end(), [](
const Mode &mode) {
234 return mode.flags.testFlag(ModeFlag::Current);
236 if (currentModeIt != d->modes.end()) {
238 (*currentModeIt).flags &= ~uint(ModeFlag::Current);
241 auto existingModeIt = std::find_if(d->modes.begin(), d->modes.end(), [size, refreshRate](
const Mode &mode) {
242 return mode.size == size && mode.refreshRate == refreshRate;
245 Q_ASSERT(existingModeIt != d->modes.end());
246 (*existingModeIt).flags |= ModeFlag::Current;
247 Q_EMIT modesChanged();
248 Q_EMIT refreshRateChanged((*existingModeIt).refreshRate);
249 Q_EMIT pixelSizeChanged((*existingModeIt).size);
250 Q_EMIT currentModeChanged();
253 int32_t OutputInterface::Private::toTransform()
const
256 case Transform::Normal:
257 return WL_OUTPUT_TRANSFORM_NORMAL;
258 case Transform::Rotated90:
259 return WL_OUTPUT_TRANSFORM_90;
260 case Transform::Rotated180:
261 return WL_OUTPUT_TRANSFORM_180;
262 case Transform::Rotated270:
263 return WL_OUTPUT_TRANSFORM_270;
264 case Transform::Flipped:
265 return WL_OUTPUT_TRANSFORM_FLIPPED;
266 case Transform::Flipped90:
267 return WL_OUTPUT_TRANSFORM_FLIPPED_90;
268 case Transform::Flipped180:
269 return WL_OUTPUT_TRANSFORM_FLIPPED_180;
270 case Transform::Flipped270:
271 return WL_OUTPUT_TRANSFORM_FLIPPED_270;
276 int32_t OutputInterface::Private::toSubPixel()
const
279 case SubPixel::Unknown:
280 return WL_OUTPUT_SUBPIXEL_UNKNOWN;
282 return WL_OUTPUT_SUBPIXEL_NONE;
283 case SubPixel::HorizontalRGB:
284 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
285 case SubPixel::HorizontalBGR:
286 return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
287 case SubPixel::VerticalRGB:
288 return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
289 case SubPixel::VerticalBGR:
290 return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
295 void OutputInterface::Private::bind(wl_client *client, uint32_t version, uint32_t
id)
297 auto c = display->getConnection(client);
298 wl_resource *resource = c->createResource(&wl_output_interface, qMin(version, s_version),
id);
300 wl_client_post_no_memory(client);
303 wl_resource_set_user_data(resource,
this);
304 wl_resource_set_implementation(resource, &s_interface,
this, unbind);
306 r.resource = resource;
310 sendGeometry(resource);
313 auto currentModeIt = modes.constEnd();
314 for (
auto it = modes.constBegin(); it != modes.constEnd(); ++it) {
315 const Mode &mode = *it;
316 if (mode.flags.testFlag(ModeFlag::Current)) {
321 sendMode(resource, mode);
324 if (currentModeIt != modes.constEnd()) {
325 sendMode(resource, *currentModeIt);
332 void OutputInterface::Private::unbind(wl_resource *resource)
334 Private *o = cast(resource);
338 auto it = std::find_if(o->resources.begin(), o->resources.end(), [resource](
const ResourceData &r) {
339 return r.resource == resource;
341 if (it != o->resources.end()) {
342 o->resources.erase(it);
346 void OutputInterface::Private::sendMode(wl_resource *resource,
const Mode &mode)
349 if (mode.flags.testFlag(ModeFlag::Current)) {
350 flags |= WL_OUTPUT_MODE_CURRENT;
352 if (mode.flags.testFlag(ModeFlag::Preferred)) {
353 flags |= WL_OUTPUT_MODE_PREFERRED;
355 wl_output_send_mode(resource, flags, mode.size.width(), mode.size.height(), mode.refreshRate);
358 void OutputInterface::Private::sendGeometry(wl_resource *resource)
360 wl_output_send_geometry(resource,
363 physicalSize.width(),
364 physicalSize.height(),
366 qPrintable(manufacturer),
371 void OutputInterface::Private::sendScale(
const ResourceData &data)
373 if (data.version < 2) {
376 wl_output_send_scale(data.resource, scale);
379 void OutputInterface::Private::sendDone(
const ResourceData &data)
381 if (data.version < 2) {
384 wl_output_send_done(data.resource);
387 void OutputInterface::Private::updateGeometry()
389 for (
auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
390 sendGeometry((*it).resource);
395 void OutputInterface::Private::updateScale()
397 for (
auto it = resources.constBegin(); it != resources.constEnd(); ++it) {
404 #define SETTER(setterName, type, argumentName) \
405 void OutputInterface::setterName(type arg) \
408 if (d->argumentName == arg) { \
411 d->argumentName = arg; \
412 Q_EMIT argumentName##Changed(d->argumentName); \
416 SETTER(setPhysicalSize,
const QSize &, physicalSize)
417 SETTER(setGlobalPosition,
const QPoint &, globalPosition)
418 SETTER(setManufacturer,
const QString &, manufacturer)
419 SETTER(setModel,
const QString &, model)
420 SETTER(setScale,
int, scale)
421 SETTER(setSubPixel, SubPixel, subPixel)
422 SETTER(setTransform, Transform, transform)
426 QSize OutputInterface::physicalSize()
const
429 return d->physicalSize;
432 QPoint OutputInterface::globalPosition()
const
435 return d->globalPosition;
438 QString OutputInterface::manufacturer()
const
441 return d->manufacturer;
444 QString OutputInterface::model()
const
450 int OutputInterface::scale()
const
456 OutputInterface::SubPixel OutputInterface::subPixel()
const
462 OutputInterface::Transform OutputInterface::transform()
const
474 void OutputInterface::setDpmsMode(OutputInterface::DpmsMode mode)
477 if (d->dpms.mode == mode) {
481 Q_EMIT dpmsModeChanged();
484 void OutputInterface::setDpmsSupported(
bool supported)
487 if (d->dpms.supported == supported) {
490 d->dpms.supported = supported;
491 Q_EMIT dpmsSupportedChanged();
494 OutputInterface::DpmsMode OutputInterface::dpmsMode()
const
500 bool OutputInterface::isDpmsSupported()
const
503 return d->dpms.supported;
510 for (
auto it = d->resources.constBegin(), end = d->resources.constEnd(); it != end; ++it) {
511 if (wl_resource_get_client((*it).resource) == client->
client()) {
512 ret << (*it).resource;
523 OutputInterface::Private *OutputInterface::d_func()
const
525 return reinterpret_cast<Private *
>(d.data());