1 | /* Demonstrates hooking up an input method context to a custom widget. |
2 | */ |
3 | #include <gtk/gtk.h> |
4 | |
5 | G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget) |
6 | |
7 | struct _DemoWidget |
8 | { |
9 | GtkWidget parent_instance; |
10 | |
11 | GtkIMContext *im_context; |
12 | PangoLayout *layout; |
13 | }; |
14 | |
15 | struct _DemoWidgetClass |
16 | { |
17 | GtkWidgetClass parent_class; |
18 | }; |
19 | |
20 | G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET) |
21 | |
22 | static void |
23 | commit_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 | |
32 | static void |
33 | preedit_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 | |
49 | static gboolean |
50 | key_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 | |
68 | static void |
69 | demo_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 | |
91 | static void |
92 | demo_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 | |
102 | static void |
103 | demo_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 | |
114 | static void |
115 | demo_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 | |
125 | static GtkWidget * |
126 | demo_widget_new (void) |
127 | { |
128 | return g_object_new (object_type: demo_widget_get_type (), NULL); |
129 | } |
130 | |
131 | int |
132 | main (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 | |