1 /*
2     SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3     SPDX-FileCopyrightText: 2015 Sebastian Kügler <sebas@kde.org>
4     SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
5 
6     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7 */
8 #include "display.h"
9 #include "outputconfiguration_v2_interface.h"
10 #include "outputdevice_v2_interface.h"
11 #include "logging.h"
12 #include "outputchangeset_v2_p.h"
13 
14 #include "qwayland-server-kde-output-management-v2.h"
15 #include "qwayland-server-kde-output-device-v2.h"
16 
17 namespace KWaylandServer
18 {
19 class OutputConfigurationV2InterfacePrivate : public QtWaylandServer::kde_output_configuration_v2
20 {
21 public:
22     OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface *q, OutputManagementV2Interface *outputManagement, wl_resource *resource);
23 
24     void sendApplied();
25     void sendFailed();
26     void emitConfigurationChangeRequested() const;
27     void clearPendingChanges();
28 
29     bool hasPendingChanges(OutputDeviceV2Interface *outputdevice) const;
30     OutputChangeSetV2 *pendingChanges(OutputDeviceV2Interface *outputdevice);
31 
32     OutputManagementV2Interface *outputManagement;
33     QHash<OutputDeviceV2Interface *, OutputChangeSetV2 *> changes;
34     OutputConfigurationV2Interface *q;
35 
36 protected:
37     void kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable) override;
38     void kde_output_configuration_v2_mode(Resource *resource, struct ::wl_resource *outputdevice, struct ::wl_resource *mode) override;
39     void kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform) override;
40     void kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y) override;
41     void kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale) override;
42     void kde_output_configuration_v2_apply(Resource *resource) override;
43     void kde_output_configuration_v2_destroy(Resource *resource) override;
44     void kde_output_configuration_v2_destroy_resource(Resource *resource) override;
45     void kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan) override;
46     void kde_output_configuration_v2_set_vrr_policy(Resource *resource, struct ::wl_resource *outputdevice, uint32_t policy) override;
47     void kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange) override;
48 };
49 
kde_output_configuration_v2_enable(Resource * resource,wl_resource * outputdevice,int32_t enable)50 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_enable(Resource *resource, wl_resource *outputdevice, int32_t enable)
51 {
52     Q_UNUSED(resource)
53 
54     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
55     pendingChanges(output)->d->enabled = enable == 1;
56 }
57 
kde_output_configuration_v2_mode(Resource * resource,wl_resource * outputdevice,wl_resource * modeResource)58 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_mode(Resource *resource, wl_resource *outputdevice, wl_resource *modeResource)
59 {
60     Q_UNUSED(resource)
61     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
62     OutputDeviceModeV2Interface *mode = OutputDeviceModeV2Interface::get(modeResource);
63 
64     pendingChanges(output)->d->size = mode->size();
65     pendingChanges(output)->d->refreshRate = mode->refreshRate();
66 }
67 
kde_output_configuration_v2_transform(Resource * resource,wl_resource * outputdevice,int32_t transform)68 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_transform(Resource *resource, wl_resource *outputdevice, int32_t transform)
69 {
70     Q_UNUSED(resource)
71     auto toTransform = [transform]() {
72         switch (transform) {
73             case WL_OUTPUT_TRANSFORM_90:
74                 return OutputDeviceV2Interface::Transform::Rotated90;
75             case WL_OUTPUT_TRANSFORM_180:
76                 return OutputDeviceV2Interface::Transform::Rotated180;
77             case WL_OUTPUT_TRANSFORM_270:
78                 return OutputDeviceV2Interface::Transform::Rotated270;
79             case WL_OUTPUT_TRANSFORM_FLIPPED:
80                 return OutputDeviceV2Interface::Transform::Flipped;
81             case WL_OUTPUT_TRANSFORM_FLIPPED_90:
82                 return OutputDeviceV2Interface::Transform::Flipped90;
83             case WL_OUTPUT_TRANSFORM_FLIPPED_180:
84                 return OutputDeviceV2Interface::Transform::Flipped180;
85             case WL_OUTPUT_TRANSFORM_FLIPPED_270:
86                 return OutputDeviceV2Interface::Transform::Flipped270;
87             case WL_OUTPUT_TRANSFORM_NORMAL:
88             default:
89                 return OutputDeviceV2Interface::Transform::Normal;
90         }
91     };
92     auto _transform = toTransform();
93     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
94     pendingChanges(output)->d->transform = _transform;
95 }
96 
kde_output_configuration_v2_position(Resource * resource,wl_resource * outputdevice,int32_t x,int32_t y)97 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_position(Resource *resource, wl_resource *outputdevice, int32_t x, int32_t y)
98 {
99     Q_UNUSED(resource)
100     auto _pos = QPoint(x, y);
101     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
102     pendingChanges(output)->d->position = _pos;
103 }
104 
kde_output_configuration_v2_scale(Resource * resource,wl_resource * outputdevice,wl_fixed_t scale)105 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_scale(Resource *resource, wl_resource *outputdevice, wl_fixed_t scale)
106 {
107     Q_UNUSED(resource)
108     const qreal doubleScale = wl_fixed_to_double(scale);
109 
110     if (doubleScale <= 0) {
111         qCWarning(KWAYLAND_SERVER) << "Requested to scale output device to" << doubleScale << ", but I can't do that.";
112         return;
113     }
114     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
115 
116     pendingChanges(output)->d->scale = doubleScale;
117 }
118 
kde_output_configuration_v2_apply(Resource * resource)119 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_apply(Resource *resource)
120 {
121     Q_UNUSED(resource)
122     emitConfigurationChangeRequested();
123 }
124 
kde_output_configuration_v2_overscan(Resource * resource,wl_resource * outputdevice,uint32_t overscan)125 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_overscan(Resource *resource, wl_resource *outputdevice, uint32_t overscan)
126 {
127     Q_UNUSED(resource)
128     if (overscan > 100) {
129         qCWarning(KWAYLAND_SERVER) << "Invalid overscan requested:" << overscan;
130         return;
131     }
132     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
133     pendingChanges(output)->d->overscan = overscan;
134 }
135 
kde_output_configuration_v2_set_vrr_policy(Resource * resource,wl_resource * outputdevice,uint32_t policy)136 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_vrr_policy(Resource *resource, wl_resource *outputdevice, uint32_t policy)
137 {
138     Q_UNUSED(resource)
139     if (policy > static_cast<uint32_t>(OutputDeviceV2Interface::VrrPolicy::Automatic)) {
140         qCWarning(KWAYLAND_SERVER) << "Invalid Vrr Policy requested:" << policy;
141         return;
142     }
143     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
144     pendingChanges(output)->d->vrrPolicy = static_cast<OutputDeviceV2Interface::VrrPolicy>(policy);
145 }
146 
kde_output_configuration_v2_set_rgb_range(Resource * resource,wl_resource * outputdevice,uint32_t rgbRange)147 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_set_rgb_range(Resource *resource, wl_resource *outputdevice, uint32_t rgbRange)
148 {
149     Q_UNUSED(resource)
150     if (rgbRange > static_cast<uint32_t>(OutputDeviceV2Interface::RgbRange::Limited)) {
151         qCWarning(KWAYLAND_SERVER) << "Invalid Rgb Range requested:" << rgbRange;
152         return;
153     }
154     OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice);
155     pendingChanges(output)->d->rgbRange = static_cast<OutputDeviceV2Interface::RgbRange>(rgbRange);
156 }
157 
kde_output_configuration_v2_destroy(Resource * resource)158 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy(Resource *resource)
159 {
160     wl_resource_destroy(resource->handle);
161 }
162 
kde_output_configuration_v2_destroy_resource(Resource * resource)163 void OutputConfigurationV2InterfacePrivate::kde_output_configuration_v2_destroy_resource(Resource *resource)
164 {
165     Q_UNUSED(resource)
166     delete q;
167 }
168 
emitConfigurationChangeRequested() const169 void OutputConfigurationV2InterfacePrivate::emitConfigurationChangeRequested() const
170 {
171     auto configinterface = reinterpret_cast<OutputConfigurationV2Interface *>(q);
172     Q_EMIT outputManagement->configurationChangeRequested(configinterface);
173 }
174 
OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface * q,OutputManagementV2Interface * outputManagement,wl_resource * resource)175 OutputConfigurationV2InterfacePrivate::OutputConfigurationV2InterfacePrivate(OutputConfigurationV2Interface *q, OutputManagementV2Interface *outputManagement, wl_resource *resource)
176     : QtWaylandServer::kde_output_configuration_v2(resource)
177     , outputManagement(outputManagement)
178     , q(q)
179 {
180 }
181 
changes() const182 QHash<OutputDeviceV2Interface*, OutputChangeSetV2*> OutputConfigurationV2Interface::changes() const
183 {
184     return d->changes;
185 }
186 
setApplied()187 void OutputConfigurationV2Interface::setApplied()
188 {
189     d->clearPendingChanges();
190     d->sendApplied();
191 }
192 
sendApplied()193 void OutputConfigurationV2InterfacePrivate::sendApplied()
194 {
195     send_applied();
196 }
197 
setFailed()198 void OutputConfigurationV2Interface::setFailed()
199 {
200     d->clearPendingChanges();
201     d->sendFailed();
202 }
203 
sendFailed()204 void OutputConfigurationV2InterfacePrivate::sendFailed()
205 {
206     send_failed();
207 }
208 
pendingChanges(OutputDeviceV2Interface * outputdevice)209 OutputChangeSetV2 *OutputConfigurationV2InterfacePrivate::pendingChanges(OutputDeviceV2Interface *outputdevice)
210 {
211     auto &change = changes[outputdevice];
212     if (!change) {
213         change = new OutputChangeSetV2(outputdevice, q);
214     }
215     return change;
216 }
217 
hasPendingChanges(OutputDeviceV2Interface * outputdevice) const218 bool OutputConfigurationV2InterfacePrivate::hasPendingChanges(OutputDeviceV2Interface *outputdevice) const
219 {
220     auto it = changes.constFind(outputdevice);
221     if (it == changes.constEnd()) {
222         return false;
223     }
224     auto c = *it;
225     return c->enabledChanged() ||
226     c->sizeChanged() ||
227     c->refreshRateChanged() ||
228     c->transformChanged() ||
229     c->positionChanged() ||
230     c->scaleChanged();
231 }
232 
clearPendingChanges()233 void OutputConfigurationV2InterfacePrivate::clearPendingChanges()
234 {
235     qDeleteAll(changes.begin(), changes.end());
236     changes.clear();
237 }
238 
OutputConfigurationV2Interface(OutputManagementV2Interface * parent,wl_resource * resource)239 OutputConfigurationV2Interface::OutputConfigurationV2Interface(OutputManagementV2Interface *parent, wl_resource *resource)
240     : QObject()
241     , d(new OutputConfigurationV2InterfacePrivate(this, parent, resource))
242 {
243 }
244 
~OutputConfigurationV2Interface()245 OutputConfigurationV2Interface::~OutputConfigurationV2Interface()
246 {
247     d->clearPendingChanges();
248 }
249 
250 }
251