如何检测X11窗口内容何时改变?

2 投票
1 回答
2602 浏览
提问于 2025-04-17 15:11

我正在尝试写一个工具,把Xvfb的内容转成HTML5画布。这个工具需要知道X11窗口什么时候发生变化,这样才能把屏幕更新发送给客户端。可以把它想象成一个基于网页的VNC或RDP,但仅仅针对X11窗口(为什么要发送整个桌面呢?=)。

以为可以通过Xlib或xcb(xpyb)很简单地做到这一点,但在我的实验中,我最多只能检测到窗口的创建、销毁或移动。这些功能虽然不错,但我还需要知道窗口内容什么时候变化(想象一下,给一个xterm发送一个按键,结果它看起来像是冻结了,直到你移动窗口)。

如果有人知道怎么判断X11窗口内容变化的方法,我非常想听听!我对各种创意解决方案都持开放态度。例如,我尝试使用ffmpeg通过fifo流式传输x11grab,并定期检查是否有变化,但结果发现这在CPU使用率上非常低效(即使没有任何操作,它似乎也会让整个系统变慢)。

我还尝试在一个循环中以15帧每秒的速度抓取屏幕截图,同时尽可能高效地检查变化(例如,看看这个cStringIO缓冲区是否和上一个匹配)。这同样非常消耗CPU。

理想的解决方案是我能监视一个套接字的文件描述符,并在X11窗口发生变化时调用一个处理程序。我愿意接受检测整个X11屏幕变化的方案……这总比我现在的情况要好。

任何帮助都非常感谢!

1 个回答

4

首先,你其实可以用vnc来监控一个窗口的变化,而不是整个桌面。来自x11vnc的文档

-id windowid           Show the X window corresponding to "windowid" not
                       the entire display.  New windows like popup menus,
                       transient toplevels, etc, may not be seen or may be
                       clipped.  Disabling SaveUnders or BackingStore in the
                       X server may help show them.  x11vnc may crash if the
                       window is initially partially obscured, changes size,
                       is iconified, etc.  Some steps are taken to avoid this
                       and the -xrandr mechanism is used to track resizes.  Use
                       xwininfo(1) to get the window id, or use "-id pick"
                       to have x11vnc run xwininfo(1) for you and extract
                       the id.  The -id option is useful for exporting very
                       simple applications (e.g. the current view on a webcam).
-sid windowid          As -id, but instead of using the window directly it
                       shifts a root view to it: this shows SaveUnders menus,
                       etc, although they will be clipped if they extend beyond
                       the window.


-appshare              Simple application sharing based on the -id/-sid
                       mechanism.  Every new toplevel window that the
                       application creates induces a new viewer window via
                       a reverse connection.  The -id/-sid and -connect
                       options are required.  Run 'x11vnc -appshare -help'
                       for more info.

如果你想手动编写类似的功能,你需要使用damage扩展

这里有一个简单的javascript示例,使用node-x11(抱歉,我不太确定python是否支持damage扩展)

var x11 = require('x11');

var X = x11.createClient(function(err, display) {
    X.require('damage', function(Damage) {
        var damage = X.AllocID();
        Damage.Create(damage, parseInt(process.argv[2]), Damage.ReportLevel.NonEmpty);
        X.on('event', function(ev) {
          Damage.Subtract(damage, 0, 0);
          console.log("window content changed!");
        });
    });
});

用窗口的ID作为命令行参数启动它,这样每当窗口内容变化时,你就会收到通知。

撰写回答