1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2017 Red Hat, Inc.
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 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 #include <wayland-client-protocol.h>
22 
23 #include <gtk/gtk.h>
24 #include "gtk/gtkintl.h"
25 #include "gtk/gtkimmodule.h"
26 
27 #include "gdk/wayland/gdkwayland.h"
28 #include "gtk-text-input-client-protocol.h"
29 
30 typedef struct _GtkIMContextWaylandGlobal GtkIMContextWaylandGlobal;
31 typedef struct _GtkIMContextWayland GtkIMContextWayland;
32 typedef struct _GtkIMContextWaylandClass GtkIMContextWaylandClass;
33 
34 struct _GtkIMContextWaylandGlobal
35 {
36   struct wl_display *display;
37   struct wl_registry *registry;
38   uint32_t text_input_manager_wl_id;
39   struct gtk_text_input_manager *text_input_manager;
40   struct gtk_text_input *text_input;
41   uint32_t enter_serial;
42 
43   GtkIMContext *current;
44 };
45 
46 struct _GtkIMContextWaylandClass
47 {
48   GtkIMContextSimpleClass parent_class;
49 };
50 
51 struct _GtkIMContextWayland
52 {
53   GtkIMContextSimple parent_instance;
54   GdkWindow *window;
55   GtkWidget *widget;
56 
57   GtkGesture *gesture;
58   gdouble press_x;
59   gdouble press_y;
60 
61   struct {
62     gchar *text;
63     gint cursor_idx;
64   } surrounding;
65 
66   struct {
67     gchar *text;
68     gint cursor_idx;
69   } preedit;
70 
71   cairo_rectangle_int_t cursor_rect;
72   guint use_preedit : 1;
73 };
74 
75 GType type_wayland = 0;
76 static GObjectClass *parent_class;
77 static GtkIMContextWaylandGlobal *global = NULL;
78 
79 static const GtkIMContextInfo imwayland_info =
80 {
81   "waylandgtk",      /* ID */
82   NC_("input method menu", "Waylandgtk"),      /* Human readable name */
83   GETTEXT_PACKAGE, /* Translation domain */
84   GTK_LOCALEDIR,   /* Dir for bindtextdomain (not strictly needed for "gtk+") */
85   "",              /* Languages for which this module is the default */
86 };
87 
88 static const GtkIMContextInfo *info_list[] =
89 {
90   &imwayland_info,
91 };
92 
93 #define GTK_IM_CONTEXT_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), type_wayland, GtkIMContextWayland))
94 
95 #ifndef INCLUDE_IM_wayland
96 #define MODULE_ENTRY(type,function) G_MODULE_EXPORT type im_module_ ## function
97 #else
98 #define MODULE_ENTRY(type, function) type _gtk_immodule_wayland_ ## function
99 #endif
100 
101 static void
reset_preedit(GtkIMContextWayland * context)102 reset_preedit (GtkIMContextWayland *context)
103 {
104   if (context->preedit.text == NULL)
105     return;
106 
107   g_clear_pointer (&context->preedit.text, g_free);
108   context->preedit.cursor_idx = 0;
109   g_signal_emit_by_name (context, "preedit-changed");
110 }
111 
112 static void
text_input_enter(void * data,struct gtk_text_input * text_input,uint32_t serial,struct wl_surface * surface)113 text_input_enter (void                     *data,
114                   struct gtk_text_input    *text_input,
115                   uint32_t                  serial,
116                   struct wl_surface        *surface)
117 {
118   GtkIMContextWaylandGlobal *global = data;
119 
120   global->enter_serial = serial;
121 }
122 
123 static void
text_input_leave(void * data,struct gtk_text_input * text_input,uint32_t serial,struct wl_surface * surface)124 text_input_leave (void                     *data,
125                   struct gtk_text_input    *text_input,
126                   uint32_t                  serial,
127                   struct wl_surface        *surface)
128 {
129   GtkIMContextWayland *context;
130 
131   if (!global->current)
132     return;
133 
134   context = GTK_IM_CONTEXT_WAYLAND (global->current);
135   reset_preedit (context);
136 }
137 
138 static void
text_input_preedit(void * data,struct gtk_text_input * text_input,const char * text,guint cursor)139 text_input_preedit (void                     *data,
140                     struct gtk_text_input    *text_input,
141                     const char               *text,
142                     guint                     cursor)
143 {
144   GtkIMContextWayland *context;
145   gboolean state_change;
146 
147   if (!global->current)
148     return;
149 
150   context = GTK_IM_CONTEXT_WAYLAND (global->current);
151   if (!text && !context->preedit.text)
152     return;
153 
154   state_change = ((text == NULL) != (context->preedit.text == NULL));
155 
156   if (state_change && !context->preedit.text)
157     g_signal_emit_by_name (context, "preedit-start");
158 
159   g_free (context->preedit.text);
160   context->preedit.text = g_strdup (text);
161   context->preedit.cursor_idx = cursor;
162 
163   g_signal_emit_by_name (context, "preedit-changed");
164 
165   if (state_change && !context->preedit.text)
166     g_signal_emit_by_name (context, "preedit-end");
167 }
168 
169 static void
text_input_commit(void * data,struct gtk_text_input * text_input,const char * text)170 text_input_commit (void                     *data,
171                    struct gtk_text_input    *text_input,
172                    const char               *text)
173 {
174   GtkIMContextWaylandGlobal *global = data;
175 
176   if (global->current && text)
177     g_signal_emit_by_name (global->current, "commit", text);
178 }
179 
180 static void
text_input_delete_surrounding_text(void * data,struct gtk_text_input * text_input,uint32_t offset,uint32_t len)181 text_input_delete_surrounding_text (void                     *data,
182                                     struct gtk_text_input    *text_input,
183                                     uint32_t                  offset,
184                                     uint32_t                  len)
185 {
186   GtkIMContextWaylandGlobal *global = data;
187 
188   if (global->current)
189     g_signal_emit_by_name (global->current, "delete-surrounding", offset, len);
190 }
191 
192 static const struct gtk_text_input_listener text_input_listener = {
193   text_input_enter,
194   text_input_leave,
195   text_input_preedit,
196   text_input_commit,
197   text_input_delete_surrounding_text
198 };
199 
200 static void
registry_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * interface,uint32_t version)201 registry_handle_global (void               *data,
202                         struct wl_registry *registry,
203                         uint32_t            id,
204                         const char         *interface,
205                         uint32_t            version)
206 {
207   GtkIMContextWaylandGlobal *global = data;
208   GdkSeat *seat = gdk_display_get_default_seat (gdk_display_get_default ());
209 
210   if (strcmp (interface, "gtk_text_input_manager") == 0)
211     {
212       global->text_input_manager_wl_id = id;
213       global->text_input_manager =
214         wl_registry_bind (global->registry, global->text_input_manager_wl_id,
215                           &gtk_text_input_manager_interface, 1);
216       global->text_input =
217         gtk_text_input_manager_get_text_input (global->text_input_manager,
218                                                gdk_wayland_seat_get_wl_seat (seat));
219       gtk_text_input_add_listener (global->text_input,
220                                    &text_input_listener, global);
221     }
222 }
223 
224 static void
registry_handle_global_remove(void * data,struct wl_registry * registry,uint32_t id)225 registry_handle_global_remove (void               *data,
226                                struct wl_registry *registry,
227                                uint32_t            id)
228 {
229   GtkIMContextWaylandGlobal *global = data;
230 
231   if (id != global->text_input_manager_wl_id)
232     return;
233 
234   g_clear_pointer(&global->text_input, gtk_text_input_destroy);
235   g_clear_pointer(&global->text_input_manager, gtk_text_input_manager_destroy);
236 }
237 
238 static const struct wl_registry_listener registry_listener = {
239     registry_handle_global,
240     registry_handle_global_remove
241 };
242 
243 static void
gtk_im_context_wayland_global_init(GdkDisplay * display)244 gtk_im_context_wayland_global_init (GdkDisplay *display)
245 {
246   g_return_if_fail (global == NULL);
247 
248   global = g_new0 (GtkIMContextWaylandGlobal, 1);
249   global->display = gdk_wayland_display_get_wl_display (display);
250   global->registry = wl_display_get_registry (global->display);
251 
252   wl_registry_add_listener (global->registry, &registry_listener, global);
253 }
254 
255 static void
notify_surrounding_text(GtkIMContextWayland * context)256 notify_surrounding_text (GtkIMContextWayland *context)
257 {
258   if (!global || !global->text_input)
259     return;
260   if (global->current != GTK_IM_CONTEXT (context))
261     return;
262   if (!context->surrounding.text)
263     return;
264 
265   gtk_text_input_set_surrounding_text (global->text_input,
266                                        context->surrounding.text,
267                                        context->surrounding.cursor_idx,
268                                        context->surrounding.cursor_idx);
269 }
270 
271 static void
notify_cursor_location(GtkIMContextWayland * context)272 notify_cursor_location (GtkIMContextWayland *context)
273 {
274   cairo_rectangle_int_t rect;
275 
276   if (!global || !global->text_input)
277     return;
278   if (global->current != GTK_IM_CONTEXT (context))
279     return;
280   if (!context->window)
281     return;
282 
283   rect = context->cursor_rect;
284   gdk_window_get_root_coords (context->window, rect.x, rect.y,
285                               &rect.x, &rect.y);
286 
287   gtk_text_input_set_cursor_rectangle (global->text_input,
288                                        rect.x, rect.y,
289                                        rect.width, rect.height);
290 }
291 
292 static uint32_t
translate_hints(GtkInputHints input_hints,GtkInputPurpose purpose)293 translate_hints (GtkInputHints   input_hints,
294                  GtkInputPurpose purpose)
295 {
296   uint32_t hints = 0;
297 
298   if (input_hints & GTK_INPUT_HINT_SPELLCHECK)
299     hints |= GTK_TEXT_INPUT_CONTENT_HINT_SPELLCHECK;
300   if (input_hints & GTK_INPUT_HINT_WORD_COMPLETION)
301     hints |= GTK_TEXT_INPUT_CONTENT_HINT_COMPLETION;
302   if (input_hints & GTK_INPUT_HINT_LOWERCASE)
303     hints |= GTK_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
304   if (input_hints & GTK_INPUT_HINT_UPPERCASE_CHARS)
305     hints |= GTK_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
306   if (input_hints & GTK_INPUT_HINT_UPPERCASE_WORDS)
307     hints |= GTK_TEXT_INPUT_CONTENT_HINT_TITLECASE;
308   if (input_hints & GTK_INPUT_HINT_UPPERCASE_SENTENCES)
309     hints |= GTK_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
310 
311   if (purpose == GTK_INPUT_PURPOSE_PIN ||
312       purpose == GTK_INPUT_PURPOSE_PASSWORD)
313     {
314       hints |= (GTK_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT |
315                 GTK_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA);
316     }
317 
318   return hints;
319 }
320 
321 static uint32_t
translate_purpose(GtkInputPurpose purpose)322 translate_purpose (GtkInputPurpose purpose)
323 {
324   switch (purpose)
325     {
326     case GTK_INPUT_PURPOSE_FREE_FORM:
327       return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
328     case GTK_INPUT_PURPOSE_ALPHA:
329       return GTK_TEXT_INPUT_CONTENT_PURPOSE_ALPHA;
330     case GTK_INPUT_PURPOSE_DIGITS:
331       return GTK_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
332     case GTK_INPUT_PURPOSE_NUMBER:
333       return GTK_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
334     case GTK_INPUT_PURPOSE_PHONE:
335       return GTK_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
336     case GTK_INPUT_PURPOSE_URL:
337       return GTK_TEXT_INPUT_CONTENT_PURPOSE_URL;
338     case GTK_INPUT_PURPOSE_EMAIL:
339       return GTK_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
340     case GTK_INPUT_PURPOSE_NAME:
341       return GTK_TEXT_INPUT_CONTENT_PURPOSE_NAME;
342     case GTK_INPUT_PURPOSE_PASSWORD:
343       return GTK_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
344     case GTK_INPUT_PURPOSE_PIN:
345       return GTK_TEXT_INPUT_CONTENT_PURPOSE_PIN;
346     case GTK_INPUT_PURPOSE_TERMINAL:
347       return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
348     }
349 
350   return GTK_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
351 }
352 
353 static void
notify_content_type(GtkIMContextWayland * context)354 notify_content_type (GtkIMContextWayland *context)
355 {
356   GtkInputHints hints;
357   GtkInputPurpose purpose;
358 
359   if (global->current != GTK_IM_CONTEXT (context))
360     return;
361 
362   g_object_get (context,
363                 "input-hints", &hints,
364                 "input-purpose", &purpose,
365                 NULL);
366 
367   gtk_text_input_set_content_type (global->text_input,
368                                    translate_hints (hints, purpose),
369                                    translate_purpose (purpose));
370 }
371 
372 static void
commit_state(GtkIMContextWayland * context)373 commit_state (GtkIMContextWayland *context)
374 {
375   if (global->current != GTK_IM_CONTEXT (context))
376     return;
377   gtk_text_input_commit (global->text_input);
378 }
379 
380 static void
enable_text_input(GtkIMContextWayland * context,gboolean toggle_panel)381 enable_text_input (GtkIMContextWayland *context,
382                    gboolean             toggle_panel)
383 {
384   guint flags = 0;
385 
386   if (context->use_preedit)
387     flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_CAN_SHOW_PREEDIT;
388   if (toggle_panel)
389     flags |= GTK_TEXT_INPUT_ENABLE_FLAGS_TOGGLE_INPUT_PANEL;
390 
391   gtk_text_input_enable (global->text_input,
392                          global->enter_serial,
393                          flags);
394 }
395 
396 static void
gtk_im_context_wayland_finalize(GObject * object)397 gtk_im_context_wayland_finalize (GObject *object)
398 {
399   GtkIMContextWayland *context = GTK_IM_CONTEXT_WAYLAND (object);
400 
401   g_clear_object (&context->window);
402   g_clear_object (&context->gesture);
403 
404   G_OBJECT_CLASS (parent_class)->finalize (object);
405 }
406 
407 static void
pressed_cb(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,GtkIMContextWayland * context)408 pressed_cb (GtkGestureMultiPress *gesture,
409             gint                  n_press,
410             gdouble               x,
411             gdouble               y,
412             GtkIMContextWayland  *context)
413 {
414   if (n_press == 1)
415     {
416       context->press_x = x;
417       context->press_y = y;
418     }
419 }
420 
421 static void
released_cb(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,GtkIMContextWayland * context)422 released_cb (GtkGestureMultiPress *gesture,
423              gint                  n_press,
424              gdouble               x,
425              gdouble               y,
426              GtkIMContextWayland  *context)
427 {
428   GtkInputHints hints;
429 
430   if (!global->current)
431     return;
432 
433   g_object_get (context, "input-hints", &hints, NULL);
434 
435   if (n_press == 1 &&
436       (hints & GTK_INPUT_HINT_INHIBIT_OSK) == 0 &&
437       !gtk_drag_check_threshold (context->widget,
438                                  context->press_x,
439                                  context->press_y,
440                                  x, y))
441     {
442       enable_text_input (GTK_IM_CONTEXT_WAYLAND (context), TRUE);
443     }
444 }
445 
446 static void
gtk_im_context_wayland_set_client_window(GtkIMContext * context,GdkWindow * window)447 gtk_im_context_wayland_set_client_window (GtkIMContext *context,
448                                           GdkWindow    *window)
449 {
450   GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
451   GtkWidget *widget = NULL;
452 
453   if (window == context_wayland->window)
454     return;
455 
456   if (window)
457     gdk_window_get_user_data (window, (gpointer*) &widget);
458 
459   if (context_wayland->widget && context_wayland->widget != widget)
460     g_clear_object (&context_wayland->gesture);
461 
462   g_set_object (&context_wayland->window, window);
463 
464   if (context_wayland->widget != widget)
465     {
466       context_wayland->widget = widget;
467 
468       if (widget)
469         {
470           GtkGesture *gesture;
471 
472           gesture = gtk_gesture_multi_press_new (widget);
473           gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture),
474                                                       GTK_PHASE_CAPTURE);
475           g_signal_connect (gesture, "pressed",
476                             G_CALLBACK (pressed_cb), context);
477           g_signal_connect (gesture, "released",
478                             G_CALLBACK (released_cb), context);
479           context_wayland->gesture = gesture;
480         }
481     }
482 }
483 
484 static void
gtk_im_context_wayland_get_preedit_string(GtkIMContext * context,gchar ** str,PangoAttrList ** attrs,gint * cursor_pos)485 gtk_im_context_wayland_get_preedit_string (GtkIMContext   *context,
486                                            gchar         **str,
487                                            PangoAttrList **attrs,
488                                            gint           *cursor_pos)
489 {
490   GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
491   gchar *preedit_str;
492 
493   if (attrs)
494     *attrs = NULL;
495 
496   GTK_IM_CONTEXT_CLASS (parent_class)->get_preedit_string (context, str, attrs, cursor_pos);
497 
498   /* If the parent implementation returns a len>0 string, go with it */
499   if (str && *str)
500     {
501       if (**str)
502         return;
503 
504       g_free (*str);
505     }
506 
507   preedit_str =
508     context_wayland->preedit.text ? context_wayland->preedit.text : "";
509 
510   if (str)
511     *str = g_strdup (preedit_str);
512   if (cursor_pos)
513     *cursor_pos = context_wayland->preedit.cursor_idx;
514 
515   if (attrs)
516     {
517       if (!*attrs)
518         *attrs = pango_attr_list_new ();
519       pango_attr_list_insert (*attrs,
520                               pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
521     }
522 }
523 
524 static gboolean
gtk_im_context_wayland_filter_keypress(GtkIMContext * context,GdkEventKey * key)525 gtk_im_context_wayland_filter_keypress (GtkIMContext *context,
526                                         GdkEventKey  *key)
527 {
528   /* This is done by the compositor */
529   return GTK_IM_CONTEXT_CLASS (parent_class)->filter_keypress (context, key);
530 }
531 
532 static void
gtk_im_context_wayland_focus_in(GtkIMContext * context)533 gtk_im_context_wayland_focus_in (GtkIMContext *context)
534 {
535   GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
536 
537   if (global->current == context)
538     return;
539   if (!global->text_input)
540     return;
541 
542   global->current = context;
543   enable_text_input (context_wayland, FALSE);
544   notify_content_type (context_wayland);
545   notify_surrounding_text (context_wayland);
546   notify_cursor_location (context_wayland);
547   commit_state (context_wayland);
548 }
549 
550 static void
gtk_im_context_wayland_focus_out(GtkIMContext * context)551 gtk_im_context_wayland_focus_out (GtkIMContext *context)
552 {
553   if (global->current != context)
554     return;
555 
556   gtk_text_input_disable (global->text_input);
557   global->current = NULL;
558 }
559 
560 static void
gtk_im_context_wayland_reset(GtkIMContext * context)561 gtk_im_context_wayland_reset (GtkIMContext *context)
562 {
563   reset_preedit (GTK_IM_CONTEXT_WAYLAND (context));
564 
565   GTK_IM_CONTEXT_CLASS (parent_class)->reset (context);
566 }
567 
568 static void
gtk_im_context_wayland_set_cursor_location(GtkIMContext * context,GdkRectangle * rect)569 gtk_im_context_wayland_set_cursor_location (GtkIMContext *context,
570                                             GdkRectangle *rect)
571 {
572   GtkIMContextWayland *context_wayland;
573 
574   context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
575 
576   context_wayland->cursor_rect = *rect;
577   notify_cursor_location (context_wayland);
578   commit_state (context_wayland);
579 }
580 
581 static void
gtk_im_context_wayland_set_use_preedit(GtkIMContext * context,gboolean use_preedit)582 gtk_im_context_wayland_set_use_preedit (GtkIMContext *context,
583                                         gboolean      use_preedit)
584 {
585   GtkIMContextWayland *context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
586 
587   context_wayland->use_preedit = !!use_preedit;
588 }
589 
590 static void
gtk_im_context_wayland_set_surrounding(GtkIMContext * context,const gchar * text,gint len,gint cursor_index)591 gtk_im_context_wayland_set_surrounding (GtkIMContext *context,
592                                         const gchar  *text,
593                                         gint          len,
594                                         gint          cursor_index)
595 {
596   GtkIMContextWayland *context_wayland;
597 
598   context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
599 
600   g_free (context_wayland->surrounding.text);
601   context_wayland->surrounding.text = g_strndup (text, len);
602   context_wayland->surrounding.cursor_idx = cursor_index;
603 
604   notify_surrounding_text (context_wayland);
605   commit_state (context_wayland);
606 }
607 
608 static gboolean
gtk_im_context_wayland_get_surrounding(GtkIMContext * context,gchar ** text,gint * cursor_index)609 gtk_im_context_wayland_get_surrounding (GtkIMContext  *context,
610                                         gchar        **text,
611                                         gint          *cursor_index)
612 {
613   GtkIMContextWayland *context_wayland;
614 
615   context_wayland = GTK_IM_CONTEXT_WAYLAND (context);
616 
617   if (!context_wayland->surrounding.text)
618     return FALSE;
619 
620   *text = context_wayland->surrounding.text;
621   *cursor_index = context_wayland->surrounding.cursor_idx;
622   return TRUE;
623 }
624 
625 static void
gtk_im_context_wayland_class_init(GtkIMContextWaylandClass * klass)626 gtk_im_context_wayland_class_init (GtkIMContextWaylandClass *klass)
627 {
628   GObjectClass *object_class = G_OBJECT_CLASS (klass);
629   GtkIMContextClass *im_context_class = GTK_IM_CONTEXT_CLASS (klass);
630 
631   object_class->finalize = gtk_im_context_wayland_finalize;
632 
633   im_context_class->set_client_window = gtk_im_context_wayland_set_client_window;
634   im_context_class->get_preedit_string = gtk_im_context_wayland_get_preedit_string;
635   im_context_class->filter_keypress = gtk_im_context_wayland_filter_keypress;
636   im_context_class->focus_in = gtk_im_context_wayland_focus_in;
637   im_context_class->focus_out = gtk_im_context_wayland_focus_out;
638   im_context_class->reset = gtk_im_context_wayland_reset;
639   im_context_class->set_cursor_location = gtk_im_context_wayland_set_cursor_location;
640   im_context_class->set_use_preedit = gtk_im_context_wayland_set_use_preedit;
641   im_context_class->set_surrounding = gtk_im_context_wayland_set_surrounding;
642   im_context_class->get_surrounding = gtk_im_context_wayland_get_surrounding;
643 
644   parent_class = g_type_class_peek_parent (klass);
645 }
646 
647 static void
on_content_type_changed(GtkIMContextWayland * context)648 on_content_type_changed (GtkIMContextWayland *context)
649 {
650   notify_content_type (context);
651   commit_state (context);
652 }
653 
654 static void
gtk_im_context_wayland_init(GtkIMContextWayland * context)655 gtk_im_context_wayland_init (GtkIMContextWayland *context)
656 {
657   context->use_preedit = TRUE;
658   g_signal_connect_swapped (context, "notify::input-purpose",
659                             G_CALLBACK (on_content_type_changed), context);
660   g_signal_connect_swapped (context, "notify::input-hints",
661                             G_CALLBACK (on_content_type_changed), context);
662 }
663 
664 static void
gtk_im_context_wayland_register_type(GTypeModule * module)665 gtk_im_context_wayland_register_type (GTypeModule *module)
666 {
667   const GTypeInfo object_info = {
668     sizeof (GtkIMContextWaylandClass),
669     NULL, NULL,
670     (GClassInitFunc) gtk_im_context_wayland_class_init,
671     NULL, NULL,
672     sizeof (GtkIMContextWayland),
673     0,
674     (GInstanceInitFunc) gtk_im_context_wayland_init,
675   };
676 
677   type_wayland = g_type_module_register_type (module,
678                                               GTK_TYPE_IM_CONTEXT_SIMPLE,
679                                               "GtkIMContextWayland",
680                                               &object_info, 0);
681 }
682 
MODULE_ENTRY(void,init)683 MODULE_ENTRY (void, init) (GTypeModule * module)
684 {
685   gtk_im_context_wayland_register_type (module);
686   gtk_im_context_wayland_global_init (gdk_display_get_default ());
687 }
688 
MODULE_ENTRY(void,exit)689 MODULE_ENTRY (void, exit) (void)
690 {
691 }
692 
MODULE_ENTRY(void,list)693 MODULE_ENTRY (void, list) (const GtkIMContextInfo *** contexts, int *n_contexts)
694 {
695   *contexts = info_list;
696   *n_contexts = G_N_ELEMENTS (info_list);
697 }
698 
MODULE_ENTRY(GtkIMContext *,create)699 MODULE_ENTRY (GtkIMContext *, create) (const gchar * context_id)
700 {
701   if (strcmp (context_id, "waylandgtk") == 0)
702     return g_object_new (type_wayland, NULL);
703   else
704     return NULL;
705 }
706