Reputation: 81
I have created what I would consider the simplest GTK 4 application to create a window with a menubar that activates a GAction
when the menu item is clicked.
#include <stdio.h>
#include <assert.h>
#include <gtk/gtk.h>
static void
activate_quit(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
printf("Quit activated\n");
}
static void
startup(GApplication *app, gpointer user_data)
{
assert(user_data == NULL);
char *menubar_ui = (
"<interface>"
" <menu id='menubar'>"
" <submenu>"
" <attribute name='label' translatable='yes'>_File</attribute>"
" <section>"
" <item>"
" <attribute name='label' translatable='yes'>_Quit</attribute>"
" <attribute name='action'>app.quit</attribute>"
" <attribute name='accel'><Primary>q</attribute>"
" </item>"
" </section>"
" </submenu>"
" </menu>"
"</interface>"
);
GtkBuilder *builder = gtk_builder_new_from_string(menubar_ui, -1);
GObject *menubar = gtk_builder_get_object(builder, "menubar");
gtk_application_set_menubar(GTK_APPLICATION(app), G_MENU_MODEL(menubar));
g_object_unref(builder);
static GActionEntry app_entries[] = {
{ "quit", activate_quit, NULL, NULL, NULL, { 0 } },
};
g_action_map_add_action_entries(G_ACTION_MAP(app), app_entries, G_N_ELEMENTS(app_entries), app);
}
static void
activate(GApplication *app, gpointer user_data)
{
assert(user_data == NULL);
GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app));
assert(app != NULL);
gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(window), TRUE);
gtk_window_present(GTK_WINDOW(window));
}
int
main(int argc, char **argv)
{
GtkApplication *app = gtk_application_new(NULL, G_APPLICATION_HANDLES_OPEN);
g_signal_connect(app, "startup", G_CALLBACK(startup), NULL);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), 0, NULL);
g_object_unref(app);
return status;
}
Running this code gives me a "critical" error message when I click on "Quit" in the menubar, or when I only click on "File" and then exit out of the dropdown menu without activating the menu item. The error can be produced multiple times during a single run of the program. While the application does not crash, obviously some basic assumption I am making about how GTK 4 works is incorrect.
$ cc main.c `pkg-config --libs --cflags gtk4`
$ ./a.out
Quit activated
(a.out:13357): Gtk-CRITICAL **: 20:29:44.927: gtk_widget_child_focus: assertion 'GTK_IS_WIDGET (widget)' failed
I have noticed that if the "Quit" menu item is not active (because the "app.quit" action is not registered), then the error message does not appear. This suggests that the problem lies in the GAction
system, rather than the GtkBuilder
or GMenu
objects.
What aspect of my code is causing the assertion failure?
Upvotes: 5
Views: 4353
Reputation: 81
I am convinced that this is a trivial bug in GTK 4. It only affects windows which do not contain a child, so in any real application this bug would never arise. Adding a label to the window solves the problem.
static void
activate(GApplication *app, gpointer user_data)
{
assert(user_data == NULL);
GtkWidget *window = gtk_application_window_new(GTK_APPLICATION(app));
assert(app != NULL);
gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(window), TRUE);
GtkWidget *label = gtk_label_new("Hello world");
gtk_window_set_child(GTK_WINDOW(window), label);
gtk_window_present(GTK_WINDOW(window));
}
Upvotes: 3