Windows system menu doesn't work

When I run my app on Windows using Gtk3 the system menu on the top left of the GtkWindow seems broken. I can open the menu but can’t click ‘close’ or cancel the menu by clicked elsewhere. Like this.

My window code is here.

What do I need to do to get that working?

When you read your post carefully again, you may notice that some important informations may be missing, like Windows and GTK3 versions, and how GTK was installed on that windows box. Maybe virtual machine involved?

Do the official examples from

https://developer.gnome.org/gtk3/3.24/ch01s04.html#id-1.2.3.12.5

work for you on windows? I have no Windows available currently, and have not used Menus in the last years. But I think the old GTK2 menu style is deprecated, and I think the topmost screen menu may fully disappear in GTK4, I think I read that in a blog post some years ago. I thing gaction and gmenu is the way to go, but I have to read about that still. See https://wiki.gnome.org/HowDoI/

In the lgiIde app do you have the GMenu connected with something like


static void close_program(GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
g_application_quit(G_APPLICATION(user_data));
}

GSimpleAction *close = g_simple_action_new(“close”, NULL);
g_signal_connect(close, “activate”, G_CALLBACK(close_program), app);
g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(close));
g_object_unref(close);

Eric

Found it:

https://wiki.gnome.org/HowDoI/ApplicationMenu

Application menus are in the process of being phased out

Windows 7 & 10. GTK v3.22.

I tried that code and found that by creating a GtkApplication the menu started to work. However trying to attach a callback doesn’t work for me, the app just exits rather than calling ‘close_program’.

The menu working is now intermittent. Sometimes it will close the app, sometimes it will hang it like before.

I guess you will know yourself that that behaviour may be not a GTK problem, but be caused by very buggy code somewhere in your application. With C it is very easy to produce such bugs, and it is really hard to find the sources. I can remember, more than 10 years ago I had a similar problem with Ruby-GTK, leading to random crashes. I can not remember if it was my wrong code, or more an issue of Ruby bindings, but it was not a GTK issue.

I don’t have experience with GTK and windows. Menu’s are tough enough on linux with different desktops having different menu setups. I figure to get menu’s to work on linux, windows and mac is a challenge for the menu dev.

The following code works on Ubuntu 18.04 with GTK 3.22 and the Gnome desktop. I don’t know if it can be made to work with the windows system menu but it might give you a start.

GTK also has a gtk_menu along with the g_menu. It looks like you are using g_menu. If you need a simple menu that doesn’t tie into the application object the gtk_menu might be useful.

Eric


//gcc -Wall gtk_app.c -o gtk_app `pkg-config --cflags --libs gtk+-3.0`

#include<gtk/gtk.h>

static void quit_program(GSimpleAction *action, GVariant *parameter, gpointer user_data)
 {
   g_application_quit(G_APPLICATION(user_data));
 }
static void test1_callback(GSimpleAction *action, GVariant *parameter, gpointer user_data)
 {
   g_print("Test1 Callback\n");
 }
static void app_startup(GtkApplication *app, gpointer user_data)
 {
   //Setup menu callbacks.
   GSimpleAction *test1=g_simple_action_new("test1", NULL);
   g_signal_connect(test1, "activate", G_CALLBACK(test1_callback), app);
   g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(test1));
   g_object_unref(test1);
   GSimpleAction *quit=g_simple_action_new("quit", NULL);
   g_signal_connect(quit, "activate", G_CALLBACK(quit_program), app);
   g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(quit));
   g_object_unref(quit);

   //Setup menu.
   GMenu *menu=g_menu_new();
   GMenu *submenu=g_menu_new();
   g_menu_append_submenu(menu, "Application", G_MENU_MODEL(submenu));
   GMenu *section=g_menu_new();
   g_menu_append_section(submenu, NULL, G_MENU_MODEL(section));
   g_menu_append(section, "Test1", "app.test1");
   g_menu_append(section, "Quit", "app.quit");
   g_object_unref(submenu);
   g_object_unref(section);

   gtk_application_set_menubar(GTK_APPLICATION(app), G_MENU_MODEL(menu));
   g_object_unref(menu);
 }
