Skip to content

Instantly share code, notes, and snippets.

@matzipan
Last active November 1, 2023 22:55
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save matzipan/d4e78f3e5ea95890f403871b50d63b76 to your computer and use it in GitHub Desktop.
Save matzipan/d4e78f3e5ea95890f403871b50d63b76 to your computer and use it in GitHub Desktop.
Vala, GLib and GTK+ cheatsheet

Building with debug symbols with cmake

cmake -DCMAKE_BUILD_TYPE=Debug .. should do the trick of building the binaries and including the debug symbols.

Enable debug messages

Set the following environment variable G_MESSAGES_DEBUG=all. This will allow you to see messages you print with debug in Vala.

GtkApplication lifecycle

More info here.

Markup escaping

If you try and set_text on a Gtk.Label a string which might contain markup characters (<>&), you need to escape them first, using GLib.Markup.escape_text.

Remove timeout when Gtk.Widget is unrealized

This one allows you to have repeating timeouts which end when the owning Gtk.Widget approaches the end of its lifecycle.

var timeout_reference = GLib.Timeout.add_seconds(10, () => { 
    // do job here
    
    return true; 
});
        
unrealize.connect(() => { 
    GLib.Source.remove (timeout_reference);
});

Path constructing

Instead of using standard string constructing method path_string1 + path_string2 you can use GLib.Path.build_filename method in order to construct a valid path to a file, for example: GLib.Path.build_filename (GLib.Environment.get_home_dir (), "folder1", "folder2").

Missing return

If your function has a non-void return value and your return statements are wrapped in outer if/while blocks, you might be met with a compiler error saying there is a missing return statement at end of subroutine body. If you are sure the logic is sound, and your code will never reach the end of a function, you can use an assert_not_reached () function call.

Showing and hiding GTK widgets

public static void set_widget_visible (Gtk.Widget widget, bool visible) {
    widget.no_show_all = !visible;
    widget.visible = visible;
}

The reason behind this is that even if the widget is hidden with widget.visible = false;, if, at some point in the future, a parent of that has show_all () invoked on it, it will also reveal the widget we wanted to hide. no_show_all disables that behavior.

On inheritance of constructors

For various reasons, including some listed here, you might want to use GObject style construction. The downside is that, if you use this construction method, all the children which inherit your class will also inherit your class' constructor. Your only way around this is to make your parent class abstract and extract the code you don't want inherited in a separate class, which still uses GObject style construction.

Transfer ownership with getters

If you see the following error when compiling, error: Return value transfers ownership but method return type hasn't been declared to transfer ownership, use owned get like so:

owned get {
    ...
}

To make Gtk.Pixbuf work with hidpi

A custom Gtk.DrawingArea, which uses the following snippet in the draw signal handler:

var surface = Gdk.cairo_surface_create_from_pixbuf (pixbuf, scale_factor, null);
context.set_source_surface (surface, 0, 0);

For example:

private class CustomPixbuf : Gtk.DrawingArea {
        private int HEIGHT = 16;
        private int WIDTH = 16;
        
        private Gdk.Pixbuf _pixbuf;
        public Gdk.Pixbuf pixbuf {
            get {
                return _pixbuf;
            }

            set {
                _pixbuf = value;

                queue_draw ();
            }
        }

        public CustomPixbuf () {
            Object ();
        }

        construct {
            set_size_request (WIDTH, HEIGHT);
        }

        public override bool draw (Cairo.Context context) {
            var width = get_allocated_width ();
            var height = get_allocated_height ();
            
            if(_pixbuf!=null) {
                var surface = Gdk.cairo_surface_create_from_pixbuf (pixbuf, scale_factor, null);
                context.set_source_surface (surface, 0, 0);
            }
            
            context.rectangle(0, 0, width, height);
            context.fill ();

            return Gdk.EVENT_STOP;
        }        
    }
}

Debugging fatal warnings

If you want to catch fatal warnings or any other GLib message you can use the environment variable called G_DEBUG. That means that if you run, say, G_DEBUG=fatal-warnings gdb <your program>, the execution will stop at the type of message you've specified. Then you can just type bt and gdb will show you a the current stack trace. More in in the glib documentation.

Trigger gdb breakpoint programatically

To trigger a gdb breakpoint programatically, call GLib.breakpoint ().

Profiling with gprof

Pass the following argument to CMake: -DCMAKE_C_FLAGS=-pg. Build and run the program normally from the command line, and it will produce a fille called gmon.out in the working directory. Pass this file to gprof: gprof <your executable> gmon.out > analysis.out. By default it will first list a flat performance profile and somewhere below it, there will be a call graph.

GTK widgets that cannot recieve events

Some GTK Widgets do not have a GDK window associated to them. Without a window they cannot process events. Below is a list of these widgets:

  • Gtk.Alignment
  • Gtk.Arrow
  • Gtk.Bin
  • Gtk.Box
  • Gtk.Image
  • Gtk.Item
  • Gtk.Label
  • Gtk.Pixmap
  • Gtk.ScrolledWindow
  • Gtk.Separator
  • Gtk.Table
  • Gtk.AspectFrame
  • Gtk.Frame
  • Gtk.VBox
  • Gtk.HBox
  • Gtk.VSeparator
  • Gtk.HSeparator

Significant contributions to this list from Adam Bieńkowski.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment