Adding custom CSS properties in gtkmm is actually pretty simple once you know how. It took me quite a bit of searching along with some trial and error before I came up with a pretty simple pattern for doing so. What I was looking for was a way to use custom CSS without having to develop a whole bunch of custom classes which extended Gtk base classes.
First thing we need to do is to create a class that extends from Gtk::Widget. Now, we don’t necessarily have to use the class directly as a visual object however, it does need to extend the Gtk::Widget class for it to work. The following is my example for creating simple custom CSS properties. Let’s start off by adding a single custom property called “width”.
class CustomCSS : public Gtk::Widget { public: Gtk::StyleProperty<int> width_property; int width; CustomCss() : Glib::ObjectBase("customcss"), Gtk::Widget(), //-gtkmm__CustomObject_customcss-width width_property(*this, "width", 100), width(100) {} };
Let’s examine the above code to find out what’s really going on here.
class CustomCSS : public Gtk::Widget
First we need to create a class the extends the Gtk::Widget class.
public:
Gtk::StyleProperty<int> width_property;
int width;
Next, we need to add a public style property that defines what will be reading the width values and a simple property of the type we’ll want to use, in this case an int.
CustomCss() :
Glib::ObjectBase("customcss"),
Gtk::Widget(),
//-gtkmm__CustomObject_customcss-width
width_property(*this, "width", 100),
width(100)
{}
Finally, we’ll want to implement a default constructor where we set the name we will be using in our CSS to reference this class “customcss”, pass in the Gtk::Widget() constructor, then we’ll need to being initializing our custom properties to be used in CSS. For this, we initialize the width_property, give it a CSS property name of “width” and set the default value to 100. Then we do the same for the actual property by calling width(100).
Now, if we want to use the custom CSS class and properties we’ll need to add them to our CSS file. I noted above also that in our CSS file, the “width” property would actually need to be specified as “-gtkmm__CustomObject_customcss-width”. The first part “-gtkmm__CustomObject_” will be the default used by gtkmm when accessing the custom property, the last two parts “customcss” and “width” we control by setting the Glib::ObjectBase(“customcss”) and the width_property(*this, “width”, 100) respectively.
/* somefile.css */ { -gtkmm__CustomObject_customcss-width: 500; }
To enable this custom property to be used, we first need to define an all selector “*” followed by our CSS implementation which contains “-gtkmm__CustomObject_customcss-width: 500;”. Now, let’s use it in our C++ application.
include <gtkmm.h> int main(int argc, char ** argv){ //your code doing something useful //setup our css context and provider Glib::ustring cssFile = "/path/to/somefile.css"; Glib::RefPtr<Gtk::CssProvider> css_provider = Gtk::CssProvider::create(); Glib::RefPtr<Gtk::StyleContext> style_context = Gtk::StyleContext::create(); //load our css file, wherever that may be hiding if(css_provider->load_from_path(HOME_DIRECTORY + "/.config/xfce4/finder/xfce4-finder.css")){ Glib::RefPtr<Gdk::Screen> screen = window->get_screen(); style_context->add_provider_for_screen(screen, css_provider, GTK_STYLE_PROVIDER_PRIORITY_USER); } //instantiate our custom css class CustomCss css; //get the width int width = css.width_property.get_value(); //do something useful with the width we retrieved from css //run application run application->run(main_window); return EXIT_SUCCESS; }
As you can see from the above, we’ve created both a CssProvider and a StyleContext, then we load our CSS file by using load_from_path, set our screen to be the main application window’s screen, then finally we add a provider by calling add_provider_for_screen. Once that’s all done we can use our CustomCSS class. Simply instantiate it, and call get_value() of the property we want to use. It’s that simple. If we wanted to add more than one property, we just added them to the constructor’s inline calls like so.
class CustomCSS : public Gtk::Widget { public: Gtk::StyleProperty<int> width_property; int width; Gtk::StyleProperty<int> height_property; int height; //etc... CustomCss() : Glib::ObjectBase("customcss"), Gtk::Widget(), //-gtkmm__CustomObject_customcss-width width_property(*this, "width", 100), width(100), //-gtkmm__CustomObject_customcss-height height_property(*this, "height", 50), height(50) //etc... {} };
Once again, we add the new properties if we want to our CSS file.
/* somefile.css */ { -gtkmm__CustomObject_customcss-width: 500; -gtkmm__CustomObject_customcss-height: 100; /* etc… */ }
Then we access them the same way as before in our C++ code.
//instantiate our custom css class CustomCss css; //get the width int width = css.width_property.get_value(); //get the height int height = css.height_property.get_value(); //get etc…
I hope this helps. I found this a simple and clean way of introducing custom CSS properties without having to create a bunch of Gtk::Widget classes. As always, thanks for stopping by and let me know if there’s anything I can do to help.
Some of the text in the examples looks as though it’s white. I have to select the text to read it. Is that something you could fix?
I’m a newbie at gtkmm: I don’t know how to associate the css property with the widget. I can’t see how deriving from widget something that uses stylesheet values affects other Gtk elements derived from widget. Something is missing from the picture. I would ordinarily expect there to be some way to apply an “id” or “class” identifier to Gtk elements you want to have the style sheet apply to, but I can’t find it. You usually wouldn’t want to set one style for a Label widget since that could have multiple uses that the style wasn’t applicable to.
I’m having trouble connecting the dots here. Is there a good example that does that?
Thanks
Chris