static void app_activate(GtkApplication *app, gpointer user_data)
 {
   GtkWidget *window=gtk_application_window_new(GTK_APPLICATION(app));
   gtk_window_set_title(GTK_WINDOW(window), "Application Test");
   gtk_window_set_default_size(GTK_WINDOW(window), 200, 100);
   gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
   
   GtkWidget *label=gtk_label_new("GMenu Test");
   gtk_widget_set_hexpand(label, TRUE);
   gtk_widget_set_vexpand(label, TRUE);

   GtkWidget *grid=gtk_grid_new();
   gtk_grid_set_row_spacing(GTK_GRID(grid), 10);
   gtk_grid_attach(GTK_GRID(grid), label, 0, 1, 1, 1);
   
   gtk_container_add(GTK_CONTAINER(window), grid);

   gtk_widget_show_all(window);
 }
int main(int argc, char **argv)
 {
   gint status;
   GtkApplication *app=gtk_application_new("app.example", G_APPLICATION_FLAGS_NONE);
   g_signal_connect(app, "startup", G_CALLBACK(app_startup), NULL);
   g_signal_connect(app, "activate", G_CALLBACK(app_activate), NULL);
   g_print("Version %i.%i.%i\n", gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version());
   status=g_application_run(G_APPLICATION(app), argc, argv);
   g_object_unref(app);
   return(status);
  }

Compiles and works fine, gtk±3.24.8:3::gentoo

Have just shipped new GAction example to github, see

so I may try a Nim variant of your code soon.

[EDIT]

Do you know how I have to modify your example to get a more modern gears menu? Can only find some minimal examples done with glade/builder, but no one done with plain code.

[EDIT 2]

Well, I think I found the starting point for the gears menu:

https://developer.gnome.org/gtk3/stable/GtkHeaderBar.html

Have already done the Nim conversion, works fine. I do not yet understand everything, I will add it to the gintro readme and examples directory this evening. Later I may try to change it for a gears menu…

# nim c menubar.nim
import gintro/[gtk, glib, gobject, gio]
from strutils import `%`

proc test1Callback(action: SimpleAction; parameter: Variant; app: Application) =
  echo "Test1 Callback"

proc quitProgram(action: SimpleAction; parameter: Variant; app: Application) =
  quit(app)

proc appStartup(app: Application) =
  let test1 = newSimpleAction("test1")
  connect(test1, "activate", test1Callback, app)
  app.addAction(test1)
  let quit = newSimpleAction("quit")
  connect(quit, "activate", quitProgram, app)
  app.addAction(quit)
  let menu = gio.newMenu()
  let subMenu = gio.newMenu()
  appendSubmenu(menu, "Application", submenu)
  let section = gio.newMenu()
  appendSection(subMenu, nil, section)
  append(section, "Test1", "app.test1")
  append(section, "Quit", "app.quit")
  setMenuBar(app, menu)

proc appActivate(app: Application) =
  let window = newApplicationWindow(app)
  window.title = "GTK3 App with Menubar"
  window.defaultSize = (200, 100)
  window.position = WindowPosition.center
  let label = newLabel("GMenu Test")
  label.setHExpand
  label.setVExpand
  let grid = newGrid()
  grid.rowSpacing = 10
  grid.attach(label, 0, 1, 1, 1)
  window.add(grid)
  showAll(window)

proc main =
  let app = newApplication("app.example")
  connect(app, "startup", appStartup)
  connect(app, "activate", appActivate)
  echo "GTK Version $1.$2.$3" % [$majorVersion(), $minorVersion(), $microVersion()]
  let status = run(app)
  quit(status)

main()

Have just done some testing.

First, when I launch one instance of the program, and move the window to the left screen border, so that it begins to expand to left half screen area in gnome shell, I get this message:

$ ./gtk_app
Version 3.24.8

(gtk_app:6437): Gtk-CRITICAL **: 17:57:57.654: gtk_distribute_natural_allocation: assertion ‘extra_space >= 0’ failed

