1 /*
2 * Copyright © 2012 Openismus GmbH
3 * Copyright © 2012 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial
15 * portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #include "config.h"
28
29 #include <stdbool.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <time.h>
35
36 #include <libweston/libweston.h>
37 #include "weston.h"
38 #include "text-input-unstable-v1-server-protocol.h"
39 #include "input-method-unstable-v1-server-protocol.h"
40 #include "shared/helpers.h"
41 #include "shared/timespec-util.h"
42
43 struct text_input_manager;
44 struct input_method;
45 struct input_method_context;
46 struct text_backend;
47
48 struct text_input {
49 struct wl_resource *resource;
50
51 struct weston_compositor *ec;
52
53 struct wl_list input_methods;
54
55 struct weston_surface *surface;
56
57 pixman_box32_t cursor_rectangle;
58
59 bool input_panel_visible;
60
61 struct text_input_manager *manager;
62 };
63
64 struct text_input_manager {
65 struct wl_global *text_input_manager_global;
66 struct wl_listener destroy_listener;
67
68 struct text_input *current_text_input;
69
70 struct weston_compositor *ec;
71 };
72
73 struct input_method {
74 struct wl_resource *input_method_binding;
75 struct wl_global *input_method_global;
76 struct wl_listener destroy_listener;
77
78 struct weston_seat *seat;
79 struct text_input *input;
80
81 struct wl_list link;
82
83 struct wl_listener keyboard_focus_listener;
84
85 bool focus_listener_initialized;
86
87 struct input_method_context *context;
88
89 struct text_backend *text_backend;
90 };
91
92 struct input_method_context {
93 struct wl_resource *resource;
94
95 struct text_input *input;
96 struct input_method *input_method;
97
98 struct wl_resource *keyboard;
99 };
100
101 struct text_backend {
102 struct weston_compositor *compositor;
103
104 struct {
105 char *path;
106 struct wl_client *client;
107
108 unsigned deathcount;
109 struct timespec deathstamp;
110 } input_method;
111
112 struct wl_listener client_listener;
113 struct wl_listener seat_created_listener;
114 };
115
116 static void
117 input_method_context_create(struct text_input *input,
118 struct input_method *input_method);
119 static void
120 input_method_context_end_keyboard_grab(struct input_method_context *context);
121
122 static void
123 input_method_init_seat(struct weston_seat *seat);
124
125 static void
deactivate_input_method(struct input_method * input_method)126 deactivate_input_method(struct input_method *input_method)
127 {
128 struct text_input *text_input = input_method->input;
129 struct weston_compositor *ec = text_input->ec;
130
131 if (input_method->context && input_method->input_method_binding) {
132 input_method_context_end_keyboard_grab(input_method->context);
133 zwp_input_method_v1_send_deactivate(
134 input_method->input_method_binding,
135 input_method->context->resource);
136 input_method->context->input = NULL;
137 }
138
139 wl_list_remove(&input_method->link);
140 input_method->input = NULL;
141 input_method->context = NULL;
142
143 if (wl_list_empty(&text_input->input_methods) &&
144 text_input->input_panel_visible &&
145 text_input->manager->current_text_input == text_input) {
146 wl_signal_emit(&ec->hide_input_panel_signal, ec);
147 text_input->input_panel_visible = false;
148 }
149
150 if (text_input->manager->current_text_input == text_input)
151 text_input->manager->current_text_input = NULL;
152
153 zwp_text_input_v1_send_leave(text_input->resource);
154 }
155
156 static void
destroy_text_input(struct wl_resource * resource)157 destroy_text_input(struct wl_resource *resource)
158 {
159 struct text_input *text_input = wl_resource_get_user_data(resource);
160 struct input_method *input_method, *next;
161
162 wl_list_for_each_safe(input_method, next,
163 &text_input->input_methods, link)
164 deactivate_input_method(input_method);
165
166 free(text_input);
167 }
168
169 static void
text_input_set_surrounding_text(struct wl_client * client,struct wl_resource * resource,const char * text,uint32_t cursor,uint32_t anchor)170 text_input_set_surrounding_text(struct wl_client *client,
171 struct wl_resource *resource,
172 const char *text,
173 uint32_t cursor,
174 uint32_t anchor)
175 {
176 struct text_input *text_input = wl_resource_get_user_data(resource);
177 struct input_method *input_method, *next;
178
179 wl_list_for_each_safe(input_method, next,
180 &text_input->input_methods, link) {
181 if (!input_method->context)
182 continue;
183 zwp_input_method_context_v1_send_surrounding_text(
184 input_method->context->resource, text, cursor, anchor);
185 }
186 }
187
188 static void
text_input_activate(struct wl_client * client,struct wl_resource * resource,struct wl_resource * seat,struct wl_resource * surface)189 text_input_activate(struct wl_client *client,
190 struct wl_resource *resource,
191 struct wl_resource *seat,
192 struct wl_resource *surface)
193 {
194 struct text_input *text_input = wl_resource_get_user_data(resource);
195 struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
196 struct input_method *input_method;
197 struct weston_compositor *ec = text_input->ec;
198 struct text_input *current;
199
200 if (!weston_seat)
201 return;
202
203 input_method = weston_seat->input_method;
204 if (input_method->input == text_input)
205 return;
206
207 if (input_method->input)
208 deactivate_input_method(input_method);
209
210 input_method->input = text_input;
211 wl_list_insert(&text_input->input_methods, &input_method->link);
212 input_method_init_seat(weston_seat);
213
214 text_input->surface = wl_resource_get_user_data(surface);
215
216 input_method_context_create(text_input, input_method);
217
218 current = text_input->manager->current_text_input;
219
220 if (current && current != text_input) {
221 current->input_panel_visible = false;
222 wl_signal_emit(&ec->hide_input_panel_signal, ec);
223 }
224
225 if (text_input->input_panel_visible) {
226 wl_signal_emit(&ec->show_input_panel_signal,
227 text_input->surface);
228 wl_signal_emit(&ec->update_input_panel_signal,
229 &text_input->cursor_rectangle);
230 }
231 text_input->manager->current_text_input = text_input;
232
233 zwp_text_input_v1_send_enter(text_input->resource,
234 text_input->surface->resource);
235 }
236
237 static void
text_input_deactivate(struct wl_client * client,struct wl_resource * resource,struct wl_resource * seat)238 text_input_deactivate(struct wl_client *client,
239 struct wl_resource *resource,
240 struct wl_resource *seat)
241 {
242 struct weston_seat *weston_seat = wl_resource_get_user_data(seat);
243
244 if (weston_seat && weston_seat->input_method->input)
245 deactivate_input_method(weston_seat->input_method);
246 }
247
248 static void
text_input_reset(struct wl_client * client,struct wl_resource * resource)249 text_input_reset(struct wl_client *client,
250 struct wl_resource *resource)
251 {
252 struct text_input *text_input = wl_resource_get_user_data(resource);
253 struct input_method *input_method, *next;
254
255 wl_list_for_each_safe(input_method, next,
256 &text_input->input_methods, link) {
257 if (!input_method->context)
258 continue;
259 zwp_input_method_context_v1_send_reset(
260 input_method->context->resource);
261 }
262 }
263
264 static void
text_input_set_cursor_rectangle(struct wl_client * client,struct wl_resource * resource,int32_t x,int32_t y,int32_t width,int32_t height)265 text_input_set_cursor_rectangle(struct wl_client *client,
266 struct wl_resource *resource,
267 int32_t x,
268 int32_t y,
269 int32_t width,
270 int32_t height)
271 {
272 struct text_input *text_input = wl_resource_get_user_data(resource);
273 struct weston_compositor *ec = text_input->ec;
274
275 text_input->cursor_rectangle.x1 = x;
276 text_input->cursor_rectangle.y1 = y;
277 text_input->cursor_rectangle.x2 = x + width;
278 text_input->cursor_rectangle.y2 = y + height;
279
280 wl_signal_emit(&ec->update_input_panel_signal,
281 &text_input->cursor_rectangle);
282 }
283
284 static void
text_input_set_content_type(struct wl_client * client,struct wl_resource * resource,uint32_t hint,uint32_t purpose)285 text_input_set_content_type(struct wl_client *client,
286 struct wl_resource *resource,
287 uint32_t hint,
288 uint32_t purpose)
289 {
290 struct text_input *text_input = wl_resource_get_user_data(resource);
291 struct input_method *input_method, *next;
292
293 wl_list_for_each_safe(input_method, next,
294 &text_input->input_methods, link) {
295 if (!input_method->context)
296 continue;
297 zwp_input_method_context_v1_send_content_type(
298 input_method->context->resource, hint, purpose);
299 }
300 }
301
302 static void
text_input_invoke_action(struct wl_client * client,struct wl_resource * resource,uint32_t button,uint32_t index)303 text_input_invoke_action(struct wl_client *client,
304 struct wl_resource *resource,
305 uint32_t button,
306 uint32_t index)
307 {
308 struct text_input *text_input = wl_resource_get_user_data(resource);
309 struct input_method *input_method, *next;
310
311 wl_list_for_each_safe(input_method, next,
312 &text_input->input_methods, link) {
313 if (!input_method->context)
314 continue;
315 zwp_input_method_context_v1_send_invoke_action(
316 input_method->context->resource, button, index);
317 }
318 }
319
320 static void
text_input_commit_state(struct wl_client * client,struct wl_resource * resource,uint32_t serial)321 text_input_commit_state(struct wl_client *client,
322 struct wl_resource *resource,
323 uint32_t serial)
324 {
325 struct text_input *text_input = wl_resource_get_user_data(resource);
326 struct input_method *input_method, *next;
327
328 wl_list_for_each_safe(input_method, next,
329 &text_input->input_methods, link) {
330 if (!input_method->context)
331 continue;
332 zwp_input_method_context_v1_send_commit_state(
333 input_method->context->resource, serial);
334 }
335 }
336
337 static void
text_input_show_input_panel(struct wl_client * client,struct wl_resource * resource)338 text_input_show_input_panel(struct wl_client *client,
339 struct wl_resource *resource)
340 {
341 struct text_input *text_input = wl_resource_get_user_data(resource);
342 struct weston_compositor *ec = text_input->ec;
343
344 text_input->input_panel_visible = true;
345
346 if (!wl_list_empty(&text_input->input_methods) &&
347 text_input == text_input->manager->current_text_input) {
348 wl_signal_emit(&ec->show_input_panel_signal,
349 text_input->surface);
350 wl_signal_emit(&ec->update_input_panel_signal,
351 &text_input->cursor_rectangle);
352 }
353 }
354
355 static void
text_input_hide_input_panel(struct wl_client * client,struct wl_resource * resource)356 text_input_hide_input_panel(struct wl_client *client,
357 struct wl_resource *resource)
358 {
359 struct text_input *text_input = wl_resource_get_user_data(resource);
360 struct weston_compositor *ec = text_input->ec;
361
362 text_input->input_panel_visible = false;
363
364 if (!wl_list_empty(&text_input->input_methods) &&
365 text_input == text_input->manager->current_text_input)
366 wl_signal_emit(&ec->hide_input_panel_signal, ec);
367 }
368
369 static void
text_input_set_preferred_language(struct wl_client * client,struct wl_resource * resource,const char * language)370 text_input_set_preferred_language(struct wl_client *client,
371 struct wl_resource *resource,
372 const char *language)
373 {
374 struct text_input *text_input = wl_resource_get_user_data(resource);
375 struct input_method *input_method, *next;
376
377 wl_list_for_each_safe(input_method, next,
378 &text_input->input_methods, link) {
379 if (!input_method->context)
380 continue;
381 zwp_input_method_context_v1_send_preferred_language(
382 input_method->context->resource, language);
383 }
384 }
385
386 static const struct zwp_text_input_v1_interface text_input_implementation = {
387 text_input_activate,
388 text_input_deactivate,
389 text_input_show_input_panel,
390 text_input_hide_input_panel,
391 text_input_reset,
392 text_input_set_surrounding_text,
393 text_input_set_content_type,
394 text_input_set_cursor_rectangle,
395 text_input_set_preferred_language,
396 text_input_commit_state,
397 text_input_invoke_action
398 };
399
text_input_manager_create_text_input(struct wl_client * client,struct wl_resource * resource,uint32_t id)400 static void text_input_manager_create_text_input(struct wl_client *client,
401 struct wl_resource *resource,
402 uint32_t id)
403 {
404 struct text_input_manager *text_input_manager =
405 wl_resource_get_user_data(resource);
406 struct text_input *text_input;
407
408 text_input = zalloc(sizeof *text_input);
409 if (text_input == NULL)
410 return;
411
412 text_input->resource =
413 wl_resource_create(client, &zwp_text_input_v1_interface, 1, id);
414 wl_resource_set_implementation(text_input->resource,
415 &text_input_implementation,
416 text_input, destroy_text_input);
417
418 text_input->ec = text_input_manager->ec;
419 text_input->manager = text_input_manager;
420
421 wl_list_init(&text_input->input_methods);
422 };
423
424 static const struct zwp_text_input_manager_v1_interface manager_implementation = {
425 text_input_manager_create_text_input
426 };
427
428 static void
bind_text_input_manager(struct wl_client * client,void * data,uint32_t version,uint32_t id)429 bind_text_input_manager(struct wl_client *client,
430 void *data,
431 uint32_t version,
432 uint32_t id)
433 {
434 struct text_input_manager *text_input_manager = data;
435 struct wl_resource *resource;
436
437 /* No checking for duplicate binding necessary. */
438 resource =
439 wl_resource_create(client,
440 &zwp_text_input_manager_v1_interface, 1, id);
441 if (resource)
442 wl_resource_set_implementation(resource,
443 &manager_implementation,
444 text_input_manager, NULL);
445 }
446
447 static void
text_input_manager_notifier_destroy(struct wl_listener * listener,void * data)448 text_input_manager_notifier_destroy(struct wl_listener *listener, void *data)
449 {
450 struct text_input_manager *text_input_manager =
451 container_of(listener,
452 struct text_input_manager,
453 destroy_listener);
454
455 wl_list_remove(&text_input_manager->destroy_listener.link);
456 wl_global_destroy(text_input_manager->text_input_manager_global);
457
458 free(text_input_manager);
459 }
460
461 static void
text_input_manager_create(struct weston_compositor * ec)462 text_input_manager_create(struct weston_compositor *ec)
463 {
464 struct text_input_manager *text_input_manager;
465
466 text_input_manager = zalloc(sizeof *text_input_manager);
467 if (text_input_manager == NULL)
468 return;
469
470 text_input_manager->ec = ec;
471
472 text_input_manager->text_input_manager_global =
473 wl_global_create(ec->wl_display,
474 &zwp_text_input_manager_v1_interface, 1,
475 text_input_manager, bind_text_input_manager);
476
477 text_input_manager->destroy_listener.notify =
478 text_input_manager_notifier_destroy;
479 wl_signal_add(&ec->destroy_signal,
480 &text_input_manager->destroy_listener);
481 }
482
483 static void
input_method_context_destroy(struct wl_client * client,struct wl_resource * resource)484 input_method_context_destroy(struct wl_client *client,
485 struct wl_resource *resource)
486 {
487 wl_resource_destroy(resource);
488 }
489
490 static void
input_method_context_commit_string(struct wl_client * client,struct wl_resource * resource,uint32_t serial,const char * text)491 input_method_context_commit_string(struct wl_client *client,
492 struct wl_resource *resource,
493 uint32_t serial,
494 const char *text)
495 {
496 struct input_method_context *context =
497 wl_resource_get_user_data(resource);
498
499 if (context->input)
500 zwp_text_input_v1_send_commit_string(context->input->resource,
501 serial, text);
502 }
503
504 static void
input_method_context_preedit_string(struct wl_client * client,struct wl_resource * resource,uint32_t serial,const char * text,const char * commit)505 input_method_context_preedit_string(struct wl_client *client,
506 struct wl_resource *resource,
507 uint32_t serial,
508 const char *text,
509 const char *commit)
510 {
511 struct input_method_context *context =
512 wl_resource_get_user_data(resource);
513
514 if (context->input)
515 zwp_text_input_v1_send_preedit_string(context->input->resource,
516 serial, text, commit);
517 }
518
519 static void
input_method_context_preedit_styling(struct wl_client * client,struct wl_resource * resource,uint32_t index,uint32_t length,uint32_t style)520 input_method_context_preedit_styling(struct wl_client *client,
521 struct wl_resource *resource,
522 uint32_t index,
523 uint32_t length,
524 uint32_t style)
525 {
526 struct input_method_context *context =
527 wl_resource_get_user_data(resource);
528
529 if (context->input)
530 zwp_text_input_v1_send_preedit_styling(context->input->resource,
531 index, length, style);
532 }
533
534 static void
input_method_context_preedit_cursor(struct wl_client * client,struct wl_resource * resource,int32_t cursor)535 input_method_context_preedit_cursor(struct wl_client *client,
536 struct wl_resource *resource,
537 int32_t cursor)
538 {
539 struct input_method_context *context =
540 wl_resource_get_user_data(resource);
541
542 if (context->input)
543 zwp_text_input_v1_send_preedit_cursor(context->input->resource,
544 cursor);
545 }
546
547 static void
input_method_context_delete_surrounding_text(struct wl_client * client,struct wl_resource * resource,int32_t index,uint32_t length)548 input_method_context_delete_surrounding_text(struct wl_client *client,
549 struct wl_resource *resource,
550 int32_t index,
551 uint32_t length)
552 {
553 struct input_method_context *context =
554 wl_resource_get_user_data(resource);
555
556 if (context->input)
557 zwp_text_input_v1_send_delete_surrounding_text(
558 context->input->resource, index, length);
559 }
560
561 static void
input_method_context_cursor_position(struct wl_client * client,struct wl_resource * resource,int32_t index,int32_t anchor)562 input_method_context_cursor_position(struct wl_client *client,
563 struct wl_resource *resource,
564 int32_t index,
565 int32_t anchor)
566 {
567 struct input_method_context *context =
568 wl_resource_get_user_data(resource);
569
570 if (context->input)
571 zwp_text_input_v1_send_cursor_position(context->input->resource,
572 index, anchor);
573 }
574
575 static void
input_method_context_modifiers_map(struct wl_client * client,struct wl_resource * resource,struct wl_array * map)576 input_method_context_modifiers_map(struct wl_client *client,
577 struct wl_resource *resource,
578 struct wl_array *map)
579 {
580 struct input_method_context *context =
581 wl_resource_get_user_data(resource);
582
583 if (context->input)
584 zwp_text_input_v1_send_modifiers_map(context->input->resource,
585 map);
586 }
587
588 static void
input_method_context_keysym(struct wl_client * client,struct wl_resource * resource,uint32_t serial,uint32_t time,uint32_t sym,uint32_t state,uint32_t modifiers)589 input_method_context_keysym(struct wl_client *client,
590 struct wl_resource *resource,
591 uint32_t serial,
592 uint32_t time,
593 uint32_t sym,
594 uint32_t state,
595 uint32_t modifiers)
596 {
597 struct input_method_context *context =
598 wl_resource_get_user_data(resource);
599
600 if (context->input)
601 zwp_text_input_v1_send_keysym(context->input->resource,
602 serial, time,
603 sym, state, modifiers);
604 }
605
606 static void
unbind_keyboard(struct wl_resource * resource)607 unbind_keyboard(struct wl_resource *resource)
608 {
609 struct input_method_context *context =
610 wl_resource_get_user_data(resource);
611
612 input_method_context_end_keyboard_grab(context);
613 context->keyboard = NULL;
614 }
615
616 static void
input_method_context_grab_key(struct weston_keyboard_grab * grab,const struct timespec * time,uint32_t key,uint32_t state_w)617 input_method_context_grab_key(struct weston_keyboard_grab *grab,
618 const struct timespec *time, uint32_t key,
619 uint32_t state_w)
620 {
621 struct weston_keyboard *keyboard = grab->keyboard;
622 struct wl_display *display;
623 uint32_t serial;
624 uint32_t msecs;
625
626 if (!keyboard->input_method_resource)
627 return;
628
629 display = wl_client_get_display(
630 wl_resource_get_client(keyboard->input_method_resource));
631 serial = wl_display_next_serial(display);
632 msecs = timespec_to_msec(time);
633 wl_keyboard_send_key(keyboard->input_method_resource,
634 serial, msecs, key, state_w);
635 }
636
637 static void
input_method_context_grab_modifier(struct weston_keyboard_grab * grab,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)638 input_method_context_grab_modifier(struct weston_keyboard_grab *grab,
639 uint32_t serial,
640 uint32_t mods_depressed,
641 uint32_t mods_latched,
642 uint32_t mods_locked,
643 uint32_t group)
644 {
645 struct weston_keyboard *keyboard = grab->keyboard;
646
647 if (!keyboard->input_method_resource)
648 return;
649
650 wl_keyboard_send_modifiers(keyboard->input_method_resource,
651 serial, mods_depressed, mods_latched,
652 mods_locked, group);
653 }
654
655 static void
input_method_context_grab_cancel(struct weston_keyboard_grab * grab)656 input_method_context_grab_cancel(struct weston_keyboard_grab *grab)
657 {
658 weston_keyboard_end_grab(grab->keyboard);
659 }
660
661 static const struct weston_keyboard_grab_interface input_method_context_grab = {
662 input_method_context_grab_key,
663 input_method_context_grab_modifier,
664 input_method_context_grab_cancel,
665 };
666
667 static void
input_method_context_grab_keyboard(struct wl_client * client,struct wl_resource * resource,uint32_t id)668 input_method_context_grab_keyboard(struct wl_client *client,
669 struct wl_resource *resource,
670 uint32_t id)
671 {
672 struct input_method_context *context =
673 wl_resource_get_user_data(resource);
674 struct wl_resource *cr;
675 struct weston_seat *seat = context->input_method->seat;
676 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
677
678 cr = wl_resource_create(client, &wl_keyboard_interface, 1, id);
679 wl_resource_set_implementation(cr, NULL, context, unbind_keyboard);
680
681 context->keyboard = cr;
682
683 weston_keyboard_send_keymap(keyboard, cr);
684
685 if (keyboard->grab != &keyboard->default_grab) {
686 weston_keyboard_end_grab(keyboard);
687 }
688 weston_keyboard_start_grab(keyboard, &keyboard->input_method_grab);
689 keyboard->input_method_resource = cr;
690 }
691
692 static void
input_method_context_key(struct wl_client * client,struct wl_resource * resource,uint32_t serial,uint32_t time,uint32_t key,uint32_t state_w)693 input_method_context_key(struct wl_client *client,
694 struct wl_resource *resource,
695 uint32_t serial,
696 uint32_t time,
697 uint32_t key,
698 uint32_t state_w)
699 {
700 struct input_method_context *context =
701 wl_resource_get_user_data(resource);
702 struct weston_seat *seat = context->input_method->seat;
703 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
704 struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
705 struct timespec ts;
706
707 timespec_from_msec(&ts, time);
708
709 default_grab->interface->key(default_grab, &ts, key, state_w);
710 }
711
712 static void
input_method_context_modifiers(struct wl_client * client,struct wl_resource * resource,uint32_t serial,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)713 input_method_context_modifiers(struct wl_client *client,
714 struct wl_resource *resource,
715 uint32_t serial,
716 uint32_t mods_depressed,
717 uint32_t mods_latched,
718 uint32_t mods_locked,
719 uint32_t group)
720 {
721 struct input_method_context *context =
722 wl_resource_get_user_data(resource);
723
724 struct weston_seat *seat = context->input_method->seat;
725 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
726 struct weston_keyboard_grab *default_grab = &keyboard->default_grab;
727
728 default_grab->interface->modifiers(default_grab,
729 serial, mods_depressed,
730 mods_latched, mods_locked,
731 group);
732 }
733
734 static void
input_method_context_language(struct wl_client * client,struct wl_resource * resource,uint32_t serial,const char * language)735 input_method_context_language(struct wl_client *client,
736 struct wl_resource *resource,
737 uint32_t serial,
738 const char *language)
739 {
740 struct input_method_context *context =
741 wl_resource_get_user_data(resource);
742
743 if (context->input)
744 zwp_text_input_v1_send_language(context->input->resource,
745 serial, language);
746 }
747
748 static void
input_method_context_text_direction(struct wl_client * client,struct wl_resource * resource,uint32_t serial,uint32_t direction)749 input_method_context_text_direction(struct wl_client *client,
750 struct wl_resource *resource,
751 uint32_t serial,
752 uint32_t direction)
753 {
754 struct input_method_context *context =
755 wl_resource_get_user_data(resource);
756
757 if (context->input)
758 zwp_text_input_v1_send_text_direction(context->input->resource,
759 serial, direction);
760 }
761
762
763 static const struct zwp_input_method_context_v1_interface context_implementation = {
764 input_method_context_destroy,
765 input_method_context_commit_string,
766 input_method_context_preedit_string,
767 input_method_context_preedit_styling,
768 input_method_context_preedit_cursor,
769 input_method_context_delete_surrounding_text,
770 input_method_context_cursor_position,
771 input_method_context_modifiers_map,
772 input_method_context_keysym,
773 input_method_context_grab_keyboard,
774 input_method_context_key,
775 input_method_context_modifiers,
776 input_method_context_language,
777 input_method_context_text_direction
778 };
779
780 static void
destroy_input_method_context(struct wl_resource * resource)781 destroy_input_method_context(struct wl_resource *resource)
782 {
783 struct input_method_context *context =
784 wl_resource_get_user_data(resource);
785
786 if (context->keyboard)
787 wl_resource_destroy(context->keyboard);
788
789 if (context->input_method && context->input_method->context == context)
790 context->input_method->context = NULL;
791
792 free(context);
793 }
794
795 static void
input_method_context_create(struct text_input * input,struct input_method * input_method)796 input_method_context_create(struct text_input *input,
797 struct input_method *input_method)
798 {
799 struct input_method_context *context;
800 struct wl_resource *binding;
801
802 if (!input_method->input_method_binding)
803 return;
804
805 context = zalloc(sizeof *context);
806 if (context == NULL)
807 return;
808
809 binding = input_method->input_method_binding;
810 context->resource =
811 wl_resource_create(wl_resource_get_client(binding),
812 &zwp_input_method_context_v1_interface,
813 1, 0);
814 wl_resource_set_implementation(context->resource,
815 &context_implementation,
816 context, destroy_input_method_context);
817
818 context->input = input;
819 context->input_method = input_method;
820 input_method->context = context;
821
822
823 zwp_input_method_v1_send_activate(binding, context->resource);
824 }
825
826 static void
input_method_context_end_keyboard_grab(struct input_method_context * context)827 input_method_context_end_keyboard_grab(struct input_method_context *context)
828 {
829 struct weston_keyboard_grab *grab;
830 struct weston_keyboard *keyboard;
831
832 keyboard = weston_seat_get_keyboard(context->input_method->seat);
833 if (!keyboard)
834 return;
835
836 grab = &keyboard->input_method_grab;
837 keyboard = grab->keyboard;
838 if (!keyboard)
839 return;
840
841 if (keyboard->grab == grab)
842 weston_keyboard_end_grab(keyboard);
843
844 keyboard->input_method_resource = NULL;
845 }
846
847 static void
unbind_input_method(struct wl_resource * resource)848 unbind_input_method(struct wl_resource *resource)
849 {
850 struct input_method *input_method = wl_resource_get_user_data(resource);
851
852 input_method->input_method_binding = NULL;
853 input_method->context = NULL;
854 }
855
856 static void
bind_input_method(struct wl_client * client,void * data,uint32_t version,uint32_t id)857 bind_input_method(struct wl_client *client,
858 void *data,
859 uint32_t version,
860 uint32_t id)
861 {
862 struct input_method *input_method = data;
863 struct text_backend *text_backend = input_method->text_backend;
864 struct wl_resource *resource;
865
866 resource =
867 wl_resource_create(client,
868 &zwp_input_method_v1_interface, 1, id);
869
870 if (input_method->input_method_binding != NULL) {
871 wl_resource_post_error(resource,
872 WL_DISPLAY_ERROR_INVALID_OBJECT,
873 "interface object already bound");
874 return;
875 }
876
877 if (text_backend->input_method.client != client) {
878 wl_resource_post_error(resource,
879 WL_DISPLAY_ERROR_INVALID_OBJECT,
880 "permission to bind "
881 "input_method denied");
882 return;
883 }
884
885 wl_resource_set_implementation(resource, NULL, input_method,
886 unbind_input_method);
887 input_method->input_method_binding = resource;
888 }
889
890 static void
input_method_notifier_destroy(struct wl_listener * listener,void * data)891 input_method_notifier_destroy(struct wl_listener *listener, void *data)
892 {
893 struct input_method *input_method =
894 container_of(listener, struct input_method, destroy_listener);
895
896 if (input_method->input)
897 deactivate_input_method(input_method);
898
899 wl_global_destroy(input_method->input_method_global);
900 wl_list_remove(&input_method->destroy_listener.link);
901
902 free(input_method);
903 }
904
905 static void
handle_keyboard_focus(struct wl_listener * listener,void * data)906 handle_keyboard_focus(struct wl_listener *listener, void *data)
907 {
908 struct weston_keyboard *keyboard = data;
909 struct input_method *input_method =
910 container_of(listener, struct input_method,
911 keyboard_focus_listener);
912 struct weston_surface *surface = keyboard->focus;
913
914 if (!input_method->input)
915 return;
916
917 if (!surface || input_method->input->surface != surface)
918 deactivate_input_method(input_method);
919 }
920
921 static void
input_method_init_seat(struct weston_seat * seat)922 input_method_init_seat(struct weston_seat *seat)
923 {
924 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
925
926 if (seat->input_method->focus_listener_initialized)
927 return;
928
929 if (keyboard) {
930 seat->input_method->keyboard_focus_listener.notify =
931 handle_keyboard_focus;
932 wl_signal_add(&keyboard->focus_signal,
933 &seat->input_method->keyboard_focus_listener);
934 keyboard->input_method_grab.interface =
935 &input_method_context_grab;
936 }
937
938 seat->input_method->focus_listener_initialized = true;
939 }
940
941 static void launch_input_method(struct text_backend *text_backend);
942
943 static void
respawn_input_method_process(struct text_backend * text_backend)944 respawn_input_method_process(struct text_backend *text_backend)
945 {
946 struct timespec time;
947 int64_t tdiff;
948
949 /* if input_method dies more than 5 times in 10 seconds, give up */
950 weston_compositor_get_time(&time);
951 tdiff = timespec_sub_to_msec(&time,
952 &text_backend->input_method.deathstamp);
953 if (tdiff > 10000) {
954 text_backend->input_method.deathstamp = time;
955 text_backend->input_method.deathcount = 0;
956 }
957
958 text_backend->input_method.deathcount++;
959 if (text_backend->input_method.deathcount > 5) {
960 weston_log("input_method disconnected, giving up.\n");
961 return;
962 }
963
964 weston_log("input_method disconnected, respawning...\n");
965 launch_input_method(text_backend);
966 }
967
968 static void
input_method_client_notifier(struct wl_listener * listener,void * data)969 input_method_client_notifier(struct wl_listener *listener, void *data)
970 {
971 struct text_backend *text_backend;
972
973 text_backend = container_of(listener, struct text_backend,
974 client_listener);
975
976 text_backend->input_method.client = NULL;
977 respawn_input_method_process(text_backend);
978 }
979
980 static void
launch_input_method(struct text_backend * text_backend)981 launch_input_method(struct text_backend *text_backend)
982 {
983 if (!text_backend->input_method.path)
984 return;
985
986 if (strcmp(text_backend->input_method.path, "") == 0)
987 return;
988
989 text_backend->input_method.client =
990 weston_client_start(text_backend->compositor,
991 text_backend->input_method.path);
992
993 if (!text_backend->input_method.client) {
994 weston_log("not able to start %s\n",
995 text_backend->input_method.path);
996 return;
997 }
998
999 text_backend->client_listener.notify = input_method_client_notifier;
1000 wl_client_add_destroy_listener(text_backend->input_method.client,
1001 &text_backend->client_listener);
1002 }
1003
1004 static void
text_backend_seat_created(struct text_backend * text_backend,struct weston_seat * seat)1005 text_backend_seat_created(struct text_backend *text_backend,
1006 struct weston_seat *seat)
1007 {
1008 struct input_method *input_method;
1009 struct weston_compositor *ec = seat->compositor;
1010
1011 input_method = zalloc(sizeof *input_method);
1012 if (input_method == NULL)
1013 return;
1014
1015 input_method->seat = seat;
1016 input_method->input = NULL;
1017 input_method->focus_listener_initialized = false;
1018 input_method->context = NULL;
1019 input_method->text_backend = text_backend;
1020
1021 input_method->input_method_global =
1022 wl_global_create(ec->wl_display,
1023 &zwp_input_method_v1_interface, 1,
1024 input_method, bind_input_method);
1025
1026 input_method->destroy_listener.notify = input_method_notifier_destroy;
1027 wl_signal_add(&seat->destroy_signal, &input_method->destroy_listener);
1028
1029 seat->input_method = input_method;
1030 }
1031
1032 static void
handle_seat_created(struct wl_listener * listener,void * data)1033 handle_seat_created(struct wl_listener *listener, void *data)
1034 {
1035 struct weston_seat *seat = data;
1036 struct text_backend *text_backend =
1037 container_of(listener, struct text_backend,
1038 seat_created_listener);
1039
1040 text_backend_seat_created(text_backend, seat);
1041 }
1042
1043 static void
text_backend_configuration(struct text_backend * text_backend)1044 text_backend_configuration(struct text_backend *text_backend)
1045 {
1046 struct weston_config *config = wet_get_config(text_backend->compositor);
1047 struct weston_config_section *section;
1048 char *client;
1049
1050 section = weston_config_get_section(config,
1051 "input-method", NULL, NULL);
1052 client = wet_get_libexec_path("weston-keyboard");
1053 weston_config_section_get_string(section, "path",
1054 &text_backend->input_method.path,
1055 client);
1056 free(client);
1057 }
1058
1059 WL_EXPORT void
text_backend_destroy(struct text_backend * text_backend)1060 text_backend_destroy(struct text_backend *text_backend)
1061 {
1062 wl_list_remove(&text_backend->seat_created_listener.link);
1063
1064 if (text_backend->input_method.client) {
1065 /* disable respawn */
1066 wl_list_remove(&text_backend->client_listener.link);
1067 wl_client_destroy(text_backend->input_method.client);
1068 }
1069
1070 free(text_backend->input_method.path);
1071 free(text_backend);
1072 }
1073
1074 WL_EXPORT struct text_backend *
text_backend_init(struct weston_compositor * ec)1075 text_backend_init(struct weston_compositor *ec)
1076 {
1077 struct text_backend *text_backend;
1078 struct weston_seat *seat;
1079
1080 text_backend = zalloc(sizeof(*text_backend));
1081 if (text_backend == NULL)
1082 return NULL;
1083
1084 text_backend->compositor = ec;
1085
1086 text_backend_configuration(text_backend);
1087
1088 wl_list_for_each(seat, &ec->seat_list, link)
1089 text_backend_seat_created(text_backend, seat);
1090 text_backend->seat_created_listener.notify = handle_seat_created;
1091 wl_signal_add(&ec->seat_created_signal,
1092 &text_backend->seat_created_listener);
1093
1094 text_input_manager_create(ec);
1095
1096 launch_input_method(text_backend);
1097
1098 return text_backend;
1099 }
1100