Search code examples
csscgtkgtk3

GTK3 CCS style not being applied


I am unable to set any style on a widget by name. Here is my code:

#include <gtk/gtk.h>

#define CSS_STYLE           "\
#first {                     \
    background-color: black; \
    background-image: none;  \
    border-width: 0;         \
    color: yellow            \
}"

int main (void)
{
    gtk_init(0, NULL);

    GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    g_signal_connect(win, "delete_event", G_CALLBACK(gtk_main_quit), NULL);

    GtkWidget *radio1 = gtk_radio_button_new(NULL);
    gtk_widget_set_name(radio1, "first");
puts(gtk_widget_get_name(radio1));

    GtkCssProvider *provider = gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider, CSS_STYLE, -1, NULL);
    gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVI>

    gtk_container_add(GTK_CONTAINER(win), radio1);
    gtk_widget_show_all(win);
    gtk_main();

    exit(EXIT_SUCCESS);
}

The non-indented puts shows the name for the radiobutton is set correctly. But none of the styling is applied. I know the code is correct, because if I change #first to radio in the css, the styling is applied to the radiobutton.

Can someone please help me understand what I'm doing wrong here?


Solution

  • The best explanation I can give is that the radio button widget is actually comprised of a "radio" child widget that sets within a background area and can contain a label. So the radio button widget, as a whole, will fill up the widget that it is placed within. In your code, since you are attaching the single radio button widget directly to the window, that widget will expand to fill the whole window. So you will see a completely black window with the small button. To provide a contrast to this behavior, I made a revised version of your code to place the radio button into a grid widget (along with a placeholder button widget) and then place the grid widget into the window. Following is the revised code.

    #include <gtk/gtk.h>
    
    #define CSS_STYLE           "\
    #first {                     \
        background-color: black; \
        background-image: none;  \
        border-width: 20;        \
        color: yellow            \
    }
    
    int main (void)
    {
        gtk_init(0, NULL);
        
        GtkWidget *win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        g_signal_connect(win, "delete_event", G_CALLBACK(gtk_main_quit), NULL);
        
        GtkWidget *grid = gtk_grid_new();
        GtkWidget *button = gtk_button_new_with_label("OK");
        
        GtkWidget *radio1 = gtk_radio_button_new(NULL);
        gtk_widget_set_name(radio1, "first");
        
        gtk_grid_attach(GTK_GRID(grid), radio1, 0, 0, 1, 1);
        gtk_grid_attach(GTK_GRID(grid), button, 1, 0, 1, 1);
        
        GtkCssProvider *provider = gtk_css_provider_new();
        gtk_css_provider_load_from_data(provider, CSS_STYLE, -1, NULL);
        gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
        
        gtk_container_add(GTK_CONTAINER(win), grid);
        gtk_window_set_default_size(GTK_WINDOW(win), 200, 100); /* Added this is to give the window an initial size */
        gtk_widget_show_all(win);
        gtk_main();
        
        exit(EXIT_SUCCESS);
    }
    

    Following are some sample images contrasting the attachment of the radio button widget directly to the window versus inserting the radio button widget into a grid and then attaching the grid to window.

    Radio button contrast

    You can still see a bit of an undesired background effect. So to truly associate the background to just the area that the button occupies would require including the reference to the "radio" element of the radio button widget as follows.

    #first radio {              \
    

    Revising the style definition will result in background just for the radio button icon to be set as seen in the following illustration.

    Radio button within grid

    The last bit to touch on was the color attribute in your CSS block. It appears that you wanted to change the radio button color to yellow. However, the actual button that appears is an icon and its source is dependent upon the theme being used and usually found in the theme's asset folder. However, there is a lengthy GTK theme reference that you could use if you want to direct the icon image to the same image within another theme. Following is the GTK-specific CSS directive that you could use that I integrated into your CSS definition.

    #define CSS_STYLE           "\
    #first radio {              \
        background-color: black; \
        background-image: none;  \
        border-width: 20;         \
    } \
    #first radio:checked {-gtk-icon-source: -gtk-scaled(url(\"/usr/share/themes/Mint-X-Orange/gtk-3.0/assets/radio-selected.png\"), \
        url(\"/usr/share/themes/Mint-X-Orange/gtk-3.0/assets/[email protected]\"));\
    }"
    

    It is a bit messy, but it does redirect the radio button icon to a different colored icon.

    Orange radio button

    FYI, I chose orange. I did not spot a yellow colored theme on my system. Also, this theme folder structure is how Linux Mint stores theme information. It might be different on your system, so you might have to do some exploration if you want to affect the icons used.

    I hope that clarifies things.

    Regards.