GtkStyleProvider - 提供自己的实现

GtkStyleProvider - providing own implementation

我正在尝试提供我自己的 GtkStyleProvider 实现,因为 "normal" CSS 提供程序在我的案例中需要大量工作和额外处理。

我希望能够根据某些内部状态提供小部件样式,并且要在 CSS 中执行此操作,我必须写出一大串 CSS(翻译内容像 Pango.FontDescriptions 到 CSS 风格的声明)基于任何状态的变化,然后将它送入 GktCssProvider 将处理它 back进入 Gtk 领域。与自定义提供程序相比,自定义提供程序只会(以某种方式)发出信号表明其客户端小部件应该向其询问样式,并直接根据状态分发新样式。

似乎 GtkStyleProvider 是实现这一目标的一种方式 - 我可以制作一个提供者 returns 基于某种状态的样式,并将其作为样式提供者添加到相关 GtkStyleContext. (C)界面为

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

为此,我写了这样的东西,我希望它能工作,但什么也没做,因为它应该总是报告 属性 未设置:

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

编译正常,运行正常,但几乎会发出警告:

(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....

尽管有警告,get_style_property() 方法似乎从未被调用,因此无法提供自定义样式。

用 "normal" CSS 提供程序替换 DerivedStyleProvider 工作正常。

实现自定义 GtkStyleProvider(任何语言)的正确方法是什么?

查看 GtkCssProvider 的实现,它似乎不仅使用了 GtkStyleProviderInterface,还使用了 GtkStyleProviderPrivateInterface,以及大量复杂的自定义绕过(显然是出于效率原因,根据GTK+ IRC 频道上的好心人),我决定只使用普通的 CSS 方法,只处理手动构建 CSS 作为字符串。

机制是:

  • 创建了一个 GtkCssProvider
  • Provider 附加到具有 gtk_style_context_add_provider()(或全局 gtk_style_context_add_provider_for_screen())的相关样式上下文
  • 数据管理器发出数据已更改的信号
  • 这被我的 Data->CSS 翻译器捕获,它为相关的 GtkCssProvider
  • 生成一个新的 CSS 字符串
  • 此字符串通过 gtk_css_provider_load_from_data() 馈送到现有提供程序。
  • 该更新导致的任何 UI 更改都会自动发生

我想问题很可能是我没有完全理解 GTK+ 是如何工作的。如果您将 CSS 视为 规范样式 "oracle" 用于 UI,那么我认为更新 CSS 确实 实际上是正确的方法,我期待一种技术上可能可行的低级别访问,但不是 "correct" GTK+ 方式。

这种低级访问是我对其他框架的期望,在这些框架中,您(仅)可以直接控制 "background colour" 小部件的样式,并且没有 CSS层来抽象它,但这不是它在 GTK+ 中的工作方式(不再)。

至少我是这么理解的!