This is for C and Nim version.

Next, what is hard to understand: When we launch multiple instances, we get multiple windows, each with its own menu. But only for the first instance appStartup() is executed. We may wonder how second instance gets it menu.

Finally, do you have an idea how we can add an menu entry to close the active window only? (Of course the x at rigtth top corner works for this)

[EDIT]

I can get some more warnings, when I move the initial tiny window to the left to make it halfscreen:

$ ./gtk_app
Version 3.24.8

(gtk_app:7218): Gtk-CRITICAL **: 19:02:52.971: gtk_distribute_natural_allocation: assertion 'extra_space >= 0' failed

(gtk_app:7218): Gtk-CRITICAL **: 19:03:00.470: gtk_distribute_natural_allocation: assertion 'extra_space >= 0' failed

(gtk_app:7218): Gtk-CRITICAL **: 19:03:00.470: gtk_widget_get_preferred_width_for_height: assertion 'height >= 0' failed

(gtk_app:7218): Gtk-WARNING **: 19:03:00.470: gtk_widget_size_allocate(): attempt to allocate widget with width 110 and height -16

I am not getting the gtk_distribute_natural_allocation() error here. I moved the window to different corners and let it expand half size and full size but no warning.

The application object has some flags that you can set. One is


GtkApplication app=gtk_application_new(“app.example”, G_APPLICATION_FLAGS_NONE);
g_application_set_flags((GApplication
)app, G_APPLICATION_NON_UNIQUE);
g_signal_connect(app, “startup”, G_CALLBACK(app_startup), NULL);

that will run startup for each instance.

Eric

Unfortunately I still do not fully understand the code.

One point which I try to understand is

HowDoI/GAction - GNOME Wiki! section Action scopes.

What code do I need to get actions for whole app, and what code to get action for one window only.

From HowDoI/GAction - GNOME Wiki!

I may get the feeling that I have to define window actions in activateCb()?

To test I modified your example in this way:

static void test1_callback(GSimpleAction *action, GVariant *parameter, gpointer user_data)
 {
   g_print("Test1 Callback\n");
   GtkWindow *w = gtk_application_get_active_window (GTK_APPLICATION (user_data));
   gtk_window_maximize (w);
 }

My assumption was, that as test1_callback() in an app action, it would maximize all open windows now. But it seems to maximize only one. While quit_program() closes all windows and terminates the app.

Next change what I did was

g_menu_append(section, "Test1", "win.test1");

changing “app.test1” to “win.test1”. Result is that menu entry is grey and can not be selected. Why?

[EDIT]

Well, after one hour of google search I found some more info about Action scopes in

https://wiki.gnome.org/HowDoI/ApplicationMenu

(I did not read that page carefully at the beginning due to the DEPRECATION WARNING).

I really hope Mr Ron Tarrant will write some tutorials about the non trivial points of GTK at some time in the future :slight_smile:

[EDIT 2]

“app” actions affect the application as a whole and are installed directly on the GtkApplication. “win” actions affect one window specifically and are installed onto each GtkApplicationWindow.

From

https://wiki.gnome.org/HowDoI/GAction

we can learn that we can create a a “window” action with

13 window.add_action(action)

and bind it to a button with

19 button.set_action_name("win.save")

But how will the saveCB callback detect that it is a “windows” action from

12 action.connect("activate", saveCb)

From HowDoI/ApplicationMenu - GNOME Wiki!

it seems that for win and app actions there is only a cosmetic difference:

When the application menu is shown by the shell, the “win.” actions are referring to the copy of this action on the currently focused window. If such an action does not exist, the menu item will be greyed out.

But creating a menu item that is always greyed out makes no real sense. So there is no real benefit for win actions, we can always app actions, as C. Eric Cashon did in his example code?

The funny fact is, that for my current GTK version the windows are becoming smaller and smaller, when I move then to the left to make them half screen and move back to recover.

Doing moving left and moving back continuely srinks the window, until errors occur.

So I guess it is not our error.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.