You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GJS中通过Gtk.Context绘制GTK主题窗口按钮?

问题:GJS Cairo上下文无法渲染GTK主题的窗口关闭按钮

我正在尝试从当前GTK活跃主题提取窗口按钮,在GJS的Cairo上下文内渲染,用于Gnome-Global-Menu。最开始我写了一段提取关闭按钮的代码:

this.actor = new St.DrawingArea();
this.actor.connect('repaint', Lang.bind(this, this._onRepaint));

_onRepaint: function(area) {
    let cr = area.get_context();
    let [width, height] = area.get_surface_size();
    let provider = Gtk.CssProvider.get_default();
    let path = new Gtk.WidgetPath();
    let pos1 = path.append_type(Gtk.HeaderBar);
    let pos2 = path.append_type(Gtk.Button);
    path.iter_add_class(pos1, 'titlebar');
    path.iter_add_class(pos2, 'titlebutton');
    path.iter_add_class(pos2, 'close');
    
    let context = new Gtk.StyleContext();
    context.set_screen(Gdk.Screen.get_default());
    context.set_path(path);
    
    context.save();
    context.set_state(Gtk.StateFlags.NORMAL);
    Gtk.render_background(context, cr, 0, 0, width, height);
    Gtk.render_frame(context, cr, 0, 0, width, height);
    context.restore();
},

但这段代码完全没效果。后来我发现Ambiance主题的CSS选择器是这样的:

.titlebar button.titlebutton.close {
    border-color: #333333;
    color: #323112;
    -gtk-icon-shadow: 0 1px rgba(255, 255, 255, 0.25);
    background-image: -gtk-scaled(url("assets/windowbutton-close.png"), url("assets/windowbutton-close@2.png"), url("assets/windowbutton-close@3.png"), url("assets/windowbutton-close@4.png"));
}

而我的代码生成的Widget Path是.titlebar GtkButton.titlebutton.close——因为GJS里Gtk.Button的GType返回的是GtkButton,和主题里用的button不匹配。于是我创建了一个辅助类来修正这个问题:

const GtkButton = new GObject.Class({
    Name: 'button',
    GTypeName: 'button',
    Extends: Gtk.Button,
    _init: function(params) {
        this.parent(params);
    },
});

把代码里的let pos2 = path.append_type(Gtk.Button);替换成let pos2 = path.append_type(GtkButton);后,生成的路径终于和CSS选择器匹配了,但Cairo上下文里还是没有任何内容显示(我的绘图区域尺寸是GNOME Shell面板的27像素)。

另外,我发现直接从实际Gtk Widget获取样式上下文的方式是可行的:

let headerWidget = new Gtk.HeaderBar();
let buttonWidget = new Gtk.Button();
let context = headerWidget.get_style_context();
context.add_class('titlebar');
headerWidget.add(buttonWidget);
context = buttonWidget.get_style_context();
context.add_class('titlebutton');
context.add_class('close');

想请教一下,我现在的代码还缺少什么步骤才能让按钮在Cairo上下文里正常渲染出来?

内容的提问来源于stack exchange,提问作者lestcape

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:21:37