I am trying to provide my own implementation of a GtkStyleProvider
, since the "normal" CSS provider is a lot of work and extra processing to use in my case.
I want to be able to provide widget styling based on some internal state, and to do this in CSS, I'd have to write out a huge string of CSS (translating things like Pango.FontDescription
s into CSS-style declarations) based on any change in state, and then feed it into a GktCssProvider
which will process it back into Gtk-land. Compare to a custom provider, which will just signal (somehow) that its client widgets should ask it for style and it hand out new styling based directly on the state.
It seems that GtkStyleProvider
is a way to achieve that - I can make a provider that returns styling based on some state, and add it as a style provider to the relevant GtkStyleContext
. The (C) interface is
// deprecated - return NULL in new code
GtkIconFactory * gtk_style_provider_get_icon_factory (
GtkStyleProvider *provider,
GtkWidgetPath *path);)
// deprecated - return NULL in new code
GtkStyleProperties * gtk_style_provider_get_style (
GtkStyleProvider *provider,
GtkWidgetPath *path))
// return true if property found and has a value, else false
gboolean gtk_style_provider_get_style_property (
GtkStyleProvider *provider,
GtkWidgetPath *path,
GtkStateFlags state,
GParamSpec *pspec,
GValue *value);
To this end, I wrote something like this, which I expected to work, but do nothing, as it should always report the property is not set:
# compile with: valac styleprov.vala --pkg gtk+-3.0 --pkg gdk-3.0
using Gtk;
using Gdk;
public class DerivedStyleProvider : Object, Gtk.StyleProvider
{
public unowned Gtk.IconFactory get_icon_factory (Gtk.WidgetPath path)
{
return (Gtk.IconFactory) null; // Evil cast to work around buggy declaration in VAPI file
}
public Gtk.StyleProperties get_style (Gtk.WidgetPath path)
{
return (Gtk.StyleProperties) null; // Evil cast to work around buggy declaration in VAPI file
}
public bool get_style_property (Gtk.WidgetPath path,
Gtk.StateFlags state,
GLib.ParamSpec pspec,
out GLib.Value value)
{
stdout.printf("get_style_property");
// Compiler happiness for testing
value = Value (typeof (string));
return false; //TODO
}
}
public class styleprov.MainWindow : Gtk.Window
{
construct {
DerivedStyleProvider styleProvider = new DerivedStyleProvider();
// but this would work
//Gtk.CssProvider styleProvider = new Gtk.CssProvider();
//styleProvider.load_from_data("*{ background-color: #ff0000; }");
StyleContext.add_provider_for_screen(this.get_screen(),
styleProvider,
Gtk.STYLE_PROVIDER_PRIORITY_USER);
}
}
class styleprov.Main : GLib.Object
{
public void run() {
styleprov.MainWindow mainWindow = new styleprov.MainWindow();
mainWindow.show_all();
}
public static int main (string[] args) {
Gtk.init (ref args);
Main app = new Main();
app.run();
Gtk.main ();
return 0;
}
}
This compiles OK, and runs up, but almost spews warnings:
(styleprov:32365): GLib-GObject-WARNING **: gsignal.c:2523: signal '-gtk-private-changed' is invalid for instance '0x1154ac0' of type 'DerivedStyleProvider'
(styleprov:32365): Gtk-WARNING **: (gtkstylecascade.c:256):gtk_style_cascade_lookup: code should not be reached
(styleprov:32365): Gtk-WARNING **: (gtkstylecascade.c:256):gtk_style_cascade_lookup: code should not be reached
...several of these....
Warnings notwithstanding, the get_style_property()
method never appears to be called, and so no custom styling can be provided.
Replacing the DerivedStyleProvider
with a "normal" CSS provider works fine.
What is the right way to implement a custom GtkStyleProvider
(in any language)?
Looking at the implementation of
GtkCssProvider
, which appears to use not onlyGtkStyleProviderInterface
but alsoGtkStyleProviderPrivateInterface
, and a lot of complex custom bypassing (apparently for efficiency reasons, according to the friendly folks on he GTK+ IRC channel), I decided to just use the normal CSS method and just deal with constructing the CSS by hand as a string.The mechanism is:
GtkCssProvider
is createdgtk_style_context_add_provider()
(or the globalgtk_style_context_add_provider_for_screen()
)GtkCssProvider
gtk_css_provider_load_from_data()
.I suppose the problem is likely that I don't fully understand how GTK+ works underneath. If you treat the CSS as the canonical style "oracle" for the UI, then I suppose that updating the CSS really is actually the correct approach, and I'm expecting a low-level access that is perhaps technically possible, but is not "correct" in the GTK+ way.
This low-level access is what I have grown to expect from other frameworks where you (only) have direct control over the styling of things like "background colour" of widgets, and there's no CSS layer to abstract it, but is just not how it works in GTK+ (any more).
At least, that's how I understand it!