GCC Code Coverage Report


Directory: ./
File: server/text_input_v2.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 241 250 96.4%
Branches: 80 124 64.5%

Line Branch Exec Source
1 /****************************************************************************
2 Copyright © 2020 Adrien Faveraux <ad1rie3@hotmail.fr>
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 "display.h"
21 #include "wayland/client.h"
22 #include "wayland/global.h"
23 #include "wayland/resource.h"
24
25 #include "seat_p.h"
26 #include "surface.h"
27 #include "surface_p.h"
28
29 #include "text_input_v2_p.h"
30
31 namespace Wrapland::Server
32 {
33
34 const struct zwp_text_input_manager_v2_interface text_input_manager_v2::Private::s_interface = {
35 resourceDestroyCallback,
36 cb<get_text_input_callback>,
37 };
38
39 74 text_input_manager_v2::Private::Private(Display* display, text_input_manager_v2* q_ptr)
40 148 : text_input_manager_v2_global(q_ptr,
41 74 display,
42 &zwp_text_input_manager_v2_interface,
43 &s_interface)
44 74 {
45
1/2
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
74 create();
46 74 }
47
48 39 void text_input_manager_v2::Private::get_text_input_callback(text_input_manager_v2_bind* bind,
49 uint32_t id,
50 wl_resource* wlSeat)
51 {
52 39 auto seat = SeatGlobal::get_handle(wlSeat);
53
54
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 auto textInput = new text_input_v2(bind->client->handle, bind->version, id);
55
56 39 textInput->d_ptr->seat = seat;
57
58 39 seat->d_ptr->text_inputs.register_device(textInput);
59 39 }
60 39
61 113 text_input_manager_v2::text_input_manager_v2(Display* display)
62
2/4
✓ Branch 0 taken 74 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74 times.
74 : d_ptr(new Private(display, this))
63 113 {
64 74 }
65
66 148 text_input_manager_v2::~text_input_manager_v2() = default;
67
68 const struct zwp_text_input_v2_interface text_input_v2::Private::s_interface = {
69 destroyCallback,
70 enable_callback,
71 disable_callback,
72 show_input_panel_callback,
73 hide_input_panel_callback,
74 set_surrounding_text_callback,
75 set_content_type_callback,
76 set_cursor_rectangle_callback,
77 set_preferred_language_callback,
78 update_state_callback,
79 };
80
81
3/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
117 text_input_v2::Private::Private(Client* client, uint32_t version, uint32_t id, text_input_v2* q_ptr)
82 78 : Wayland::Resource<text_input_v2>(client,
83 39 version,
84 39 id,
85 &zwp_text_input_v2_interface,
86 &s_interface,
87 39 q_ptr)
88 39 , q_ptr{q_ptr}
89 39 {
90 39 }
91
92 91 void text_input_v2::Private::sync(text_input_v2_state const& old)
93 {
94
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 35 times.
91 if (seat->text_inputs().v2.text_input == q_ptr) {
95 56 seat->text_inputs().sync_to_input_method(old, state);
96 56 }
97 91 }
98
99 39 void text_input_v2::Private::enable(Surface* surface)
100 {
101
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 assert(surface);
102
103
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 auto changed = this->surface != surface || !state.enabled;
104 39 auto const old = state;
105
106
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 QObject::disconnect(destroy_notifiers.surface);
107
108 39 this->surface = surface;
109 39 state.enabled = true;
110
111 78 destroy_notifiers.surface
112
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
77 = QObject::connect(surface, &Surface::resourceDestroyed, handle, [this] {
113 // TODO(romangg): Instead call disable?
114 38 this->surface = nullptr;
115 38 });
116
117
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 if (changed) {
118
1/2
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
39 sync(old);
119 39 }
120 39 }
121
122 1 void text_input_v2::Private::disable()
123 {
124 1 auto changed = state.enabled;
125 1 auto const old = state;
126
127 1 surface = nullptr;
128 1 state.enabled = false;
129
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (changed) {
131
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 sync(old);
132 1 }
133 1 }
134
135 41 void text_input_v2::Private::send_enter(Surface* surface, uint32_t serial)
136 {
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (!surface) {
138 return;
139 }
140 41 send<zwp_text_input_v2_send_enter>(serial, surface->d_ptr->resource);
141 41 }
142
143 41 void text_input_v2::Private::send_leave(uint32_t serial, Surface* surface)
144 {
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 if (!surface) {
146 return;
147 }
148 41 send<zwp_text_input_v2_send_leave>(serial, surface->d_ptr->resource);
149 41 }
150
151 39 void text_input_v2::Private::enable_callback(wl_client* /*wlClient*/,
152 wl_resource* wlResource,
153 wl_resource* surface)
154 {
155 39 auto priv = get_handle(wlResource)->d_ptr;
156 39 priv->enable(Wayland::Resource<Surface>::get_handle(surface));
157 39 }
158
159 1 void text_input_v2::Private::disable_callback(wl_client* /*wlClient*/,
160 wl_resource* wlResource,
161 wl_resource* /*surface*/)
162 {
163 1 auto priv = get_handle(wlResource)->d_ptr;
164 1 priv->disable();
165 1 }
166
167 1 void text_input_v2::Private::update_state_callback(wl_client* /*wlClient*/,
168 wl_resource* wlResource,
169 uint32_t /*serial*/,
170 uint32_t reason)
171 {
172 1 auto priv = get_handle(wlResource)->d_ptr;
173
174 // TODO(unknown author): use other reason values reason
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (reason == ZWP_TEXT_INPUT_V2_UPDATE_STATE_RESET) {
176 1 Q_EMIT priv->handle->reset_requested();
177 1 }
178 1 }
179
180 1 void text_input_v2::Private::show_input_panel_callback(wl_client* /*wlClient*/,
181 wl_resource* wlResource)
182 {
183 1 auto priv = get_handle(wlResource)->d_ptr;
184 1 Q_EMIT priv->handle->show_input_panel_requested();
185 1 }
186
187 1 void text_input_v2::Private::hide_input_panel_callback(wl_client* /*wlClient*/,
188 wl_resource* wlResource)
189 {
190 1 auto priv = get_handle(wlResource)->d_ptr;
191 1 Q_EMIT priv->handle->hide_input_panel_requested();
192 1 }
193
194 1 void text_input_v2::Private::set_surrounding_text_callback(wl_client* /*wlClient*/,
195 wl_resource* wlResource,
196 char const* text,
197 int32_t cursor,
198 int32_t anchor)
199 {
200 1 auto priv = get_handle(wlResource)->d_ptr;
201
202
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1 if (priv->state.surrounding_text.data == text
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 && priv->state.surrounding_text.cursor_position == cursor
204 && priv->state.surrounding_text.selection_anchor == anchor) {
205 return;
206 }
207
208 1 auto const old = priv->state;
209
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 priv->state.surrounding_text.data = text;
210 1 priv->state.surrounding_text.cursor_position = cursor;
211 1 priv->state.surrounding_text.selection_anchor = anchor;
212
213
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 priv->sync(old);
214
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Q_EMIT priv->handle->surrounding_text_changed();
215 1 }
216
217 72 text_input_v2_content_hints convert_hint(uint32_t hint)
218 {
219 72 auto const hints = static_cast<zwp_text_input_v2_content_hint>(hint);
220 72 text_input_v2_content_hints ret = text_input_v2_content_hint::none;
221
222
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION) {
223 6 ret |= text_input_v2_content_hint::completion;
224 6 }
225
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION) {
226 6 ret |= text_input_v2_content_hint::correction;
227 6 }
228
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 6 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION) {
229 6 ret |= text_input_v2_content_hint::capitalization;
230 6 }
231
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE) {
232 4 ret |= text_input_v2_content_hint::lowercase;
233 4 }
234
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE) {
235 4 ret |= text_input_v2_content_hint::uppercase;
236 4 }
237
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_TITLECASE) {
238 4 ret |= text_input_v2_content_hint::titlecase;
239 4 }
240
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT) {
241 4 ret |= text_input_v2_content_hint::hidden_text;
242 4 }
243
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA) {
244 4 ret |= text_input_v2_content_hint::sensitive_data;
245 4 }
246
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN) {
247 4 ret |= text_input_v2_content_hint::latin;
248 4 }
249
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 4 times.
72 if (hints & ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE) {
250 4 ret |= text_input_v2_content_hint::multiline;
251 4 }
252 72 return ret;
253 }
254
255 72 text_input_v2_content_purpose convert_purpose(uint32_t purpose)
256 {
257 72 auto const wlPurpose = static_cast<zwp_text_input_v2_content_purpose>(purpose);
258
259
13/14
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
72 switch (wlPurpose) {
260 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_ALPHA:
261 2 return text_input_v2_content_purpose::alpha;
262 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS:
263 2 return text_input_v2_content_purpose::digits;
264 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER:
265 2 return text_input_v2_content_purpose::number;
266 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE:
267 2 return text_input_v2_content_purpose::phone;
268 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL:
269 2 return text_input_v2_content_purpose::url;
270 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL:
271 2 return text_input_v2_content_purpose::email;
272 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NAME:
273 2 return text_input_v2_content_purpose::name;
274 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PASSWORD:
275 2 return text_input_v2_content_purpose::password;
276 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE:
277 2 return text_input_v2_content_purpose::date;
278 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME:
279 2 return text_input_v2_content_purpose::time;
280 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME:
281 2 return text_input_v2_content_purpose::datetime;
282 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TERMINAL:
283 2 return text_input_v2_content_purpose::terminal;
284 48 case ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL:
285 default:
286 48 return text_input_v2_content_purpose::normal;
287 }
288 72 }
289
290 72 void text_input_v2::Private::set_content_type_callback(wl_client* /*wlClient*/,
291 wl_resource* wlResource,
292 uint32_t hint,
293 uint32_t purpose)
294 {
295 72 auto priv = get_handle(wlResource)->d_ptr;
296 72 auto const content_hints = convert_hint(hint);
297 72 auto const content_purpose = convert_purpose(purpose);
298
299
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
72 if (content_hints == priv->state.content.hints
300
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 && content_purpose == priv->state.content.purpose) {
301 24 return;
302 }
303
304 48 auto const old = priv->state;
305 48 priv->state.content.hints = content_hints;
306 48 priv->state.content.purpose = content_purpose;
307
308
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 priv->sync(old);
309
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 Q_EMIT priv->handle->content_type_changed();
310 72 }
311
312 1 void text_input_v2::Private::set_cursor_rectangle_callback(wl_client* /*wlClient*/,
313 wl_resource* wlResource,
314 int32_t pos_x,
315 int32_t pos_y,
316 int32_t width,
317 int32_t height)
318 {
319 1 auto priv = get_handle(wlResource)->d_ptr;
320 1 auto const rect = QRect(pos_x, pos_y, width, height);
321
322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (priv->state.cursor_rectangle == rect) {
323 return;
324 }
325
326 1 auto const old = priv->state;
327 1 priv->state.cursor_rectangle = rect;
328
329
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 priv->sync(old);
330
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Q_EMIT priv->handle->cursor_rectangle_changed();
331 1 }
332
333 1 void text_input_v2::Private::set_preferred_language_callback(wl_client* /*wlClient*/,
334 wl_resource* wlResource,
335 char const* language)
336 {
337 1 auto priv = get_handle(wlResource)->d_ptr;
338
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (priv->state.preferred_language == language) {
340 return;
341 }
342
343 1 auto const old = priv->state;
344
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 priv->state.preferred_language = language;
345
346
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 priv->sync(old);
347
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Q_EMIT priv->handle->preferred_language_changed();
348 1 }
349
350 39 text_input_v2::text_input_v2(Client* client, uint32_t version, uint32_t id)
351 39 : QObject(nullptr)
352
2/4
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
39 , d_ptr(new Private(client, version, id, this))
353 39 {
354 39 }
355
356 95 text_input_v2_state const& text_input_v2::state() const
357 {
358 95 return d_ptr->state;
359 }
360
361 2 void text_input_v2::set_preedit_string(std::string const& text, std::string const& commit)
362 {
363 2 d_ptr->send<zwp_text_input_v2_send_preedit_string>(text.c_str(), commit.c_str());
364 2 }
365
366 1 void text_input_v2::commit(std::string const& text)
367 {
368 1 d_ptr->send<zwp_text_input_v2_send_commit_string>(text.c_str());
369 1 }
370
371 1 void text_input_v2::keysym_pressed(uint32_t keysym, Qt::KeyboardModifiers /*modifiers*/)
372 {
373 2 d_ptr->send<zwp_text_input_v2_send_keysym>(
374
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 d_ptr->seat ? d_ptr->seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_PRESSED, 0);
375 1 }
376
377 1 void text_input_v2::keysym_released(uint32_t keysym, Qt::KeyboardModifiers /*modifiers*/)
378 {
379 2 d_ptr->send<zwp_text_input_v2_send_keysym>(
380
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 d_ptr->seat ? d_ptr->seat->timestamp() : 0, keysym, WL_KEYBOARD_KEY_STATE_RELEASED, 0);
381 1 }
382
383 1 void text_input_v2::delete_surrounding_text(uint32_t beforeLength, uint32_t afterLength)
384 {
385 1 d_ptr->send<zwp_text_input_v2_send_delete_surrounding_text>(beforeLength, afterLength);
386 1 }
387
388 1 void text_input_v2::set_cursor_position(int32_t index, int32_t anchor)
389 {
390 1 d_ptr->send<zwp_text_input_v2_send_cursor_position>(index, anchor);
391 1 }
392
393 6 void text_input_v2::set_text_direction(Qt::LayoutDirection direction)
394 {
395 6 auto wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_AUTO;
396
397
3/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
6 switch (direction) {
398 case Qt::LeftToRight:
399 2 wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_LTR;
400 2 break;
401 case Qt::RightToLeft:
402 2 wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_RTL;
403 2 break;
404 case Qt::LayoutDirectionAuto:
405 2 wlDirection = ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_AUTO;
406 2 break;
407 default:
408 Q_UNREACHABLE();
409 break;
410 }
411
412 6 d_ptr->send<zwp_text_input_v2_send_text_direction>(wlDirection);
413 6 }
414
415 1 void text_input_v2::set_preedit_cursor(int32_t index)
416 {
417 1 d_ptr->send<zwp_text_input_v2_send_preedit_cursor>(index);
418 1 }
419
420 2 void text_input_v2::set_input_panel_state(bool visible, QRect const& overlapped_surface_area)
421 {
422
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
2 if (d_ptr->input_panel_visible == visible
423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 && d_ptr->overlapped_surface_area == overlapped_surface_area) {
424 // Not changed.
425 return;
426 }
427
428 2 d_ptr->input_panel_visible = visible;
429 2 d_ptr->overlapped_surface_area = overlapped_surface_area;
430
431 4 d_ptr->send<zwp_text_input_v2_send_input_panel_state>(
432 2 visible ? ZWP_TEXT_INPUT_V2_INPUT_PANEL_VISIBILITY_VISIBLE
433 : ZWP_TEXT_INPUT_V2_INPUT_PANEL_VISIBILITY_HIDDEN,
434 2 overlapped_surface_area.x(),
435 2 overlapped_surface_area.y(),
436 2 overlapped_surface_area.width(),
437 2 overlapped_surface_area.height());
438 2 }
439
440 3 void text_input_v2::set_language(std::string const& language_tag)
441 {
442
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (d_ptr->language == language_tag) {
443 1 return;
444 }
445 2 d_ptr->language = language_tag;
446 2 d_ptr->send<zwp_text_input_v2_send_language>(language_tag.c_str());
447 3 }
448
449 5 Surface* text_input_v2::surface() const
450 {
451 5 return d_ptr->surface;
452 }
453
454 41 Client* text_input_v2::client() const
455 {
456 41 return d_ptr->client->handle;
457 }
458
459 }
460