GCC Code Coverage Report


Directory: ./
File: server/touch_pool.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 98 121 81.0%
Branches: 49 78 62.8%

Line Branch Exec Source
1 /*
2 SPDX-FileCopyrightText: 2020 Roman Gilg <subdiff@gmail.com>
3 SPDX-FileCopyrightText: 2021 Francesco Sorrentino <francesco.sorr@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only
6 */
7 #include "touch_pool.h"
8 #include "data_device.h"
9 #include "display.h"
10 #include "pointer.h"
11 #include "pointer_p.h"
12 #include "seat.h"
13 #include "seat_p.h"
14 #include "touch.h"
15 #include "utils.h"
16
17 #include <config-wrapland.h>
18
19 #if HAVE_LINUX_INPUT_H
20 #include <linux/input-event-codes.h>
21 #endif
22
23 namespace Wrapland::Server
24 {
25
26 112 touch_pool::touch_pool(Seat* seat)
27 112 : seat{seat}
28 {
29 112 }
30
31 224 touch_pool::~touch_pool()
32 {
33
1/2
✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
224 QObject::disconnect(focus.surface_lost_notifier);
34
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 for (auto dev : devices) {
35 QObject::disconnect(dev, nullptr, seat, nullptr);
36 }
37 224 }
38
39 14 touch_focus const& touch_pool::get_focus() const
40 {
41 14 return focus;
42 }
43
44 1 std::vector<Touch*> const& touch_pool::get_devices() const
45 {
46 1 return devices;
47 }
48
49 12 void touch_pool::create_device(Client* client, uint32_t version, uint32_t id)
50 {
51
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 auto touch = new Touch(client, version, id, seat);
52 12 devices.push_back(touch);
53
54
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
12 if (focus.surface && focus.surface->client() == client) {
55 // this is a touch for the currently focused touch surface
56 1 focus.devices.push_back(touch);
57
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!ids.empty()) {
58 // TODO(unknown author): send out all the points
59 }
60 1 }
61 24 QObject::connect(touch, &Touch::resourceDestroyed, seat, [touch, this] {
62 12 remove_one(devices, touch);
63 12 remove_one(focus.devices, touch);
64
65
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 assert(!contains(devices, touch));
66
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 assert(!contains(focus.devices, touch));
67 12 });
68 12 Q_EMIT seat->touchCreated(touch);
69 12 }
70
71 3 void touch_pool::set_focused_surface(Surface* surface, QPointF const& surfacePosition)
72 {
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (is_in_progress()) {
74 // changing surface not allowed during a touch sequence
75 return;
76 }
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 Q_ASSERT(!seat->drags().is_touch_drag());
78
79
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (focus.surface) {
80 1 QObject::disconnect(focus.surface_lost_notifier);
81 1 }
82 3 focus = touch_focus();
83 3 focus.surface = surface;
84 3 focus.offset = surfacePosition;
85 3 focus.devices = interfacesForSurface(surface, devices);
86
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (focus.surface) {
87 6 focus.surface_lost_notifier
88 8 = QObject::connect(surface, &Surface::resourceDestroyed, seat, [this] {
89
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (is_in_progress()) {
90 // Surface destroyed during touch sequence - send a cancel
91 for (auto touch : focus.devices) {
92 touch->cancel();
93 }
94 }
95 2 focus = touch_focus();
96 2 });
97 3 }
98 3 }
99
100 1 void touch_pool::set_focused_surface_position(QPointF const& surfacePosition)
101 {
102 1 focus.offset = surfacePosition;
103 1 }
104
105 7 int32_t touch_pool::touch_down(QPointF const& globalPosition)
106 {
107
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 const int32_t id = ids.empty() ? 0 : ids.crbegin()->first + 1;
108 7 auto const serial = seat->d_ptr->display()->handle->nextSerial();
109 7 auto const pos = globalPosition - focus.offset;
110
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 for (auto touch : focus.devices) {
111 5 touch->down(id, serial, pos);
112 }
113
114
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 if (id == 0) {
115 4 focus.first_touch_position = globalPosition;
116 4 }
117
118 #if HAVE_LINUX_INPUT_H
119
5/6
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
7 if (id == 0 && focus.devices.empty() && seat->hasPointer()) {
120 // If the client did not bind the touch interface fall back
121 // to at least emulating touch through pointer events.
122 forEachInterface(
123 focus.surface, seat->pointers().get_devices(), [this, pos, serial](auto pointer) {
124 pointer->d_ptr->sendEnter(serial, focus.surface, pos);
125 pointer->d_ptr->sendMotion(pos);
126 pointer->buttonPressed(serial, BTN_LEFT);
127 pointer->d_ptr->sendFrame();
128 });
129 }
130 #endif
131
132 7 ids[id] = serial;
133 7 return id;
134 }
135
136 4 void touch_pool::touch_up(int32_t id)
137 {
138
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 Q_ASSERT(ids.count(id));
139 4 auto const serial = seat->d_ptr->display()->handle->nextSerial();
140
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
4 if (seat->drags().is_touch_drag() && seat->drags().get_source().serial == ids[id]) {
141 // the implicitly grabbing touch point has been upped
142 1 seat->drags().drop();
143 1 }
144
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (auto touch : focus.devices) {
145 4 touch->up(id, serial);
146 }
147
148 #if HAVE_LINUX_INPUT_H
149
3/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
4 if (id == 0 && focus.devices.empty() && seat->hasPointer()) {
150 // Client did not bind touch, fall back to emulating with pointer events.
151 const uint32_t serial = seat->d_ptr->display()->handle->nextSerial();
152 forEachInterface(focus.surface, seat->pointers().get_devices(), [serial](auto pointer) {
153 pointer->buttonReleased(serial, BTN_LEFT);
154 });
155 }
156 #endif
157
158 4 ids.erase(id);
159 4 }
160
161 3 void touch_pool::touch_move(int32_t id, QPointF const& globalPosition)
162 {
163
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 Q_ASSERT(ids.count(id));
164 3 auto const pos = globalPosition - focus.offset;
165
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 for (auto touch : focus.devices) {
166 2 touch->move(id, pos);
167 }
168
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (id == 0) {
170 3 focus.first_touch_position = globalPosition;
171 3 }
172
173
4/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3 if (id == 0 && focus.devices.empty() && seat->hasPointer()) {
174 // Client did not bind touch, fall back to emulating with pointer events.
175 forEachInterface(focus.surface, seat->pointers().get_devices(), [pos](auto pointer) {
176 pointer->d_ptr->sendMotion(pos);
177 });
178 }
179 3 Q_EMIT seat->touchMoved(id, ids[id], globalPosition);
180 3 }
181
182 void touch_pool::touch_move_any(QPointF const& pos)
183 {
184 assert(!ids.empty());
185 touch_move(ids.cbegin()->first, pos);
186 }
187
188 8 void touch_pool::touch_frame() const
189 {
190
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8 times.
15 for (auto touch : focus.devices) {
191 7 touch->frame();
192 }
193 8 }
194
195 2 void touch_pool::cancel_sequence()
196 {
197
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (auto touch : focus.devices) {
198 1 touch->cancel();
199 }
200
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (seat->drags().is_touch_drag()) {
201 // cancel the drag, don't drop.
202 seat->drags().cancel();
203 }
204 2 ids.clear();
205 2 }
206
207 6 bool touch_pool::is_in_progress() const
208 {
209 6 return !ids.empty();
210 }
211
212 2 bool touch_pool::has_implicit_grab(uint32_t serial) const
213 {
214
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!focus.surface) {
215 // origin surface has been destroyed
216 return false;
217 }
218 4 auto check = [serial](auto const& pair) { return pair.second == serial; };
219 2 return std::find_if(ids.begin(), ids.end(), check) != ids.end();
220 2 }
221
222 }
223