Search code examples
gtkgtk3vala

Why gtk css widget styling does not work?


I'm trying to style widget from inside of it's constructor in Vala but I don't get the result I want. Here is the original code sample:

public class MyWidget : Gtk.FlowBox {

    public MyWidget () {
        var css_provider = new Gtk.CssProvider ();
        try {
            css_provider.load_from_data (
                """
                label {
                    color: blue;
                }
                """
            );
            get_style_context ().add_provider (css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
        } catch (Error e) {
            message ("error");
        }
    }

    public void add_entry (string s) {
        var entry = new Gtk.Label (s);
        add (entry);
    }

}

I've tried all different variants of styling "flowbox", "flowboxchild", "label" etc. and only one that works is "*" for every element inside GtkFlowbox or assigning it to a class, thought I still can't style it's children. Priorities don't seem to change anything, adding global "flowbox" styles for screen context don't work too.

I've tried to do it using gtk inspector but no result here too.

So how do I style all children of widget? Or do I need to specify class for them?


Solution

  • Here is a working example:

    public class MyWidget : Gtk.FlowBox {
    
        public MyWidget () {
            this.add_entry ("default text");
        }
    
        public void add_entry (string s) {
            var entry = new Gtk.Label (s);
            add (entry);
        }
    
    }
    
    void main (string[] args) {
        Gtk.init (ref args);
    
        var window = new Gtk.Window ();
        window.destroy.connect (Gtk.main_quit);
        window.window_position = Gtk.WindowPosition.CENTER;
        window.set_default_size (300, 80);
        window.add (new MyWidget ());
    
        var css_provider = new Gtk.CssProvider ();
        try {
            css_provider.load_from_data (
                """
                GtkLabel {
                    color: blue;
                }
                """
            );
            Gtk.StyleContext.add_provider_for_screen (
                                     Gdk.Screen.get_default (),
                                     css_provider,
                                     Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
                                     );
        } catch (Error e) {
            message ("error loading CSS provider");
        }
    
        window.show_all ();
    
        Gtk.main ();
    }
    

    Compile with:

    valac --pkg gtk+-3.0 css_provider_example.vala

    add_provider is a provider for that widget only. add_provider_for_screen adds the stylesheet for all widgets in the application. I can understand for_screen can be a little misleading by making someone think it applies to all applications on that screen, but from what I can tell that is not the case.

    I've moved the add_provider_for_screen section to the main () block to clarify it is for the whole application. If you want the style to only apply to GtkLabels inside GtkFlowBoxes then the selector GtkFlowBox GtkLabel should work.

    Also the terminology 'node' and 'selector' seems a little confusing. I had to change label in the GTK+ CSS to GtkLabel. A 'node' is probably the part of the widget that can be affected by the CSS rather than an identifier for selection, but anyone clarifying that would be very helpful! I have found that .label does work. So label is treated like a class name in CSS and GtkLabel like an element. Note the dot before label. .flowbox doesn't seem to work though.