GCC Code Coverage Report


Directory: ./
File: backends/wayland/waylandoutput.cpp
Date: 2023-04-20 22:59:23
Exec Total Coverage
Lines: 106 122 86.9%
Branches: 37 62 59.7%

Line Branch Exec Source
1 /*************************************************************************
2 Copyright © 2014-2015 Sebastian Kügler <sebas@kde.org>
3 Copyright © 2019-2020 Roman Gilg <subdiff@gmail.com>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 **************************************************************************/
19 #include "waylandoutput.h"
20
21 #include "utils.h"
22 #include "wayland_interface.h"
23 #include "wayland_logging.h"
24
25 #include <QRectF>
26 #include <Wrapland/Client/wlr_output_configuration_v1.h>
27 #include <mode.h>
28
29 using namespace Disman;
30 namespace Wl = Wrapland::Client;
31
32 const std::map<Wl::WlrOutputHeadV1::Transform, Output::Rotation> s_rotationMap
33 = {{Wl::WlrOutputHeadV1::Transform::Normal, Output::None},
34 {Wl::WlrOutputHeadV1::Transform::Rotated90, Output::Right},
35 {Wl::WlrOutputHeadV1::Transform::Rotated180, Output::Inverted},
36 {Wl::WlrOutputHeadV1::Transform::Rotated270, Output::Left},
37 {Wl::WlrOutputHeadV1::Transform::Flipped, Output::None},
38 {Wl::WlrOutputHeadV1::Transform::Flipped90, Output::Right},
39 {Wl::WlrOutputHeadV1::Transform::Flipped180, Output::Inverted},
40 {Wl::WlrOutputHeadV1::Transform::Flipped270, Output::Left}};
41
42 1957 Output::Rotation toDismanRotation(const Wl::WlrOutputHeadV1::Transform transform)
43 {
44 1957 auto it = s_rotationMap.find(transform);
45
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1957 times.
1957 assert(it != s_rotationMap.end());
46 1957 return it->second;
47 }
48
49 4 Wl::WlrOutputHeadV1::Transform toWraplandTransform(const Output::Rotation rotation)
50 {
51
1/2
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
13 for (auto const& [key, val] : s_rotationMap) {
52
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (val == rotation) {
53 4 return key;
54 }
55 }
56 assert(false);
57 return Wl::WlrOutputHeadV1::Transform::Normal;
58 }
59
60 53 WaylandOutput::WaylandOutput(uint32_t id, Wrapland::Client::WlrOutputHeadV1& head)
61 53 : id{id}
62 53 , head{head}
63 {
64 53 connect(&head, &Wl::WlrOutputHeadV1::removed, this, &WaylandOutput::removed);
65 53 }
66
67 57 bool portraitMode(Wrapland::Client::WlrOutputHeadV1 const& head)
68 {
69 57 auto transform = head.transform();
70 return transform == Wl::WlrOutputHeadV1::Transform::Rotated90
71
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || transform == Wl::WlrOutputHeadV1::Transform::Rotated270
72
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 || transform == Wl::WlrOutputHeadV1::Transform::Flipped90
73
2/4
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 57 times.
114 || transform == Wl::WlrOutputHeadV1::Transform::Flipped270;
74 }
75
76 57 QRectF WaylandOutput::geometry() const
77 {
78 57 auto const current_mode = head.currentMode();
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (!current_mode) {
80 return QRectF();
81 }
82 57 auto modeSize = current_mode->size();
83
84 // Rotate and scale.
85
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
57 if (portraitMode(head)) {
86 modeSize.transpose();
87 }
88
89 57 modeSize = modeSize / head.scale();
90
91 57 return QRectF(head.position(), modeSize);
92 }
93
94 20969 QString modeName(const Wl::WlrOutputModeV1* mode)
95 {
96 41938 return QString::number(mode->size().width()) + QLatin1Char('x')
97 83876 + QString::number(mode->size().height()) + QLatin1Char('@')
98 62907 + QString::number(qRound(mode->refresh() / 1000.0));
99 }
100
101 635 OutputPtr WaylandOutput::toDismanOutput()
102 {
103 635 OutputPtr output(new Output());
104 635 output->set_id(id);
105 635 updateDismanOutput(output);
106 635 return output;
107 }
108
109 1631 void WaylandOutput::updateDismanOutput(OutputPtr& output)
110 {
111 // Initialize primary output
112 1631 output->set_enabled(head.enabled());
113 1631 output->set_name(head.name().toStdString());
114 1631 output->set_description(head.description().toStdString());
115 1631 output->set_hash(hash().toStdString());
116 1631 output->set_physical_size(head.physicalSize());
117 1631 output->set_position(head.position());
118 1631 output->set_rotation(toDismanRotation(head.transform()));
119 1631 output->set_adaptive_sync_toggle_support(supports_adapt_sync_toggle);
120 1631 output->set_adaptive_sync(head.adaptive_sync());
121
122 1631 ModeMap modeList;
123 1631 std::vector<std::string> preferredModeIds;
124 1631 m_modeIdMap.clear();
125
126 1631 auto current_head_mode = head.currentMode();
127 1631 ModePtr current_mode;
128
129 1631 int modeCounter = 0;
130 1631 auto const modes = head.modes();
131
2/2
✓ Branch 6 taken 20969 times.
✓ Branch 7 taken 1631 times.
22600 for (auto const& wlMode : qAsConst(modes)) {
132 20969 auto const modeId = std::to_string(++modeCounter);
133
134 20969 ModePtr mode(new Mode());
135
136 20969 mode->set_id(modeId);
137
138 // Wrapland gives the refresh rate as int in mHz.
139 20969 mode->set_refresh(wlMode->refresh());
140 20969 mode->set_size(wlMode->size());
141 20969 mode->set_name(modeName(wlMode).toStdString());
142
143
2/2
✓ Branch 1 taken 1631 times.
✓ Branch 2 taken 19338 times.
20969 if (wlMode->preferred()) {
144 1631 preferredModeIds.push_back(modeId);
145 }
146
2/2
✓ Branch 0 taken 1529 times.
✓ Branch 1 taken 19440 times.
20969 if (current_head_mode == wlMode) {
147 1529 current_mode = mode;
148 }
149
150 // Update the Disman => Wrapland mode id translation map.
151 20969 m_modeIdMap.insert({modeId, wlMode});
152
153 // Add to the modelist which gets set on the output.
154 20969 modeList[modeId] = mode;
155 20969 }
156
157 1631 output->set_preferred_modes(preferredModeIds);
158 1631 output->set_modes(modeList);
159
160
2/2
✓ Branch 0 taken 1529 times.
✓ Branch 1 taken 102 times.
1631 if (current_head_mode) {
161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1529 times.
1529 if (!current_mode) {
162 qCWarning(DISMAN_WAYLAND) << "Could not find the current mode in:";
163 for (auto const& [key, mode] : modeList) {
164 qCWarning(DISMAN_WAYLAND) << " " << mode;
165 }
166 } else {
167 1529 output->set_mode(current_mode);
168 1529 output->set_resolution(current_mode->size());
169
1/2
✗ Branch 4 not taken.
✓ Branch 5 taken 1529 times.
1529 if (!output->set_refresh_rate(current_mode->refresh())) {
170 qCWarning(DISMAN_WAYLAND) << "Failed setting the current mode:" << current_mode;
171 }
172 }
173 }
174
175 1631 output->set_scale(head.scale());
176 1631 output->setType(Utils::guessOutputType(head.name(), head.name()));
177 1631 }
178
179 366 bool WaylandOutput::setWlConfig(Wl::WlrOutputConfigurationV1* wlConfig,
180 const Disman::OutputPtr& output)
181 {
182 366 bool changed = false;
183
184 // enabled?
185
2/2
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 355 times.
366 if (head.enabled() != output->enabled()) {
186 11 changed = true;
187 }
188
189 // In any case set the enabled state to initialize the output's native handle.
190 366 wlConfig->setEnabled(&head, output->enabled());
191
192
2/2
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 326 times.
366 if (!output->enabled()) {
193 // A disabled head can not be configured in any way.
194 40 return changed;
195 }
196
197 // position
198
2/2
✓ Branch 5 taken 41 times.
✓ Branch 6 taken 285 times.
326 if (head.position() != output->position()) {
199 41 changed = true;
200 41 wlConfig->setPosition(&head, output->position().toPoint());
201 }
202
203 // scale
204
2/2
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 312 times.
326 if (!qFuzzyCompare(head.scale(), output->scale())) {
205 14 changed = true;
206 14 wlConfig->setScale(&head, output->scale());
207 }
208
209 // rotation
210
2/2
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 322 times.
326 if (toDismanRotation(head.transform()) != output->rotation()) {
211 4 changed = true;
212 4 wlConfig->setTransform(&head, toWraplandTransform(output->rotation()));
213 }
214
215 // mode
216
1/2
✓ Branch 8 taken 326 times.
✗ Branch 9 not taken.
326 if (auto mode_id = output->auto_mode()->id(); m_modeIdMap.find(mode_id) != m_modeIdMap.end()) {
217 326 auto newMode = m_modeIdMap.at(mode_id);
218
2/2
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 305 times.
326 if (newMode != head.currentMode()) {
219 21 changed = true;
220 21 wlConfig->setMode(&head, newMode);
221 }
222 } else {
223 qCWarning(DISMAN_WAYLAND) << "Invalid Disman mode:" << mode_id.c_str()
224 << "\n -> available were:";
225 for (auto const& [key, value] : m_modeIdMap) {
226 qCWarning(DISMAN_WAYLAND).nospace() << value << ": " << key.c_str();
227 }
228 326 }
229
230 // adaptive sync
231
2/2
✓ Branch 3 taken 107 times.
✓ Branch 4 taken 219 times.
326 if (head.adaptive_sync() != output->adaptive_sync()) {
232 107 changed = true;
233 107 wlConfig->set_adaptive_sync(&head, output->adaptive_sync());
234 }
235
236 326 return changed;
237 }
238
239 1631 QString WaylandOutput::hash() const
240 {
241
2/2
✓ Branch 3 taken 1615 times.
✓ Branch 4 taken 16 times.
1631 if (!head.model().isEmpty()) {
242 3230 return QStringLiteral("%1:%2:%3:%4")
243 1615 .arg(head.make(), head.model(), head.serialNumber(), head.name());
244 }
245 16 return head.description();
246 }
247
248 QDebug operator<<(QDebug dbg, const WaylandOutput* output)
249 {
250 dbg << "WaylandOutput(Id:" << output->id
251 << ", Name:" << QString(output->head.name() + QLatin1Char(' ') + output->head.description())
252 << ")";
253 return dbg;
254 }
255