/* Demonstrates hooking up an input method context to a custom widget. */ #include G_DECLARE_FINAL_TYPE (DemoWidget, demo_widget, DEMO, WIDGET, GtkWidget) struct _DemoWidget { GtkWidget parent_instance; GtkIMContext *im_context; PangoLayout *layout; }; struct _DemoWidgetClass { GtkWidgetClass parent_class; }; G_DEFINE_TYPE (DemoWidget, demo_widget, GTK_TYPE_WIDGET) static void commit_cb (GtkIMContext *context, const char *str, DemoWidget *demo) { pango_layout_set_text (demo->layout, str, -1); pango_layout_set_attributes (demo->layout, NULL); gtk_widget_queue_draw (GTK_WIDGET (demo)); } static void preedit_changed_cb (GtkIMContext *context, DemoWidget *demo) { char *str; PangoAttrList *attrs; int cursor_pos; gtk_im_context_get_preedit_string (context, &str, &attrs, &cursor_pos); pango_layout_set_text (demo->layout, str, -1); pango_layout_set_attributes (demo->layout, attrs); g_free (str); pango_attr_list_unref (attrs); gtk_widget_queue_draw (GTK_WIDGET (demo)); } static gboolean key_pressed_cb (GtkEventControllerKey *controller, guint keyval, guint keycode, GdkModifierType state, DemoWidget *demo) { if (keyval == GDK_KEY_BackSpace) { pango_layout_set_text (demo->layout, "", -1); pango_layout_set_attributes (demo->layout, NULL); gtk_widget_queue_draw (GTK_WIDGET (demo)); return TRUE; } return FALSE; } static void demo_widget_init (DemoWidget *demo) { GtkEventController *controller; gtk_widget_set_focusable (GTK_WIDGET (demo), TRUE); demo->layout = gtk_widget_create_pango_layout (GTK_WIDGET (demo), ""); demo->im_context = gtk_im_multicontext_new (); g_signal_connect (demo->im_context, "commit", G_CALLBACK (commit_cb), demo); g_signal_connect (demo->im_context, "preedit-changed", G_CALLBACK (preedit_changed_cb), demo); controller = gtk_event_controller_key_new (); gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (controller), demo->im_context); g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed_cb), demo); gtk_widget_add_controller (GTK_WIDGET (demo), controller); } static void demo_widget_dispose (GObject *object) { DemoWidget *demo = DEMO_WIDGET (object); g_clear_object (&demo->layout); g_clear_object (&demo->im_context); G_OBJECT_CLASS (demo_widget_parent_class)->dispose (object); } static void demo_widget_snapshot (GtkWidget *widget, GtkSnapshot *snapshot) { DemoWidget *demo = DEMO_WIDGET (widget); gtk_snapshot_render_layout (snapshot, gtk_widget_get_style_context (widget), 0, 0, demo->layout); } static void demo_widget_class_init (DemoWidgetClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); object_class->dispose = demo_widget_dispose; widget_class->snapshot = demo_widget_snapshot; } static GtkWidget * demo_widget_new (void) { return g_object_new (demo_widget_get_type (), NULL); } int main (int argc, char *argv[]) { GtkWindow *window; GtkWidget *demo; gtk_init (); window = GTK_WINDOW (gtk_window_new ()); demo = demo_widget_new (); gtk_window_set_child (window, demo); gtk_window_present (window); gtk_widget_grab_focus (demo); while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0) g_main_context_iteration (NULL, TRUE); return 0; }