1 /********************************************************************
2 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include "wlr_output_configuration_v1.h"
21
22 #include "event_queue.h"
23 #include "wayland_pointer_p.h"
24 #include "wlr_output_manager_v1.h"
25
26 #include "wayland-wlr-output-management-v1-client-protocol.h"
27
28 #include <memory>
29 #include <vector>
30
31 namespace Wrapland
32 {
33 namespace Client
34 {
35
36 struct ConfigurationHead {
37 WlrOutputHeadV1* head = nullptr;
38 zwlr_output_configuration_head_v1* native = nullptr;
39
40 WlrOutputModeV1* mode = nullptr;
41
42 struct {
43 QSize size;
44 int refresh = -1;
45 } customMode;
46
47 QPoint position;
48 bool positionSet = false;
49 WlrOutputHeadV1::Transform transform = WlrOutputHeadV1::Transform::Normal;
50 bool transformSet = false;
51 double scale = 1.;
52 bool scaleSet = false;
53 };
54
55 class Q_DECL_HIDDEN WlrOutputConfigurationV1::Private
56 {
57 public:
58 Private() = default;
59
60 void setup(zwlr_output_configuration_v1* outputConfiguration);
61
62 WaylandPointer<zwlr_output_configuration_v1, zwlr_output_configuration_v1_destroy>
63 outputConfiguration;
64 static const struct zwlr_output_configuration_v1_listener s_listener;
65 EventQueue* queue = nullptr;
66
67 void send();
68 ConfigurationHead* getConfigurationHead(WlrOutputHeadV1* head);
69
70 std::vector<std::unique_ptr<ConfigurationHead>> heads;
71 WlrOutputConfigurationV1* q;
72
73 private:
74 static void succeededCallback(void* data, zwlr_output_configuration_v1* config);
75 static void failedCallback(void* data, zwlr_output_configuration_v1* config);
76 static void cancelledCallback(void* data, zwlr_output_configuration_v1* config);
77 };
78
79 const zwlr_output_configuration_v1_listener WlrOutputConfigurationV1::Private::s_listener = {
80 succeededCallback,
81 failedCallback,
82 cancelledCallback,
83 };
84
succeededCallback(void * data,zwlr_output_configuration_v1 * config)85 void WlrOutputConfigurationV1::Private::succeededCallback(void* data,
86 zwlr_output_configuration_v1* config)
87 {
88 Q_UNUSED(config);
89 auto priv = reinterpret_cast<WlrOutputConfigurationV1::Private*>(data);
90 Q_EMIT priv->q->succeeded();
91 }
92
failedCallback(void * data,zwlr_output_configuration_v1 * config)93 void WlrOutputConfigurationV1::Private::failedCallback(void* data,
94 zwlr_output_configuration_v1* config)
95 {
96 Q_UNUSED(config);
97 auto priv = reinterpret_cast<WlrOutputConfigurationV1::Private*>(data);
98 Q_EMIT priv->q->failed();
99 }
100
cancelledCallback(void * data,zwlr_output_configuration_v1 * config)101 void WlrOutputConfigurationV1::Private::cancelledCallback(void* data,
102 zwlr_output_configuration_v1* config)
103 {
104 Q_UNUSED(config);
105 auto priv = reinterpret_cast<WlrOutputConfigurationV1::Private*>(data);
106 Q_EMIT priv->q->cancelled();
107 }
108
WlrOutputConfigurationV1(QObject * parent)109 WlrOutputConfigurationV1::WlrOutputConfigurationV1(QObject* parent)
110 : QObject(parent)
111 , d(new Private)
112 {
113 d->q = this;
114 }
115
~WlrOutputConfigurationV1()116 WlrOutputConfigurationV1::~WlrOutputConfigurationV1()
117 {
118 release();
119 }
120
setup(zwlr_output_configuration_v1 * outputConfiguration)121 void WlrOutputConfigurationV1::setup(zwlr_output_configuration_v1* outputConfiguration)
122 {
123 Q_ASSERT(outputConfiguration);
124 Q_ASSERT(!d->outputConfiguration);
125
126 d->outputConfiguration.setup(outputConfiguration);
127 d->setup(outputConfiguration);
128 }
129
setup(zwlr_output_configuration_v1 * outputConfiguration)130 void WlrOutputConfigurationV1::Private::setup(zwlr_output_configuration_v1* outputConfiguration)
131 {
132 zwlr_output_configuration_v1_add_listener(outputConfiguration, &s_listener, this);
133 }
134
getConfigurationHead(WlrOutputHeadV1 * head)135 ConfigurationHead* WlrOutputConfigurationV1::Private::getConfigurationHead(WlrOutputHeadV1* head)
136 {
137 for (auto& configurationHead : heads) {
138 if (configurationHead->head == head) {
139 return configurationHead.get();
140 }
141 }
142
143 // Create a new configuration head struct and hand a reference back by calling this function
144 // again.
145 std::unique_ptr<ConfigurationHead> configurationHead(new ConfigurationHead);
146 configurationHead->head = head;
147 heads.push_back(std::move(configurationHead));
148
149 return getConfigurationHead(head);
150 }
151
send()152 void WlrOutputConfigurationV1::Private::send()
153 {
154 for (auto& head : heads) {
155 if (!head->native) {
156 continue;
157 }
158
159 if (head->mode) {
160 zwlr_output_configuration_head_v1_set_mode(head->native, *head->mode);
161 } else if (head->customMode.refresh >= 0 && head->customMode.size.isValid()) {
162 zwlr_output_configuration_head_v1_set_custom_mode(head->native,
163 head->customMode.size.width(),
164 head->customMode.size.height(),
165 head->customMode.refresh);
166 }
167
168 if (head->positionSet) {
169 zwlr_output_configuration_head_v1_set_position(
170 head->native, head->position.x(), head->position.y());
171 }
172
173 if (head->transformSet) {
174 auto toNative = [](WlrOutputHeadV1::Transform transform) {
175 switch (transform) {
176 case WlrOutputHeadV1::Transform::Normal:
177 return WL_OUTPUT_TRANSFORM_NORMAL;
178 case WlrOutputHeadV1::Transform::Rotated90:
179 return WL_OUTPUT_TRANSFORM_90;
180 case WlrOutputHeadV1::Transform::Rotated180:
181 return WL_OUTPUT_TRANSFORM_180;
182 case WlrOutputHeadV1::Transform::Rotated270:
183 return WL_OUTPUT_TRANSFORM_270;
184 case WlrOutputHeadV1::Transform::Flipped:
185 return WL_OUTPUT_TRANSFORM_FLIPPED;
186 case WlrOutputHeadV1::Transform::Flipped90:
187 return WL_OUTPUT_TRANSFORM_FLIPPED_90;
188 case WlrOutputHeadV1::Transform::Flipped180:
189 return WL_OUTPUT_TRANSFORM_FLIPPED_180;
190 case WlrOutputHeadV1::Transform::Flipped270:
191 return WL_OUTPUT_TRANSFORM_FLIPPED_270;
192 }
193 abort();
194 };
195 zwlr_output_configuration_head_v1_set_transform(head->native,
196 toNative(head->transform));
197 }
198
199 if (head->scaleSet) {
200 zwlr_output_configuration_head_v1_set_scale(head->native,
201 wl_fixed_from_double(head->scale));
202 }
203 }
204 }
205
release()206 void WlrOutputConfigurationV1::release()
207 {
208 d->outputConfiguration.release();
209 }
210
setEventQueue(EventQueue * queue)211 void WlrOutputConfigurationV1::setEventQueue(EventQueue* queue)
212 {
213 d->queue = queue;
214 }
215
eventQueue()216 EventQueue* WlrOutputConfigurationV1::eventQueue()
217 {
218 return d->queue;
219 }
220
operator zwlr_output_configuration_v1*()221 WlrOutputConfigurationV1::operator zwlr_output_configuration_v1*()
222 {
223 return d->outputConfiguration;
224 }
225
operator zwlr_output_configuration_v1*() const226 WlrOutputConfigurationV1::operator zwlr_output_configuration_v1*() const
227 {
228 return d->outputConfiguration;
229 }
230
isValid() const231 bool WlrOutputConfigurationV1::isValid() const
232 {
233 return d->outputConfiguration.isValid();
234 }
235
setEnabled(WlrOutputHeadV1 * head,bool enable)236 void WlrOutputConfigurationV1::setEnabled(WlrOutputHeadV1* head, bool enable)
237 {
238 auto configurationHead = d->getConfigurationHead(head);
239
240 if (enable) {
241 if (!configurationHead->native) {
242 configurationHead->native
243 = zwlr_output_configuration_v1_enable_head(d->outputConfiguration, *head);
244 }
245 } else {
246 zwlr_output_configuration_v1_disable_head(d->outputConfiguration, *head);
247 }
248 }
249
setMode(WlrOutputHeadV1 * head,WlrOutputModeV1 * mode)250 void WlrOutputConfigurationV1::setMode(WlrOutputHeadV1* head, WlrOutputModeV1* mode)
251 {
252 d->getConfigurationHead(head)->mode = mode;
253 }
254
setTransform(WlrOutputHeadV1 * head,WlrOutputHeadV1::Transform transform)255 void WlrOutputConfigurationV1::setTransform(WlrOutputHeadV1* head,
256 WlrOutputHeadV1::Transform transform)
257 {
258 auto configurationHead = d->getConfigurationHead(head);
259
260 configurationHead->transform = transform;
261 configurationHead->transformSet = true;
262 }
263
setPosition(WlrOutputHeadV1 * head,const QPoint & pos)264 void WlrOutputConfigurationV1::setPosition(WlrOutputHeadV1* head, const QPoint& pos)
265 {
266 auto configurationHead = d->getConfigurationHead(head);
267
268 configurationHead->position = pos;
269 configurationHead->positionSet = true;
270 }
271
setScale(WlrOutputHeadV1 * head,double scale)272 void WlrOutputConfigurationV1::setScale(WlrOutputHeadV1* head, double scale)
273 {
274 auto configurationHead = d->getConfigurationHead(head);
275
276 configurationHead->scale = scale;
277 configurationHead->scaleSet = true;
278 }
279
test()280 void WlrOutputConfigurationV1::test()
281 {
282 d->send();
283 zwlr_output_configuration_v1_test(d->outputConfiguration);
284 }
285
apply()286 void WlrOutputConfigurationV1::apply()
287 {
288 d->send();
289 zwlr_output_configuration_v1_apply(d->outputConfiguration);
290 }
291
292 }
293 }
294