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 >k_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, ®istry_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