menumenubarvalagtk4

How do I make a Gtk4 application with a menu bar in Vala?


I attempted to make a simple Gtk4 application, and I tried to add a menu bar with a menu that does two things: print “Hello, World” and quit.

The code compiles as expected with the command

valac --pkg=gtk4 menutest.vala

However, although the window appears, the menu bar does not. I have tried this in both macOS (using Homebrew) and Fedora. What am I doing wrong?

Here is the sample code:

// menutest.vala

using Gtk;

public class Menutest : Gtk.Application {

    public Menutest() {
        Object (application_id: "org.gtk.menutest");
    }

    protected override void activate() {
        var window = new ApplicationWindow (this);
        window.title = "Hello World";
     
        // Create a menu with two items
        var menu = new Menu();
        menu.insert(0, "Hello", "app.hello");
        menu.insert(1, "Quit", "app.quit");

        // Set the menu as the application's menubar
        this.set_menubar(menu);

        // Define the actions for the menu items
        SimpleAction hello = new SimpleAction("hello", null);
        hello.activate.connect(hello_action);
        this.add_action(hello);

        SimpleAction quit = new SimpleAction("quit", null);
        quit.activate.connect(quit_action);
        this.add_action(quit);

        window.present();
    }

    public static int main (string[] args) {
        return new Menutest().run (args);
    }

    // The callback function for the "Hello" action
    private void hello_action (SimpleAction action, Variant? parameter) {
        print ("Hello, world!\n");
    }

    // The callback function for the "Quit" action
    private void quit_action (SimpleAction action, Variant? parameter) {
        this.quit ();
    }
}

The result in macOS (no menus are added at the top of the screen either):

enter image description here

The result in Fedora:

enter image description here


Solution

  • The issue was that you were missing a submenu item for the menu bar. After adding the submenu, the code now works as expected:

    using Gtk;
    
    public class Menutest : Gtk.Application {
    
        public Menutest() {
            Object (application_id: "org.gtk.menutest");
        }
    
        protected override void activate() {
            var window = new ApplicationWindow (this);
            window.title = "Hello World";
         
            // Create root menu (menu bar).
            var menu = new Menu ();
            
            // Create window submenu and insert (The "Window" entry you'll see in the menu bar)
            var window_menu = new Menu ();
            window_menu.insert(0, "Hello", "app.hello");
            window_menu.insert(1, "Quit", "app.quit");
    
            // Add window submenu to menu bar
            menu.append_submenu ("Window", window_menu);
            
            // Set the menu as the application's menubar
            this.set_menubar(menu);
            window.set_show_menubar (true);
    
            // Define the actions for the menu items
            SimpleAction hello = new SimpleAction("hello", null);
            hello.activate.connect(hello_action);
            this.add_action(hello);
    
            SimpleAction quit = new SimpleAction("quit", null);
            quit.activate.connect(quit_action);
            this.add_action(quit);
    
            window.present();
        }
    
        public static int main (string[] args) {
            return new Menutest().run (args);
        }
    
        // The callback function for the "Hello" action
        private void hello_action (SimpleAction action, Variant? parameter) {
            print ("Hello, world!\n");
        }
    
        // The callback function for the "Quit" action
        private void quit_action (SimpleAction action, Variant? parameter) {
            this.quit ();
        }
    }
    

    GTK4 Hello World App with menu bar containing one submenu item labelled "Window"