Search code examples
gtksignalstextfieldgtk4

Connect handler to insert-text signal in GTK4


I'm trying to display something each time the user inserts something in an Entry widget. For instance, I have the following callback:

void entry_text_inserted (GtkEditable* self, gchar* text, gint length, gint* position, gpointer user_data ) {
    g_print("Text inserted\n");
}

I connect it to the 'insert-text' signal:

GtkWidget *entry = gtk_entry_new();
g_signal_connect(entry, "insert-text", G_CALLBACK(entry_text_inserted), NULL);

However, this does not work: when running the application, the function entry_text_inserted is never called.

By contrast, connecting a handler to changed works perfectly: "Text changed" is correctly display whenever something happens to the text entry.

void entry_text_changed(GtkEditable *editable, gpointer user_data) {
    g_print("Text changed\n");
}
g_signal_connect(entry, "changed",     G_CALLBACK(entry_text_changed),  NULL);

Question: why is my callback to entry_text_inserted not called when I type something in the text entry?

Here is the full code:

#include <gtk/gtk.h>

// Callback function for handling text entry changes
void entry_text_inserted (GtkEditable* self, gchar* text, gint length, gint* position, gpointer user_data ) {
    g_print("Text inserted\n");
}

void activate (GtkApplication* app, gpointer user_data) {
    // Create the main window
    GtkWidget *window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "GTK4 Entry Example");
    gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);

    // Create the Entry widget
    GtkWidget *entry = gtk_entry_new();
    g_signal_connect(entry, "insert-text", G_CALLBACK(entry_text_inserted), NULL);

    gtk_window_set_child(GTK_WINDOW(window), entry);

    gtk_widget_show(window);
}


int main(int argc, char *argv[]) {
    // Initialize GTK
    gtk_init();

    GtkApplication *app;
    int status;
    app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);


    status = g_application_run (G_APPLICATION (app), argc, argv);
    g_object_unref (app);
    return status;
}

Things I've tried:

  • cast entry in g_signal_connect using GTK_EDITABLE and GTK_ENTRY: g_signal_connect(GTK_EDITABLE(entry), "insert-text", G_CALLBACK(entry_text_inserted), NULL);
  • (superstitiously) move around the g_signal_connect statement to after the widget is added to the window.

Solution

  • Here is a discussion of why it is not possible to connect the "insert-text" signal directly to a Gtk.Entry. Summarizing, GtkEditable::insert-text and GtkEditable::delete-text signals will be propagated from the “wrapper” editable to the delegate, but they will not be propagated from the delegate to the “wrapper” editable, as they would cause an infinite recursion.

    If you want to use the signal, you will have to get the Gtk.Editable from the Gtk.Entry with get_delegate(), and connect the signal directly to the Gtk.Editable.