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 
G_DEFINE_TYPE(DemoWidget,demo_widget,GTK_TYPE_WIDGET)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 (demo->layout, str, -1);
28   pango_layout_set_attributes (demo->layout, NULL);
29   gtk_widget_queue_draw (GTK_WIDGET (demo));
30 }
31 
32 static void
preedit_changed_cb(GtkIMContext * context,DemoWidget * demo)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, &attrs, &cursor_pos);
41   pango_layout_set_text (demo->layout, str, -1);
42   pango_layout_set_attributes (demo->layout, attrs);
43   g_free (str);
44   pango_attr_list_unref (attrs);
45 
46   gtk_widget_queue_draw (GTK_WIDGET (demo));
47 }
48 
49 static gboolean
key_pressed_cb(GtkEventControllerKey * controller,guint keyval,guint keycode,GdkModifierType state,DemoWidget * demo)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 (demo->layout, "", -1);
59       pango_layout_set_attributes (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
demo_widget_init(DemoWidget * demo)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), "");
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                                            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
demo_widget_dispose(GObject * object)92 demo_widget_dispose (GObject *object)
93 {
94   DemoWidget *demo = DEMO_WIDGET (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
demo_widget_snapshot(GtkWidget * widget,GtkSnapshot * snapshot)103 demo_widget_snapshot (GtkWidget   *widget,
104                       GtkSnapshot *snapshot)
105 {
106   DemoWidget *demo = DEMO_WIDGET (widget);
107 
108   gtk_snapshot_render_layout (snapshot,
109                               gtk_widget_get_style_context (widget),
110                               0, 0,
111                               demo->layout);
112 }
113 
114 static void
demo_widget_class_init(DemoWidgetClass * class)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 *
demo_widget_new(void)126 demo_widget_new (void)
127 {
128   return g_object_new (demo_widget_get_type (), NULL);
129 }
130 
131 int
main(int argc,char * argv[])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, demo);
144 
145   gtk_window_present (window);
146 
147   gtk_widget_grab_focus (demo);
148 
149   while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
150     g_main_context_iteration (NULL, TRUE);
151 
152   return 0;
153 }
154