GCC Code Coverage Report


Directory: ./
File: lib/configserializer.cpp
Date: 2023-04-20 22:59:23
Exec Total Coverage
Lines: 64 339 18.9%
Branches: 6 214 2.8%

Line Branch Exec Source
1 /*
2 * Copyright (C) 2014 Daniel Vratil <dvratil@redhat.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) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 */
19 #include "configserializer_p.h"
20
21 #include "config.h"
22 #include "disman_debug.h"
23 #include "mode.h"
24 #include "screen.h"
25
26 #include <QDBusArgument>
27 #include <QFile>
28 #include <QJsonDocument>
29 #include <QRect>
30
31 #include <string>
32 #include <vector>
33
34 using namespace Disman;
35
36 3 QJsonObject ConfigSerializer::serialize_point(const QPointF& point)
37 {
38 3 QJsonObject obj;
39 3 obj[QLatin1String("x")] = point.x();
40 3 obj[QLatin1String("y")] = point.y();
41 3 return obj;
42 }
43
44 11 QJsonObject ConfigSerializer::serialize_size(const QSize& size)
45 {
46 11 QJsonObject obj;
47 11 obj[QLatin1String("width")] = size.width();
48 11 obj[QLatin1String("height")] = size.height();
49 11 return obj;
50 }
51
52 QJsonObject ConfigSerializer::serialize_sizef(const QSizeF& size)
53 {
54 QJsonObject obj;
55 obj[QLatin1String("width")] = size.width();
56 obj[QLatin1String("height")] = size.height();
57 return obj;
58 }
59
60 QJsonObject ConfigSerializer::serialize_config(const ConfigPtr& config)
61 {
62 QJsonObject obj;
63
64 if (!config) {
65 return obj;
66 }
67
68 obj[QLatin1String("cause")] = static_cast<int>(config->cause());
69 obj[QLatin1String("features")] = static_cast<int>(config->supported_features());
70 if (auto primary = config->primary_output()) {
71 obj[QLatin1String("primary-output")] = primary->id();
72 }
73
74 QJsonArray outputs;
75 for (auto const& [key, output] : config->outputs()) {
76 outputs.append(serialize_output(output));
77 }
78 obj[QLatin1String("outputs")] = outputs;
79 if (config->screen()) {
80 obj[QLatin1String("screen")] = serialize_screen(config->screen());
81 }
82
83 obj[QLatin1String("tablet_mode_available")] = config->tablet_mode_available();
84 obj[QLatin1String("tablet_mode_engaged")] = config->tablet_mode_engaged();
85
86 return obj;
87 }
88
89 2 QJsonObject ConfigSerializer::serialize_output(const OutputPtr& output)
90 {
91 2 QJsonObject obj;
92
93 2 obj[QLatin1String("id")] = output->id();
94 2 obj[QLatin1String("name")] = QString::fromStdString(output->name());
95 2 obj[QLatin1String("description")] = QString::fromStdString(output->description());
96 2 obj[QLatin1String("hash")] = QString::fromStdString(output->hash());
97 2 obj[QLatin1String("type")] = static_cast<int>(output->type());
98 2 obj[QLatin1String("position")] = serialize_point(output->position());
99 2 obj[QLatin1String("scale")] = output->scale();
100 2 obj[QLatin1String("rotation")] = static_cast<int>(output->rotation());
101
102 2 auto const mode = output->auto_mode();
103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 assert(mode);
104 2 obj[QLatin1String("resolution")] = serialize_size(mode->size());
105 2 obj[QLatin1String("refresh")] = mode->refresh();
106
107 2 QStringList mode_q_strings;
108
2/2
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
4 for (auto const& mode_string : output->preferred_modes()) {
109 2 mode_q_strings.push_back(QString::fromStdString(mode_string));
110 }
111 2 obj[QLatin1String("preferred_modes")] = serialize_list(mode_q_strings);
112
113 2 obj[QLatin1String("follow_preferred_mode")] = output->follow_preferred_mode();
114 2 obj[QLatin1String("enabled")] = output->enabled();
115 2 obj[QLatin1String("physical_size")] = serialize_size(output->physical_size());
116 2 obj[QLatin1String("replication_source")] = output->replication_source();
117 2 obj[QLatin1String("auto_rotate")] = output->auto_rotate();
118 2 obj[QLatin1String("auto_rotate_only_in_tablet_mode")]
119 4 = output->auto_rotate_only_in_tablet_mode();
120 2 obj[QLatin1String("auto_resolution")] = output->auto_resolution();
121 2 obj[QLatin1String("auto_refresh_rate")] = output->auto_refresh_rate();
122 2 obj[QLatin1String("retention")] = static_cast<int>(output->retention());
123 2 obj[QLatin1String("adaptive_sync_toggle_support")] = output->adaptive_sync_toggle_support();
124 2 obj[QLatin1String("adaptive_sync")] = output->adaptive_sync();
125
126 2 QJsonArray modes;
127
2/2
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
4 for (auto const& [key, mode] : output->modes()) {
128 2 modes.append(serialize_mode(mode));
129 2 }
130 2 obj[QLatin1String("modes")] = modes;
131
132 2 auto data = output->global_data();
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (data.valid) {
134 obj[QLatin1String("global")] = true;
135
136 obj[QLatin1String("global.resolution")] = serialize_size(data.resolution);
137 obj[QLatin1String("global.refresh")] = data.refresh;
138
139 obj[QLatin1String("global.rotation")] = data.rotation;
140 obj[QLatin1String("global.scale")] = data.scale;
141
142 obj[QLatin1String("global.auto_resolution")] = data.auto_resolution;
143 obj[QLatin1String("global.auto_refresh_rate")] = data.auto_refresh_rate;
144
145 obj[QLatin1String("global.auto_rotate")] = data.auto_rotate;
146 obj[QLatin1String("global.auto_rotate_only_in_tablet_mode")]
147 = data.auto_rotate_only_in_tablet_mode;
148 }
149
150 2 return obj;
151 2 }
152
153 3 QJsonObject ConfigSerializer::serialize_mode(const ModePtr& mode)
154 {
155 3 QJsonObject obj;
156
157 3 obj[QLatin1String("id")] = QString::fromStdString(mode->id());
158 3 obj[QLatin1String("name")] = QString::fromStdString(mode->name());
159 3 obj[QLatin1String("size")] = serialize_size(mode->size());
160 3 obj[QLatin1String("refresh")] = mode->refresh();
161
162 3 return obj;
163 }
164
165 1 QJsonObject ConfigSerializer::serialize_screen(const ScreenPtr& screen)
166 {
167 1 QJsonObject obj;
168
169 1 obj[QLatin1String("id")] = screen->id();
170 1 obj[QLatin1String("current_size")] = serialize_size(screen->current_size());
171 1 obj[QLatin1String("max_size")] = serialize_size(screen->max_size());
172 1 obj[QLatin1String("min_size")] = serialize_size(screen->min_size());
173 1 obj[QLatin1String("max_outputs_count")] = screen->max_outputs_count();
174
175 1 return obj;
176 }
177
178 QPointF ConfigSerializer::deserialize_point(const QDBusArgument& arg)
179 {
180 double x = 0;
181 double y = 0;
182 arg.beginMap();
183
184 while (!arg.atEnd()) {
185 QString key;
186 QVariant value;
187 arg.beginMapEntry();
188 arg >> key >> value;
189 if (key == QLatin1Char('x')) {
190 x = value.toDouble();
191 } else if (key == QLatin1Char('y')) {
192 y = value.toDouble();
193 } else {
194 qCWarning(DISMAN) << "Invalid key in Point map: " << key;
195 return QPointF();
196 }
197 arg.endMapEntry();
198 }
199
200 arg.endMap();
201 return QPointF(x, y);
202 }
203
204 Output::Retention ConfigSerializer::deserialize_retention(QVariant const& var)
205 {
206 if (var.canConvert<int>()) {
207 auto val = var.toInt();
208 if (val == static_cast<int>(Output::Retention::Global)) {
209 return Output::Retention::Global;
210 }
211 if (val == static_cast<int>(Output::Retention::Individual)) {
212 return Output::Retention::Individual;
213 }
214 }
215 return Output::Retention::Undefined;
216 }
217
218 QSize ConfigSerializer::deserialize_size(const QDBusArgument& arg)
219 {
220 int w = 0, h = 0;
221 arg.beginMap();
222 while (!arg.atEnd()) {
223 QString key;
224 QVariant value;
225 arg.beginMapEntry();
226 arg >> key >> value;
227 if (key == QLatin1String("width")) {
228 w = value.toInt();
229 } else if (key == QLatin1String("height")) {
230 h = value.toInt();
231 } else {
232 qCWarning(DISMAN) << "Invalid key in size struct: " << key;
233 return QSize();
234 }
235 arg.endMapEntry();
236 }
237 arg.endMap();
238
239 return QSize(w, h);
240 }
241
242 QSizeF ConfigSerializer::deserialize_sizef(const QDBusArgument& arg)
243 {
244 double w = 0;
245 double h = 0;
246 arg.beginMap();
247 while (!arg.atEnd()) {
248 QString key;
249 QVariant value;
250 arg.beginMapEntry();
251 arg >> key >> value;
252 if (key == QLatin1String("width")) {
253 w = value.toDouble();
254 } else if (key == QLatin1String("height")) {
255 h = value.toDouble();
256 } else {
257 qCWarning(DISMAN) << "Invalid key in size struct: " << key;
258 return QSize();
259 }
260 arg.endMapEntry();
261 }
262 arg.endMap();
263
264 return QSizeF(w, h);
265 }
266
267 ConfigPtr ConfigSerializer::deserialize_config(const QVariantMap& map)
268 {
269 auto cause = static_cast<Config::Cause>(
270 map.value(QStringLiteral("cause"), static_cast<int>(Config::Cause::unknown)).toInt());
271 switch (cause) {
272 case Config::Cause::unknown:
273 case Config::Cause::generated:
274 case Config::Cause::file:
275 case Config::Cause::interactive:
276 break;
277 default:
278 qCWarning(DISMAN) << "Deserialized config without valid cause value.";
279 cause = Config::Cause::unknown;
280 }
281
282 ConfigPtr config(new Config(cause));
283
284 if (map.contains(QLatin1String("features"))) {
285 config->set_supported_features(
286 static_cast<Config::Features>(map[QStringLiteral("features")].toInt()));
287 }
288
289 if (map.contains(QLatin1String("tablet_mode_available"))) {
290 config->set_tablet_mode_available(map[QStringLiteral("tablet_mode_available")].toBool());
291 }
292 if (map.contains(QLatin1String("tablet_mode_engaged"))) {
293 config->set_tablet_mode_engaged(map[QStringLiteral("tablet_mode_engaged")].toBool());
294 }
295
296 if (map.contains(QLatin1String("outputs"))) {
297 const QDBusArgument& outputsArg = map[QStringLiteral("outputs")].value<QDBusArgument>();
298 outputsArg.beginArray();
299 OutputMap outputs;
300 while (!outputsArg.atEnd()) {
301 QVariant value;
302 outputsArg >> value;
303 const Disman::OutputPtr output = deserialize_output(value.value<QDBusArgument>());
304 if (!output) {
305 return ConfigPtr();
306 }
307 outputs.insert({output->id(), output});
308 }
309 outputsArg.endArray();
310 config->set_outputs(outputs);
311 }
312
313 if (map.contains(QLatin1String("primary-output"))) {
314 auto const id = map[QStringLiteral("primary-output")].toInt();
315 auto output = config->output(id);
316 if (!output) {
317 return ConfigPtr();
318 }
319 config->set_primary_output(output);
320 }
321
322 if (map.contains(QLatin1String("screen"))) {
323 const QDBusArgument& screenArg = map[QStringLiteral("screen")].value<QDBusArgument>();
324 const Disman::ScreenPtr screen = deserialize_screen(screenArg);
325 if (!screen) {
326 return ConfigPtr();
327 }
328 config->setScreen(screen);
329 }
330
331 return config;
332 }
333
334 OutputPtr ConfigSerializer::deserialize_output(const QDBusArgument& arg)
335 {
336 OutputPtr output(new Output);
337 Output::GlobalData global_data;
338
339 arg.beginMap();
340 while (!arg.atEnd()) {
341 QString key;
342 QVariant value;
343 arg.beginMapEntry();
344 arg >> key >> value;
345 if (key == QLatin1String("id")) {
346 output->set_id(value.toInt());
347 } else if (key == QLatin1String("name")) {
348 output->set_name(value.toString().toStdString());
349 } else if (key == QLatin1String("description")) {
350 output->set_description(value.toString().toStdString());
351 } else if (key == QLatin1String("hash")) {
352 output->set_hash_raw(value.toString().toStdString());
353 } else if (key == QLatin1String("type")) {
354 output->setType(static_cast<Output::Type>(value.toInt()));
355 } else if (key == QLatin1String("position")) {
356 output->set_position(deserialize_point(value.value<QDBusArgument>()));
357 } else if (key == QLatin1String("scale")) {
358 output->set_scale(value.toDouble());
359 } else if (key == QLatin1String("rotation")) {
360 output->set_rotation(static_cast<Output::Rotation>(value.toInt()));
361 } else if (key == QLatin1String("resolution")) {
362 output->set_resolution(deserialize_size(value.value<QDBusArgument>()));
363 } else if (key == QLatin1String("refresh")) {
364 output->set_refresh_rate(value.toInt());
365 } else if (key == QLatin1String("auto_rotate")) {
366 output->set_auto_rotate(value.toBool());
367 } else if (key == QLatin1String("auto_rotate_only_in_tablet_mode")) {
368 output->set_auto_rotate_only_in_tablet_mode(value.toBool());
369 } else if (key == QLatin1String("auto_resolution")) {
370 output->set_auto_resolution(value.toBool());
371 } else if (key == QLatin1String("auto_refresh_rate")) {
372 output->set_auto_refresh_rate(value.toBool());
373 } else if (key == QLatin1String("adaptive_sync_toggle_support")) {
374 output->set_adaptive_sync_toggle_support(value.toBool());
375 } else if (key == QLatin1String("adaptive_sync")) {
376 output->set_adaptive_sync(value.toBool());
377 }
378
379 else if (key == QLatin1String("global")) {
380 global_data.valid = true;
381 } else if (key == QLatin1String("global.resolution")) {
382 global_data.resolution = deserialize_size(value.value<QDBusArgument>());
383 } else if (key == QLatin1String("global.refresh")) {
384 global_data.refresh = value.toInt();
385 } else if (key == QLatin1String("global.rotation")) {
386 global_data.rotation = static_cast<Output::Rotation>(value.toInt());
387 } else if (key == QLatin1String("global.scale")) {
388 global_data.scale = value.toDouble();
389 } else if (key == QLatin1String("global.auto_resolution")) {
390 global_data.auto_resolution = value.toBool();
391 } else if (key == QLatin1String("global.auto_refresh_rate")) {
392 global_data.auto_refresh_rate = value.toBool();
393 } else if (key == QLatin1String("global.auto_rotate")) {
394 global_data.auto_rotate = value.toBool();
395 } else if (key == QLatin1String("global.auto_rotate_only_in_tablet_mode")) {
396 global_data.auto_rotate_only_in_tablet_mode = value.toBool();
397 }
398
399 else if (key == QLatin1String("preferred_modes")) {
400 auto q_strings = deserialize_list<QString>(value.value<QDBusArgument>());
401 std::vector<std::string> strings;
402 for (auto const& qs : q_strings) {
403 strings.push_back(qs.toStdString());
404 }
405 output->set_preferred_modes(strings);
406
407 } else if (key == QLatin1String("follow_preferred_mode")) {
408 output->set_follow_preferred_mode(value.toBool());
409 } else if (key == QLatin1String("enabled")) {
410 output->set_enabled(value.toBool());
411 } else if (key == QLatin1String("replication_source")) {
412 output->set_replication_source(value.toInt());
413 } else if (key == QLatin1String("physical_size")) {
414 output->set_physical_size(deserialize_size(value.value<QDBusArgument>()));
415 } else if (key == QLatin1String("retention")) {
416 output->set_retention(deserialize_retention(value));
417 } else if (key == QLatin1String("modes")) {
418 const QDBusArgument arg = value.value<QDBusArgument>();
419 ModeMap modes;
420 arg.beginArray();
421 while (!arg.atEnd()) {
422 QVariant value;
423 arg >> value;
424 const Disman::ModePtr mode = deserialize_mode(value.value<QDBusArgument>());
425 if (!mode) {
426 return OutputPtr();
427 }
428 modes.insert({mode->id(), mode});
429 }
430 arg.endArray();
431 output->set_modes(modes);
432 } else {
433 qCWarning(DISMAN) << "Invalid key in Output map: " << key;
434 return OutputPtr();
435 }
436 arg.endMapEntry();
437 }
438 arg.endMap();
439
440 if (global_data.valid) {
441 output->set_global_data(global_data);
442 }
443
444 return output;
445 }
446
447 ModePtr ConfigSerializer::deserialize_mode(const QDBusArgument& arg)
448 {
449 ModePtr mode(new Mode);
450
451 arg.beginMap();
452 while (!arg.atEnd()) {
453 QString key;
454 QVariant value;
455 arg.beginMapEntry();
456 arg >> key >> value;
457
458 if (key == QLatin1String("id")) {
459 mode->set_id(value.toString().toStdString());
460 } else if (key == QLatin1String("name")) {
461 mode->set_name(value.toString().toStdString());
462 } else if (key == QLatin1String("size")) {
463 mode->set_size(deserialize_size(value.value<QDBusArgument>()));
464 } else if (key == QLatin1String("refresh")) {
465 mode->set_refresh(value.toFloat());
466 } else {
467 qCWarning(DISMAN) << "Invalid key in Mode map: " << key;
468 return ModePtr();
469 }
470 arg.endMapEntry();
471 }
472 arg.endMap();
473 return mode;
474 }
475
476 ScreenPtr ConfigSerializer::deserialize_screen(const QDBusArgument& arg)
477 {
478 ScreenPtr screen(new Screen);
479
480 arg.beginMap();
481 QString key;
482 QVariant value;
483 while (!arg.atEnd()) {
484 arg.beginMapEntry();
485 arg >> key >> value;
486 if (key == QLatin1String("id")) {
487 screen->set_id(value.toInt());
488 } else if (key == QLatin1String("max_outputs_count")) {
489 screen->set_max_outputs_count(value.toInt());
490 } else if (key == QLatin1String("current_size")) {
491 screen->set_current_size(deserialize_size(value.value<QDBusArgument>()));
492 } else if (key == QLatin1String("max_size")) {
493 screen->set_max_size(deserialize_size(value.value<QDBusArgument>()));
494 } else if (key == QLatin1String("min_size")) {
495 screen->set_min_size(deserialize_size(value.value<QDBusArgument>()));
496 } else {
497 qCWarning(DISMAN) << "Invalid key in Screen map:" << key;
498 return ScreenPtr();
499 }
500 arg.endMapEntry();
501 }
502 arg.endMap();
503 return screen;
504 }
505