0
votes

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`
1
The same thing, for GtkGrid, was done much earlier, but I think it's included starting from Gtk 3.10.3. gitlab.gnome.org/GNOME/gtk/commit/144a92ef1144lb90
Not a Ubuntu user myself, but looks like you can upgrade to gtk3 3.10.8? launchpad.net/ubuntu/trusty/+source/gtk+3.0lb90
@lb90 Thank you very much for those commit links! Using that information I was able make the example work correctly, by implementing a draw handler myself that renders the background and frame in the same way.Weston
Well, I can't change the system the program is going to run on (it's not an Ubuntu). And I can't ship my own GTK build either. But as stated above, I can solve it in a draw handler. :-) Now I will try the same technique in the real application.Weston

1 Answers

1
votes

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);
  }
};