Search code examples
cssgtkgtk3gtkmmgtkmm3

Problem styling Gtk::Box with CSS in gtkmm 3.10.1


I have to write a program with gtkmm that runs on a legacy system that has GTK 3.10.1. So I have to steer clear of any features added after that.

I am having some trouble styling Gtk::Box instances using CSS. It works correctly on a Ubuntu 16.04 box that has gtkmm 3.18.0, but on Ubuntu 14.04 with 3.10.1 the CSS isn't applied to Gtk::Box instances.

A boiled down example is below. Here are screen shots of how the example renders on Ubuntu 16.04/gtkmm 3.18.0, and Ubuntu 14.04/gtkmm 3.10.1, respectively.

enter image description here enter image description here

As can be seen the Gtk::Box containing the "YEP" label is not being styled (border and background) on gtkmm 3.10.1.

  1. Am I missing something obvious?
  2. Is this a known issue with 3.10.1?
  3. Any suggestions on how I can achieve the desired result on Ubuntu 14.04/gtkmm 3.10.1?

Thanks!

The code:

// styletest.cpp

#include <gtkmm.h>

class StyleTestWindow : public Gtk::Window
{
public:
  StyleTestWindow();
  virtual ~StyleTestWindow() = default;

protected:
  Gtk::Box    mainbox;
  Gtk::Label  label;
};

StyleTestWindow::StyleTestWindow() :
  mainbox(Gtk::ORIENTATION_VERTICAL)
{
  set_size_request(300, 200);
  set_position(Gtk::WIN_POS_CENTER);
  set_border_width(50);
  set_decorated(false);

  auto css = Gtk::CssProvider::create();
  css->load_from_path("./styletest.css");
  get_style_context()->add_provider_for_screen(Gdk::Screen::get_default(), 
                                               css, 
                                               GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
  get_style_context()->add_class("mainwin");

  label.get_style_context()->add_class("yeplabel");
  label.set_halign(Gtk::ALIGN_CENTER);
  label.set_valign(Gtk::ALIGN_CENTER);
  label.set_text("YEP!");

  mainbox.get_style_context()->add_class("mainbox");
  mainbox.pack_start(label);
  add(mainbox);

  show_all_children();
}

int
main(int argc, char *argv[])
{
  Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.example.styletest");

  StyleTestWindow mainWindow;
  return app->run(mainWindow);
}

The CSS:

/* styletest.css */

.mainwin {
    background: #DEB887;
    border: 5px solid #996600;
}

.mainbox {
    background: #cc9900;
    border: 5px solid #C00000;
}

.yeplabel {
    color: #FFFFFF;
    background: #A52A2A;
    font: Comic Sans MS 16;
    padding: 10px;
}

Build with:

g++ -std=c++11 styletest.cpp -o styletest `pkg-config gtkmm-3.0 --cflags --libs`

Solution

  • A comment from @lb90 led me to a solution.

    The commit that introduces the missing rendering of Gtk::Box background and border using style context, is here: https://gitlab.gnome.org/GNOME/gtk/commit/698488ddc4

    Using the technique from said commit, I was able to work around the issue. I introduce a StyleBox class that derives from Gtk::Box and overrides the on_draw() handler. In on_draw() the background and border is rendered.

    In the example code StyleTestWindow.cpp, just change mainbox's type from Gtk::Box to StyleBox.

    StyleBox.h

    class StyleBox : public Gtk::Box
    {
    public:
      explicit StyleBox(Gtk::Orientation orientation =  Gtk::ORIENTATION_HORIZONTAL, int spacing =  0) :
        Gtk::Box(orientation, spacing)
      {
      }
    
      virtual ~StyleBox() = default;
    
    protected:
      virtual bool on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr) override
      {
        GtkWidget *widget = GTK_WIDGET(gobj());
        GtkStyleContext *context;
        GtkAllocation alloc;
        cairo_t *ccr = const_cast<cairo_t*>(cr->cobj());
    
        context = gtk_widget_get_style_context (widget);
        gtk_widget_get_allocation (widget, &alloc);
    
        gtk_render_background(context, ccr, 0, 0, alloc.width, alloc.height);
        gtk_render_frame(context, ccr, 0, 0, alloc.width, alloc.height);
    
        return Box::on_draw(cr);
      }
    };