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

如何在Vala GTK应用中识别X11根窗口事件类型?

问题描述

尝试在Vala GTK应用中识别X11根窗口的事件类型,但无论触发何种事件,事件类型的to_string()结果始终为GDK_NOTHING,原始枚举值为-1,输出示例:

filtering event type=GDK_NOTHING(-1), GDK_NOTHING, GDK_NOTHING
filtering event type=GDK_NOTHING(-1), GDK_NOTHING, GDK_NOTHING
filtering event type=GDK_NOTHING(-1), GDK_NOTHING, GDK_NOTHING

示例代码:

using Gtk;
using Gdk;
using X11;
using GLib;

public class App : Gtk.Application {
    public static int main(string[] args) {
        app = new App();
        app.register(null);

        var gdk_root = Gdk.get_default_root_window();
        gdk_root.set_events(Gdk.EventMask.ALL_EVENTS_MASK);

        gdk_root.add_filter((filter, event) => {
            stdout.printf("filtering event type=%s(%d), %s, %s\n",
                          event.type.to_string(),
                          event.type,
                          event.get_event_type().to_string(),
                          event.window_state.type.to_string());
            return Gdk.FilterReturn.CONTINUE;
        });

        return app.run(args);
    }

    private static App app;
}
解决方案
  • 直接访问X11原生事件结构体:GDK封装的Gdk.Event对于根窗口的部分事件不会正确填充type字段,需要通过event.xevent获取X11原生事件数据,以此判断事件类型。
  • 确保获取X11特定的窗口实例:将根窗口转换为Gdk.X11.X11Window,才能正常访问X11相关的事件接口。

修改后的可运行代码:

using Gtk;
using Gdk;
using Gdk.X11;
using X11;
using GLib;

public class App : Gtk.Application {
    public static int main(string[] args) {
        var app = new App();
        app.register(null);

        // 确认运行在X11环境下并获取X11显示实例
        var display = Gdk.Display.get_default() as Gdk.X11.X11Display;
        if (display == null) {
            stderr.printf("当前环境不是X11\n");
            return 1;
        }

        // 获取X11根窗口ID并查找对应的GDK窗口
        var x11_root_win_id = display.get_xrootwindow();
        var gdk_root = Gdk.X11.X11Window.lookup_for_display(display, x11_root_win_id);
        
        // 订阅所有根窗口事件
        gdk_root.set_events(Gdk.EventMask.ALL_EVENTS_MASK);

        gdk_root.add_filter((filter, event) => {
            var xevent = event.xevent;
            if (xevent == null) {
                return Gdk.FilterReturn.CONTINUE;
            }

            // 映射X11事件类型到可读名称
            string event_name;
            switch (xevent.type) {
                case X11.EventType.KeyPress:
                    event_name = "按键按下";
                    break;
                case X11.EventType.KeyRelease:
                    event_name = "按键释放";
                    break;
                case X11.EventType.ButtonPress:
                    event_name = "鼠标按下";
                    break;
                case X11.EventType.ButtonRelease:
                    event_name = "鼠标释放";
                    break;
                case X11.EventType.MotionNotify:
                    event_name = "鼠标移动";
                    break;
                case X11.EventType.PropertyNotify:
                    event_name = "属性变更";
                    break;
                case X11.EventType.ClientMessage:
                    event_name = "客户端消息";
                    break;
                default:
                    event_name = $"未知事件({xevent.type})";
                    break;
            }

            stdout.printf("捕获X11事件: %s\n", event_name);
            return Gdk.FilterReturn.CONTINUE;
        });

        return app.run(args);
    }
}
  • 关键说明:
    • 必须通过Gdk.X11.X11Display和Gdk.X11.X11Window来操作X11根窗口,普通Gdk.Window无法完整暴露X11原生事件。
    • 直接读取xevent.type判断事件类型,这是获取根窗口事件类型的可靠方式,避免GDK封装带来的信息丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:53:10