1/* Demonstrates hooking up an input method context to a custom widget.
2 */
3#include <gtk/gtk.h>
4
5G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget)
6
7struct _DemoWidget
8{
9 GtkWidget parent_instance;
10
11 GtkIMContext *im_context;
12 PangoLayout *layout;
13};
14
15struct _DemoWidgetClass
16{
17 GtkWidgetClass parent_class;
18};
19
20G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET)
21
22static void
23commit_cb (GtkIMContext *context,
24 const char *str,
25 DemoWidget *demo)
26{
27 pango_layout_set_text (layout: demo->layout, text: str, length: -1);
28 pango_layout_set_attributes (layout: demo->layout, NULL);
29 gtk_widget_queue_draw (GTK_WIDGET (demo));
30}
31
32static void
33preedit_changed_cb (GtkIMContext *context,
34 DemoWidget *demo)
35{
36 char *str;
37 PangoAttrList *attrs;
38 int cursor_pos;
39
40 gtk_im_context_get_preedit_string (context, str: &str, attrs: &attrs, cursor_pos: &cursor_pos);
41 pango_layout_set_text (layout: demo->layout, text: str, length: -1);
42 pango_layout_set_attributes (layout: demo->layout, attrs);
43 g_free (mem: str);
44 pango_attr_list_unref (list: attrs);
45
46 gtk_widget_queue_draw (GTK_WIDGET (demo));
47}
48
49static gboolean
50key_pressed_cb (GtkEventControllerKey *controller,
51 guint keyval,
52 guint keycode,
53 GdkModifierType state,
54 DemoWidget *demo)
55{
56 if (keyval == GDK_KEY_BackSpace)
57 {
58 pango_layout_set_text (layout: demo->layout, text: "", length: -1);
59 pango_layout_set_attributes (layout: demo->layout, NULL);
60 gtk_widget_queue_draw (GTK_WIDGET (demo));
61
62 return TRUE;
63 }
64
65 return FALSE;
66}
67
68static void
69demo_widget_init (DemoWidget *demo)
70{
71 GtkEventController *controller;
72
73 gtk_widget_set_focusable (GTK_WIDGET (demo), TRUE);
74
75 demo->layout = gtk_widget_create_pango_layout (GTK_WIDGET (demo), text: "");
76
77 demo->im_context = gtk_im_multicontext_new ();
78
79 g_signal_connect (demo->im_context, "commit", G_CALLBACK (commit_cb), demo);
80 g_signal_connect (demo->im_context, "preedit-changed", G_CALLBACK (preedit_changed_cb), demo);
81
82 controller = gtk_event_controller_key_new ();
83 gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (controller),
84 im_context: demo->im_context);
85
86 g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed_cb), demo);
87
88 gtk_widget_add_controller (GTK_WIDGET (demo), controller);
89}
90
91static void
92demo_widget_dispose (GObject *object)
93{
94 DemoWidget *demo = DEMO_WIDGET (ptr: object);
95
96 g_clear_object (&demo->layout);
97 g_clear_object (&demo->im_context);
98
99 G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object);
100}
101
102static void
103demo_widget_snapshot (GtkWidget *widget,
104 GtkSnapshot *snapshot)
105{
106 DemoWidget *demo = DEMO_WIDGET (ptr: widget);
107
108 gtk_snapshot_render_layout (snapshot,
109 context: gtk_widget_get_style_context (widget),
110 x: 0, y: 0,
111 layout: demo->layout);
112}
113
114static void
115demo_widget_class_init (DemoWidgetClass *class)
116{
117 GObjectClass *object_class = G_OBJECT_CLASS (class);
118 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
119
120 object_class->dispose = demo_widget_dispose;
121
122 widget_class->snapshot = demo_widget_snapshot;
123}
124
125static GtkWidget *
126demo_widget_new (void)
127{
128 return g_object_new (object_type: demo_widget_get_type (), NULL);
129}
130
131int
132main (int argc, char *argv[])
133{
134 GtkWindow *window;
135 GtkWidget *demo;
136
137 gtk_init ();
138
139 window = GTK_WINDOW (gtk_window_new ());
140
141 demo = demo_widget_new ();
142
143 gtk_window_set_child (window, child: demo);
144
145 gtk_window_present (window);
146
147 gtk_widget_grab_focus (widget: demo);
148
149 while (g_list_model_get_n_items (list: gtk_window_get_toplevels ()) > 0)
150 g_main_context_iteration (NULL, TRUE);
151
152 return 0;
153}
154

source code of gtk/tests/input.c