GCC Code Coverage Report


Directory: ./
File: server/input_method_v2.cpp
Date: 2024-01-22 17:25:27
Exec Total Coverage
Lines: 154 164 93.9%
Branches: 18 36 50.0%

Line Branch Exec Source
1 /*
2 SPDX-FileCopyrightText: 2020 Aleix Pol Gonzalez <aleixpol@kde.org>
3 SPDX-FileCopyrightText: 2021 Dorota Czaplejewicz <gihuac.dcz@porcupinefactory.org>
4 SPDX-FileCopyrightText: 2021 Roman Glig <subdiff@gmail.com>
5
6 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only
7 */
8 #include "input_method_v2_p.h"
9
10 #include "display.h"
11 #include "logging.h"
12 #include "seat_p.h"
13 #include "surface_p.h"
14 #include "text_input_v3_p.h"
15 #include "wayland/client.h"
16
17 #include <wayland-input-method-unstable-v2-server-protocol.h>
18
19 namespace Wrapland::Server
20 {
21
22 struct zwp_input_method_manager_v2_interface const input_method_manager_v2::Private::s_interface = {
23 cb<get_input_method_callback>,
24 resourceDestroyCallback,
25 };
26
27 31 void input_method_manager_v2::Private::get_input_method_callback(input_method_manager_v2_bind* bind,
28 wl_resource* wlSeat,
29 uint32_t id)
30 {
31 31 auto seat = SeatGlobal::get_handle(wlSeat);
32
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 auto im = new input_method_v2(bind->client->handle, bind->version, id);
33
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31 times.
31 if (seat->get_input_method_v2()) {
34 // Seat already has an input method.
35 im->d_ptr->send<zwp_input_method_v2_send_unavailable>();
36 return;
37 }
38 31 im->d_ptr->seat = seat;
39
40 31 seat->d_ptr->input_method = im;
41
42 62 QObject::connect(im, &input_method_v2::resourceDestroyed, seat, [seat] {
43 31 seat->d_ptr->input_method = nullptr;
44 62 Q_EMIT seat->input_method_v2_changed();
45 62 });
46 31 Q_EMIT seat->input_method_v2_changed();
47 31 }
48
49 66 input_method_manager_v2::Private::Private(Display* display, input_method_manager_v2* q_ptr)
50 132 : input_method_manager_v2_global(q_ptr,
51 66 display,
52 &zwp_input_method_manager_v2_interface,
53 &s_interface)
54 66 {
55
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 create();
56 66 }
57
58 66 input_method_manager_v2::input_method_manager_v2(Display* display)
59
2/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
66 : d_ptr(new Private(display, this))
60 66 {
61 66 }
62
63 132 input_method_manager_v2::~input_method_manager_v2() = default;
64
65 struct zwp_input_method_v2_interface const input_method_v2::Private::s_interface = {
66 commit_string_callback,
67 preedit_string_callback,
68 delete_surrounding_text_callback,
69 commit_callback,
70 get_input_popup_surface_callback,
71 grab_keyboard_callback,
72 destroyCallback,
73 };
74
75 2 void input_method_v2::Private::commit_string_callback([[maybe_unused]] wl_client* wlClient,
76 wl_resource* wlResource,
77 char const* text)
78 {
79 2 auto priv = get_handle(wlResource)->d_ptr;
80 2 priv->pending.commit_string.data = text;
81 2 priv->pending.commit_string.update = true;
82 2 }
83
84 2 void input_method_v2::Private::preedit_string_callback([[maybe_unused]] wl_client* wlClient,
85 wl_resource* wlResource,
86 char const* text,
87 int32_t cursor_begin,
88 int32_t cursor_end)
89 {
90 2 auto priv = get_handle(wlResource)->d_ptr;
91 2 priv->pending.preedit_string.data = text;
92 2 priv->pending.preedit_string.cursor_begin = cursor_begin;
93 2 priv->pending.preedit_string.cursor_end = cursor_end;
94 2 priv->pending.preedit_string.update = true;
95 2 }
96
97 1 void input_method_v2::Private::delete_surrounding_text_callback(
98 [[maybe_unused]] wl_client* wlClient,
99 wl_resource* wlResource,
100 uint32_t beforeBytes,
101 uint32_t afterBytes)
102 {
103 1 auto priv = get_handle(wlResource)->d_ptr;
104 1 priv->pending.delete_surrounding_text.before_length = beforeBytes;
105 1 priv->pending.delete_surrounding_text.after_length = afterBytes;
106 1 priv->pending.delete_surrounding_text.update = true;
107 1 }
108
109 3 void input_method_v2::Private::commit_callback([[maybe_unused]] wl_client* wlClient,
110 wl_resource* wlResource,
111 uint32_t serial)
112 {
113 3 auto priv = get_handle(wlResource)->d_ptr;
114
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (priv->serial != serial) {
116 // Not on latest done event. Reset pending to current state and wait for next commit.
117 priv->pending = priv->current;
118 return;
119 }
120
121 3 priv->seat->text_inputs().sync_to_text_input(priv->current, priv->pending);
122 3 priv->current = priv->pending;
123
124 3 priv->pending.preedit_string.update = false;
125 3 priv->pending.commit_string.update = false;
126 3 priv->pending.delete_surrounding_text.update = false;
127
128 3 Q_EMIT priv->handle->state_committed();
129 3 }
130
131 1 void input_method_v2::Private::get_input_popup_surface_callback(
132 [[maybe_unused]] wl_client* wlClient,
133 wl_resource* wlResource,
134 uint32_t id,
135 wl_resource* wlSurface)
136 {
137 1 auto priv = get_handle(wlResource)->d_ptr;
138 1 auto surface = Surface::Private::get_handle(wlSurface);
139 // TODO(romangg): should send error when surface already has a role.
140
141 1 auto popup
142
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 = new input_method_popup_surface_v2(priv->client->handle, priv->version, id, surface);
143
144 1 priv->popups.push_back(popup);
145 2 QObject::connect(popup,
146 &input_method_popup_surface_v2::resourceDestroyed,
147 1 priv->q_ptr,
148 1 [priv, popup] { remove_one(priv->popups, popup); });
149
150
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (auto ti = priv->seat->text_inputs().v3.text_input) {
151 popup->set_text_input_rectangle(ti->state().cursor_rectangle);
152 }
153
154 1 Q_EMIT priv->q_ptr->popup_surface_created(popup);
155 1 }
156
157 1 void input_method_v2::Private::grab_keyboard_callback([[maybe_unused]] wl_client* wlClient,
158 wl_resource* wlResource,
159 uint32_t id)
160 {
161 1 auto priv = get_handle(wlResource)->d_ptr;
162 1 auto grab
163
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 = new input_method_keyboard_grab_v2(priv->client->handle, priv->version, id, priv->seat);
164 1 Q_EMIT priv->q_ptr->keyboard_grabbed(grab);
165 1 }
166
167 62 input_method_v2::Private::Private(Client* client,
168 uint32_t version,
169 uint32_t id,
170 input_method_v2* q_ptr)
171 62 : Wayland::Resource<input_method_v2>(client,
172 31 version,
173 31 id,
174 &zwp_input_method_v2_interface,
175 &s_interface,
176 31 q_ptr)
177 31 , q_ptr{q_ptr}
178 31 {
179 31 }
180
181 31 input_method_v2::input_method_v2(Client* client, uint32_t version, uint32_t id)
182 31 : QObject(nullptr)
183
2/4
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
31 , d_ptr(new Private(client, version, id, this))
184 31 {
185 31 }
186
187 81 void input_method_v2::set_active(bool active)
188 {
189
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 27 times.
81 if (active) {
190 54 d_ptr->current = {};
191 54 d_ptr->pending = {};
192 54 d_ptr->send<zwp_input_method_v2_send_activate>();
193 54 } else {
194 27 d_ptr->send<zwp_input_method_v2_send_deactivate>();
195 }
196 81 }
197
198 4 void input_method_v2::set_surrounding_text(
199 std::string const& text,
200 uint32_t cursor,
201 uint32_t anchor,
202 Wrapland::Server::text_input_v3_change_cause change_cause)
203 {
204 4 d_ptr->send<zwp_input_method_v2_send_surrounding_text>(text.c_str(), cursor, anchor);
205 4 d_ptr->send<zwp_input_method_v2_send_text_change_cause>(convert_change_cause(change_cause));
206 4 }
207
208 24 void input_method_v2::set_content_type(text_input_v3_content_hints hints,
209 text_input_v3_content_purpose purpose)
210 {
211 48 d_ptr->send<zwp_input_method_v2_send_content_type>(convert_content_hints(hints),
212 24 convert_content_purpose(purpose));
213 24 }
214
215 81 void input_method_v2::done()
216 {
217 81 d_ptr->serial++;
218 81 d_ptr->send<zwp_input_method_v2_send_done>();
219 81 }
220
221 54 input_method_v2_state const& input_method_v2::state() const
222 {
223 54 return d_ptr->current;
224 }
225
226 std::vector<input_method_popup_surface_v2*> const& input_method_v2::get_popups() const
227 {
228 return d_ptr->popups;
229 }
230
231 struct zwp_input_method_keyboard_grab_v2_interface const
232 input_method_keyboard_grab_v2::Private::s_interface{
233 destroyCallback,
234 };
235
236 2 input_method_keyboard_grab_v2::Private::Private(Client* client,
237 uint32_t version,
238 uint32_t id,
239 Seat* seat,
240 input_method_keyboard_grab_v2* q_ptr)
241 2 : Wayland::Resource<input_method_keyboard_grab_v2>(client,
242 1 version,
243 1 id,
244 &zwp_input_method_keyboard_grab_v2_interface,
245 &s_interface,
246 1 q_ptr)
247 1 , seat{seat}
248 1 {
249 1 }
250
251 1 input_method_keyboard_grab_v2::input_method_keyboard_grab_v2(Client* client,
252 uint32_t version,
253 uint32_t id,
254 Wrapland::Server::Seat* seat)
255 1 : QObject(nullptr)
256
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 , d_ptr(new Private(client, version, id, seat, this))
257 1 {
258 1 }
259
260 1 void input_method_keyboard_grab_v2::set_keymap(std::string const& content)
261 {
262 1 auto tmpf = std::tmpfile();
263
264
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (auto rc = std::fputs(content.data(), tmpf); rc < 0) {
265 qCWarning(WRAPLAND_SERVER, "Failed to set input-method keymap with %d.", rc);
266 // TODO(romangg): Handle error by closing file here and returning?
267 }
268
269 1 std::rewind(tmpf);
270 2 d_ptr->send<zwp_input_method_keyboard_grab_v2_send_keymap>(
271 1 WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, fileno(tmpf), content.size());
272 1 d_ptr->keymap = file_wrap(tmpf);
273 1 }
274
275 1 void input_method_keyboard_grab_v2::key(uint32_t time, uint32_t key, key_state state)
276 {
277 1 auto serial = d_ptr->client->display()->handle->nextSerial();
278 2 d_ptr->send<zwp_input_method_keyboard_grab_v2_send_key>(serial,
279 time,
280 key,
281 1 state == key_state::pressed
282 ? WL_KEYBOARD_KEY_STATE_PRESSED
283 : WL_KEYBOARD_KEY_STATE_RELEASED);
284 1 }
285
286 1 void input_method_keyboard_grab_v2::update_modifiers(uint32_t depressed,
287 uint32_t latched,
288 uint32_t locked,
289 uint32_t group)
290 {
291 1 auto serial = d_ptr->client->display()->handle->nextSerial();
292 1 d_ptr->send<zwp_input_method_keyboard_grab_v2_send_modifiers>(
293 serial, depressed, latched, locked, group);
294 1 }
295
296 1 void input_method_keyboard_grab_v2::set_repeat_info(int32_t rate, int32_t delay)
297 {
298 1 d_ptr->send<zwp_input_method_keyboard_grab_v2_send_repeat_info>(rate, delay);
299 1 }
300
301 struct zwp_input_popup_surface_v2_interface const
302 input_method_popup_surface_v2::Private::s_interface{
303 destroyCallback,
304 };
305
306 1 input_method_popup_surface_v2::Private::Private(Client* client,
307 uint32_t version,
308 uint32_t id,
309 Surface* surface,
310 input_method_popup_surface_v2* q_ptr)
311 2 : Wayland::Resource<input_method_popup_surface_v2>(client,
312 1 version,
313 1 id,
314 &zwp_input_popup_surface_v2_interface,
315 &s_interface,
316 1 q_ptr)
317 1 , surface{surface}
318 1 {
319 1 }
320
321 1 input_method_popup_surface_v2::input_method_popup_surface_v2(Client* client,
322 uint32_t version,
323 uint32_t id,
324 Wrapland::Server::Surface* surface)
325 1 : QObject(nullptr)
326
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 , d_ptr(new Private(client, version, id, surface, this))
327 1 {
328 1 }
329
330 Surface* input_method_popup_surface_v2::surface() const
331 {
332 return d_ptr->surface;
333 }
334
335 1 void input_method_popup_surface_v2::set_text_input_rectangle(QRect const& rect)
336 {
337 2 d_ptr->send<zwp_input_popup_surface_v2_send_text_input_rectangle>(
338 1 rect.x(), rect.y(), rect.width(), rect.height());
339 1 }
340
341 }
342