我正在尝试编写一个Xvfb-to-HTML5-canvas工具,需要知道X11窗口何时更改,以便它可以向客户端发送屏幕更新。可以把它想象成基于网络的VNC或RDP,但只是用于X11窗口(为什么要发送整个桌面?=)。
我想通过Xlib或xcb(xpyb)可以直接做到这一点,但在我的实验中,我能做的最好的事情就是检测窗口何时创建,销毁或移动。这很好,除了我需要知道什么时候窗口的内容也会发生变化(想象一下将一个按键发送到xterm并让它看起来是冻结的,直到你移动窗口)。
如果有人知道如何判断X11窗口的内容何时发生变化,我很乐意听到它!我对创造性的解决方案持开放态度。例如,我尝试使用ffmpeg通过fifo流式传输x11grab并定期检查以查看是否有任何更改,但结果显示在CPU利用率方面效率极低(即使没有任何操作,它似乎也会降低整个系统的速度)。
我还尝试在循环中抓取15fps的屏幕截图,同时以最有效的方式检查更改(例如,此cStringIO缓冲区是否匹配最后一个?)。这也是CPU密集型的。
理想的解决方案是让我能够观察套接字的文件描述符并在X11窗口发生更改时调用处理程序。我愿意接受检测整个X11屏幕何时发生变化...这仍然比我所拥有的要好。
对此有任何帮助表示赞赏!
答案 0 :(得分:4)
首先,您实际上可以使用vnc来跟踪一个窗口中的更改,而不是整个桌面。来自x11vnc documentation:
-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 extension。
以下是使用node-x11的javascript中的简单示例(抱歉,我不确定python中的损坏扩展支持)
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作为命令行参数启动它,并且每当窗口内容发生更改时,您都会收到通知。