1 /*
2  * Copyright (C) 2017, 2018 Red Hat
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  *
19  * Author: Carlos Garnacho <carlosg@gnome.org>
20  */
21 
22 #include "config.h"
23 
24 #include <wayland-server.h>
25 
26 #include "wayland/meta-wayland-private.h"
27 #include "wayland/meta-wayland-seat.h"
28 #include "wayland/meta-wayland-text-input-legacy.h"
29 #include "wayland/meta-wayland-versions.h"
30 
31 #include "gtk-text-input-server-protocol.h"
32 
33 #define META_TYPE_WAYLAND_GTK_TEXT_INPUT_FOCUS (meta_wayland_gtk_text_input_focus_get_type ())
34 
35 typedef enum
36 {
37   META_WAYLAND_PENDING_STATE_NONE             = 0,
38   META_WAYLAND_PENDING_STATE_INPUT_RECT       = 1 << 0,
39   META_WAYLAND_PENDING_STATE_CONTENT_TYPE     = 1 << 1,
40   META_WAYLAND_PENDING_STATE_SURROUNDING_TEXT = 1 << 2,
41 } MetaWaylandTextInputPendingState;
42 
43 typedef struct _MetaWaylandGtkTextInput MetaWaylandGtkTextInput;
44 
45 struct _MetaWaylandGtkTextInput
46 {
47   MetaWaylandSeat *seat;
48   ClutterInputFocus *input_focus;
49 
50   struct wl_list resource_list;
51   struct wl_list focus_resource_list;
52   MetaWaylandSurface *surface;
53   struct wl_listener surface_listener;
54   uint32_t focus_serial;
55 
56   MetaWaylandTextInputPendingState pending_state;
57 
58   struct
59   {
60     char *text;
61     uint32_t cursor;
62     uint32_t anchor;
63   } surrounding;
64 
65   cairo_rectangle_int_t cursor_rect;
66 
67   uint32_t content_type_hint;
68   uint32_t content_type_purpose;
69 };
70 
71 struct _MetaWaylandGtkTextInputFocus
72 {
73   ClutterInputFocus parent_instance;
74   MetaWaylandGtkTextInput *text_input;
75 };
76 
G_DECLARE_FINAL_TYPE(MetaWaylandGtkTextInputFocus,meta_wayland_gtk_text_input_focus,META,WAYLAND_GTK_TEXT_INPUT_FOCUS,ClutterInputFocus)77 G_DECLARE_FINAL_TYPE (MetaWaylandGtkTextInputFocus,
78                       meta_wayland_gtk_text_input_focus,
79                       META, WAYLAND_GTK_TEXT_INPUT_FOCUS, ClutterInputFocus)
80 G_DEFINE_TYPE (MetaWaylandGtkTextInputFocus, meta_wayland_gtk_text_input_focus,
81                CLUTTER_TYPE_INPUT_FOCUS)
82 
83 static void
84 meta_wayland_text_input_focus_request_surrounding (ClutterInputFocus *focus)
85 {
86   MetaWaylandGtkTextInput *text_input;
87 
88   text_input = META_WAYLAND_GTK_TEXT_INPUT_FOCUS (focus)->text_input;
89   clutter_input_focus_set_surrounding (focus,
90 				       text_input->surrounding.text,
91 				       text_input->surrounding.cursor,
92                                        text_input->surrounding.anchor);
93 }
94 
95 static void
meta_wayland_text_input_focus_delete_surrounding(ClutterInputFocus * focus,int offset,guint len)96 meta_wayland_text_input_focus_delete_surrounding (ClutterInputFocus *focus,
97                                                   int                offset,
98                                                   guint              len)
99 {
100   MetaWaylandGtkTextInput *text_input;
101   uint32_t before_length;
102   uint32_t after_length;
103   struct wl_resource *resource;
104 
105   text_input = META_WAYLAND_GTK_TEXT_INPUT_FOCUS (focus)->text_input;
106   before_length = ABS (MIN (offset, 0));
107   after_length = MAX (0, offset + len);
108   g_warn_if_fail (ABS (offset) <= len);
109 
110   wl_resource_for_each (resource, &text_input->focus_resource_list)
111     {
112       gtk_text_input_send_delete_surrounding_text (resource,
113                                                    before_length,
114                                                    after_length);
115     }
116 }
117 
118 static void
meta_wayland_text_input_focus_commit_text(ClutterInputFocus * focus,const gchar * text)119 meta_wayland_text_input_focus_commit_text (ClutterInputFocus *focus,
120                                            const gchar       *text)
121 {
122   MetaWaylandGtkTextInput *text_input;
123   struct wl_resource *resource;
124 
125   text_input = META_WAYLAND_GTK_TEXT_INPUT_FOCUS (focus)->text_input;
126 
127   wl_resource_for_each (resource, &text_input->focus_resource_list)
128     {
129       gtk_text_input_send_preedit_string (resource, NULL, 0);
130       gtk_text_input_send_commit_string (resource, text);
131     }
132 }
133 
134 static void
meta_wayland_text_input_focus_set_preedit_text(ClutterInputFocus * focus,const gchar * text,guint cursor)135 meta_wayland_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
136                                                 const gchar       *text,
137                                                 guint              cursor)
138 {
139   MetaWaylandGtkTextInput *text_input;
140   struct wl_resource *resource;
141 
142   text_input = META_WAYLAND_GTK_TEXT_INPUT_FOCUS (focus)->text_input;
143 
144   wl_resource_for_each (resource, &text_input->focus_resource_list)
145     {
146       gtk_text_input_send_preedit_string (resource, text, cursor);
147     }
148 }
149 
150 static void
meta_wayland_gtk_text_input_focus_class_init(MetaWaylandGtkTextInputFocusClass * klass)151 meta_wayland_gtk_text_input_focus_class_init (MetaWaylandGtkTextInputFocusClass *klass)
152 {
153   ClutterInputFocusClass *focus_class = CLUTTER_INPUT_FOCUS_CLASS (klass);
154 
155   focus_class->request_surrounding = meta_wayland_text_input_focus_request_surrounding;
156   focus_class->delete_surrounding = meta_wayland_text_input_focus_delete_surrounding;
157   focus_class->commit_text = meta_wayland_text_input_focus_commit_text;
158   focus_class->set_preedit_text = meta_wayland_text_input_focus_set_preedit_text;
159 }
160 
161 static void
meta_wayland_gtk_text_input_focus_init(MetaWaylandGtkTextInputFocus * focus)162 meta_wayland_gtk_text_input_focus_init (MetaWaylandGtkTextInputFocus *focus)
163 {
164 }
165 
166 static ClutterInputFocus *
meta_wayland_text_input_focus_new(MetaWaylandGtkTextInput * text_input)167 meta_wayland_text_input_focus_new (MetaWaylandGtkTextInput *text_input)
168 {
169   MetaWaylandGtkTextInputFocus *focus;
170 
171   focus = g_object_new (META_TYPE_WAYLAND_GTK_TEXT_INPUT_FOCUS, NULL);
172   focus->text_input = text_input;
173 
174   return CLUTTER_INPUT_FOCUS (focus);
175 }
176 
177 static void
text_input_handle_focus_surface_destroy(struct wl_listener * listener,void * data)178 text_input_handle_focus_surface_destroy (struct wl_listener *listener,
179 					 void               *data)
180 {
181   MetaWaylandGtkTextInput *text_input = wl_container_of (listener, text_input,
182                                                          surface_listener);
183 
184   meta_wayland_gtk_text_input_set_focus (text_input, NULL);
185 }
186 
187 static void
move_resources(struct wl_list * destination,struct wl_list * source)188 move_resources (struct wl_list *destination, struct wl_list *source)
189 {
190   wl_list_insert_list (destination, source);
191   wl_list_init (source);
192 }
193 
194 static void
move_resources_for_client(struct wl_list * destination,struct wl_list * source,struct wl_client * client)195 move_resources_for_client (struct wl_list *destination,
196 			   struct wl_list *source,
197 			   struct wl_client *client)
198 {
199   struct wl_resource *resource, *tmp;
200   wl_resource_for_each_safe (resource, tmp, source)
201     {
202       if (wl_resource_get_client (resource) == client)
203         {
204           wl_list_remove (wl_resource_get_link (resource));
205           wl_list_insert (destination, wl_resource_get_link (resource));
206         }
207     }
208 }
209 
210 void
meta_wayland_gtk_text_input_set_focus(MetaWaylandGtkTextInput * text_input,MetaWaylandSurface * surface)211 meta_wayland_gtk_text_input_set_focus (MetaWaylandGtkTextInput *text_input,
212                                        MetaWaylandSurface      *surface)
213 {
214   if (text_input->surface == surface)
215     return;
216 
217   text_input->pending_state = META_WAYLAND_PENDING_STATE_NONE;
218 
219   if (text_input->surface)
220     {
221       if (!wl_list_empty (&text_input->focus_resource_list))
222         {
223           ClutterInputFocus *focus = text_input->input_focus;
224           ClutterInputMethod *input_method;
225           struct wl_resource *resource;
226           uint32_t serial;
227 
228           if (clutter_input_focus_is_focused (focus))
229             {
230               input_method = clutter_backend_get_input_method (clutter_get_default_backend ());
231               clutter_input_method_focus_out (input_method);
232             }
233 
234           serial = wl_display_next_serial (text_input->seat->wl_display);
235 
236           wl_resource_for_each (resource, &text_input->focus_resource_list)
237             {
238               gtk_text_input_send_leave (resource, serial,
239                                          text_input->surface->resource);
240             }
241 
242           move_resources (&text_input->resource_list,
243                           &text_input->focus_resource_list);
244         }
245 
246       wl_list_remove (&text_input->surface_listener.link);
247       text_input->surface = NULL;
248     }
249 
250   if (surface)
251     {
252       struct wl_resource *focus_surface_resource;
253 
254       text_input->surface = surface;
255       focus_surface_resource = text_input->surface->resource;
256       wl_resource_add_destroy_listener (focus_surface_resource,
257                                         &text_input->surface_listener);
258 
259       move_resources_for_client (&text_input->focus_resource_list,
260                                  &text_input->resource_list,
261                                  wl_resource_get_client (focus_surface_resource));
262 
263       if (!wl_list_empty (&text_input->focus_resource_list))
264         {
265           struct wl_resource *resource;
266 
267           text_input->focus_serial =
268             wl_display_next_serial (text_input->seat->wl_display);
269 
270           wl_resource_for_each (resource, &text_input->focus_resource_list)
271             {
272               gtk_text_input_send_enter (resource, text_input->focus_serial,
273                                          surface->resource);
274             }
275         }
276     }
277 }
278 
279 static void
unbind_resource(struct wl_resource * resource)280 unbind_resource (struct wl_resource *resource)
281 {
282   wl_list_remove (wl_resource_get_link (resource));
283 }
284 
285 static void
text_input_destroy(struct wl_client * client,struct wl_resource * resource)286 text_input_destroy (struct wl_client   *client,
287                     struct wl_resource *resource)
288 {
289   wl_resource_destroy (resource);
290 }
291 
292 static void
text_input_enable(struct wl_client * client,struct wl_resource * resource,uint32_t serial,uint32_t flags)293 text_input_enable (struct wl_client   *client,
294                    struct wl_resource *resource,
295                    uint32_t            serial,
296                    uint32_t            flags)
297 {
298   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
299   ClutterInputFocus *focus = text_input->input_focus;
300   ClutterInputMethod *input_method;
301   gboolean show_preedit;
302 
303   if (serial != text_input->focus_serial)
304     return;
305 
306   if (!clutter_input_focus_is_focused (focus))
307     {
308       input_method = clutter_backend_get_input_method (clutter_get_default_backend ());
309       if (input_method)
310         clutter_input_method_focus_in (input_method, focus);
311       else
312         return;
313     }
314 
315   show_preedit = (flags & GTK_TEXT_INPUT_ENABLE_FLAGS_CAN_SHOW_PREEDIT) != 0;
316   clutter_input_focus_set_can_show_preedit (focus, show_preedit);
317 
318   if (flags & GTK_TEXT_INPUT_ENABLE_FLAGS_TOGGLE_INPUT_PANEL)
319     clutter_input_focus_set_input_panel_state (focus, CLUTTER_INPUT_PANEL_STATE_TOGGLE);
320 }
321 
322 static void
text_input_disable(struct wl_client * client,struct wl_resource * resource)323 text_input_disable (struct wl_client   *client,
324                     struct wl_resource *resource)
325 {
326   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
327   ClutterInputFocus *focus = text_input->input_focus;
328   ClutterInputMethod *input_method;
329 
330   if (!clutter_input_focus_is_focused (focus))
331     return;
332 
333   clutter_input_focus_reset (text_input->input_focus);
334   text_input->pending_state = META_WAYLAND_PENDING_STATE_NONE;
335 
336   input_method = clutter_backend_get_input_method (clutter_get_default_backend ());
337   clutter_input_method_focus_out (input_method);
338 }
339 
340 static void
text_input_set_surrounding_text(struct wl_client * client,struct wl_resource * resource,const char * text,int32_t cursor,int32_t anchor)341 text_input_set_surrounding_text (struct wl_client   *client,
342                                  struct wl_resource *resource,
343                                  const char         *text,
344                                  int32_t             cursor,
345                                  int32_t             anchor)
346 {
347   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
348 
349   g_free (text_input->surrounding.text);
350   text_input->surrounding.text = g_strdup (text);
351   text_input->surrounding.cursor = cursor;
352   text_input->surrounding.anchor = anchor;
353   text_input->pending_state |= META_WAYLAND_PENDING_STATE_SURROUNDING_TEXT;
354 }
355 
356 static ClutterInputContentHintFlags
translate_hints(uint32_t hints)357 translate_hints (uint32_t hints)
358 {
359   ClutterInputContentHintFlags clutter_hints = 0;
360 
361   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_COMPLETION)
362     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_COMPLETION;
363   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_SPELLCHECK)
364     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_SPELLCHECK;
365   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION)
366     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
367   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_LOWERCASE)
368     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_LOWERCASE;
369   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_UPPERCASE)
370     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_UPPERCASE;
371   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_TITLECASE)
372     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_TITLECASE;
373   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT)
374     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_HIDDEN_TEXT;
375   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA)
376     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_SENSITIVE_DATA;
377   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_LATIN)
378     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_LATIN;
379   if (hints & GTK_TEXT_INPUT_CONTENT_HINT_MULTILINE)
380     clutter_hints |= CLUTTER_INPUT_CONTENT_HINT_MULTILINE;
381 
382   return clutter_hints;
383 }
384 
385 static ClutterInputContentPurpose
translate_purpose(uint32_t purpose)386 translate_purpose (uint32_t purpose)
387 {
388   switch (purpose)
389     {
390     case GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL:
391       return CLUTTER_INPUT_CONTENT_PURPOSE_NORMAL;
392     case GTK_TEXT_INPUT_CONTENT_PURPOSE_ALPHA:
393       return CLUTTER_INPUT_CONTENT_PURPOSE_ALPHA;
394     case GTK_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
395       return CLUTTER_INPUT_CONTENT_PURPOSE_DIGITS;
396     case GTK_TEXT_INPUT_CONTENT_PURPOSE_NUMBER:
397       return CLUTTER_INPUT_CONTENT_PURPOSE_NUMBER;
398     case GTK_TEXT_INPUT_CONTENT_PURPOSE_PHONE:
399       return CLUTTER_INPUT_CONTENT_PURPOSE_PHONE;
400     case GTK_TEXT_INPUT_CONTENT_PURPOSE_URL:
401       return CLUTTER_INPUT_CONTENT_PURPOSE_URL;
402     case GTK_TEXT_INPUT_CONTENT_PURPOSE_EMAIL:
403       return CLUTTER_INPUT_CONTENT_PURPOSE_EMAIL;
404     case GTK_TEXT_INPUT_CONTENT_PURPOSE_NAME:
405       return CLUTTER_INPUT_CONTENT_PURPOSE_NAME;
406     case GTK_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD:
407       return CLUTTER_INPUT_CONTENT_PURPOSE_PASSWORD;
408     case GTK_TEXT_INPUT_CONTENT_PURPOSE_DATE:
409       return CLUTTER_INPUT_CONTENT_PURPOSE_DATE;
410     case GTK_TEXT_INPUT_CONTENT_PURPOSE_TIME:
411       return CLUTTER_INPUT_CONTENT_PURPOSE_TIME;
412     case GTK_TEXT_INPUT_CONTENT_PURPOSE_DATETIME:
413       return CLUTTER_INPUT_CONTENT_PURPOSE_DATETIME;
414     case GTK_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL:
415       return CLUTTER_INPUT_CONTENT_PURPOSE_TERMINAL;
416     }
417 
418   g_warn_if_reached ();
419   return CLUTTER_INPUT_CONTENT_PURPOSE_NORMAL;
420 }
421 
422 static void
text_input_set_content_type(struct wl_client * client,struct wl_resource * resource,uint32_t hint,uint32_t purpose)423 text_input_set_content_type (struct wl_client   *client,
424                              struct wl_resource *resource,
425                              uint32_t            hint,
426                              uint32_t            purpose)
427 {
428   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
429 
430   if (!text_input->surface)
431     return;
432 
433   text_input->content_type_hint = hint;
434   text_input->content_type_purpose = purpose;
435   text_input->pending_state |= META_WAYLAND_PENDING_STATE_CONTENT_TYPE;
436 }
437 
438 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)439 text_input_set_cursor_rectangle (struct wl_client   *client,
440                                  struct wl_resource *resource,
441                                  int32_t             x,
442                                  int32_t             y,
443                                  int32_t             width,
444                                  int32_t             height)
445 {
446   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
447 
448   if (!text_input->surface)
449     return;
450 
451   text_input->cursor_rect = (cairo_rectangle_int_t) { x, y, width, height };
452   text_input->pending_state |= META_WAYLAND_PENDING_STATE_INPUT_RECT;
453 }
454 
455 static void
text_input_commit_state(struct wl_client * client,struct wl_resource * resource)456 text_input_commit_state (struct wl_client   *client,
457                          struct wl_resource *resource)
458 {
459   MetaWaylandGtkTextInput *text_input = wl_resource_get_user_data (resource);
460   ClutterInputFocus *focus = text_input->input_focus;
461 
462   if (!clutter_input_focus_is_focused (focus))
463     return;
464   if (text_input->surface == NULL)
465     return;
466 
467   if (text_input->pending_state & META_WAYLAND_PENDING_STATE_CONTENT_TYPE)
468     {
469       clutter_input_focus_set_content_hints (text_input->input_focus,
470                                              translate_hints (text_input->content_type_hint));
471       clutter_input_focus_set_content_purpose (text_input->input_focus,
472                                                translate_purpose (text_input->content_type_purpose));
473     }
474 
475   if (text_input->pending_state & META_WAYLAND_PENDING_STATE_SURROUNDING_TEXT)
476     {
477       clutter_input_focus_set_surrounding (text_input->input_focus,
478                                            text_input->surrounding.text,
479                                            text_input->surrounding.cursor,
480                                            text_input->surrounding.anchor);
481     }
482 
483   if (text_input->pending_state & META_WAYLAND_PENDING_STATE_INPUT_RECT)
484     {
485       graphene_rect_t cursor_rect;
486       float x1, y1, x2, y2;
487       cairo_rectangle_int_t rect;
488 
489       rect = text_input->cursor_rect;
490       meta_wayland_surface_get_absolute_coordinates (text_input->surface,
491                                                      rect.x, rect.y, &x1, &y1);
492       meta_wayland_surface_get_absolute_coordinates (text_input->surface,
493                                                      rect.x + rect.width,
494                                                      rect.y + rect.height,
495                                                      &x2, &y2);
496 
497       graphene_rect_init (&cursor_rect, x1, y1, x2 - x1, y2 - y1);
498       clutter_input_focus_set_cursor_location (text_input->input_focus,
499                                                &cursor_rect);
500     }
501 
502   text_input->pending_state = META_WAYLAND_PENDING_STATE_NONE;
503 }
504 
505 static struct gtk_text_input_interface meta_text_input_interface = {
506   text_input_destroy,
507   text_input_enable,
508   text_input_disable,
509   text_input_set_surrounding_text,
510   text_input_set_content_type,
511   text_input_set_cursor_rectangle,
512   text_input_commit_state,
513 };
514 
515 MetaWaylandGtkTextInput *
meta_wayland_gtk_text_input_new(MetaWaylandSeat * seat)516 meta_wayland_gtk_text_input_new (MetaWaylandSeat *seat)
517 {
518   MetaWaylandGtkTextInput *text_input;
519 
520   text_input = g_new0 (MetaWaylandGtkTextInput, 1);
521   text_input->input_focus = meta_wayland_text_input_focus_new (text_input);
522   text_input->seat = seat;
523 
524   wl_list_init (&text_input->resource_list);
525   wl_list_init (&text_input->focus_resource_list);
526   text_input->surface_listener.notify = text_input_handle_focus_surface_destroy;
527 
528   return text_input;
529 }
530 
531 void
meta_wayland_gtk_text_input_destroy(MetaWaylandGtkTextInput * text_input)532 meta_wayland_gtk_text_input_destroy (MetaWaylandGtkTextInput *text_input)
533 {
534   meta_wayland_gtk_text_input_set_focus (text_input, NULL);
535   g_object_unref (text_input->input_focus);
536   g_free (text_input);
537 }
538 
539 static void
meta_wayland_text_input_create_new_resource(MetaWaylandGtkTextInput * text_input,struct wl_client * client,struct wl_resource * seat_resource,uint32_t id)540 meta_wayland_text_input_create_new_resource (MetaWaylandGtkTextInput *text_input,
541                                              struct wl_client        *client,
542                                              struct wl_resource      *seat_resource,
543                                              uint32_t                 id)
544 {
545   struct wl_resource *text_input_resource;
546 
547   text_input_resource = wl_resource_create (client,
548                                             &gtk_text_input_interface,
549                                             META_GTK_TEXT_INPUT_VERSION,
550                                             id);
551 
552   wl_resource_set_implementation (text_input_resource,
553                                   &meta_text_input_interface,
554                                   text_input, unbind_resource);
555 
556   if (text_input->surface &&
557       wl_resource_get_client (text_input->surface->resource) == client)
558     {
559       wl_list_insert (&text_input->focus_resource_list,
560                       wl_resource_get_link (text_input_resource));
561 
562       gtk_text_input_send_enter (text_input_resource,
563                                  text_input->focus_serial,
564                                  text_input->surface->resource);
565     }
566   else
567     {
568       wl_list_insert (&text_input->resource_list,
569                       wl_resource_get_link (text_input_resource));
570     }
571 }
572 
573 static void
text_input_manager_destroy(struct wl_client * client,struct wl_resource * resource)574 text_input_manager_destroy (struct wl_client   *client,
575                             struct wl_resource *resource)
576 {
577   wl_resource_destroy (resource);
578 }
579 
580 static void
text_input_manager_get_text_input(struct wl_client * client,struct wl_resource * resource,uint32_t id,struct wl_resource * seat_resource)581 text_input_manager_get_text_input (struct wl_client   *client,
582                                    struct wl_resource *resource,
583                                    uint32_t            id,
584                                    struct wl_resource *seat_resource)
585 {
586   MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
587 
588   meta_wayland_text_input_create_new_resource (seat->gtk_text_input, client,
589                                                seat_resource, id);
590 }
591 
592 static struct gtk_text_input_manager_interface meta_text_input_manager_interface = {
593   text_input_manager_destroy,
594   text_input_manager_get_text_input,
595 };
596 
597 static void
bind_text_input(struct wl_client * client,void * data,uint32_t version,uint32_t id)598 bind_text_input (struct wl_client *client,
599 		 void             *data,
600 		 uint32_t          version,
601 		 uint32_t          id)
602 {
603   struct wl_resource *resource;
604 
605   resource = wl_resource_create (client,
606                                  &gtk_text_input_manager_interface,
607 				 META_GTK_TEXT_INPUT_VERSION,
608                                  id);
609   wl_resource_set_implementation (resource,
610                                   &meta_text_input_manager_interface,
611                                   NULL, NULL);
612 }
613 
614 gboolean
meta_wayland_gtk_text_input_init(MetaWaylandCompositor * compositor)615 meta_wayland_gtk_text_input_init (MetaWaylandCompositor *compositor)
616 {
617   return (wl_global_create (compositor->wayland_display,
618                             &gtk_text_input_manager_interface,
619                             META_GTK_TEXT_INPUT_VERSION,
620                             compositor->seat->gtk_text_input,
621                             bind_text_input) != NULL);
622 }
623 
624 gboolean
meta_wayland_gtk_text_input_handle_event(MetaWaylandGtkTextInput * text_input,const ClutterEvent * event)625 meta_wayland_gtk_text_input_handle_event (MetaWaylandGtkTextInput *text_input,
626                                           const ClutterEvent      *event)
627 {
628   if (!text_input->surface ||
629       !clutter_input_focus_is_focused (text_input->input_focus))
630     return FALSE;
631 
632   return clutter_input_focus_filter_event (text_input->input_focus, event);
633 }
634