我正在编写一个具有X11 / Xlib接口的程序,我的事件处理循环如下所示:
while (XNextEvent(display, &ev) >= 0) {
switch (ev.type) {
// Process events
}
}
问题是当窗口调整大小时,我收到一堆Expose
个事件,告诉我要重绘的窗口部分。如果我直接响应事件重绘它们,重绘操作就会非常滞后,因为它很慢(调整大小后我会看到所有新生效的矩形逐个刷新。)
我想要做的是在更改时记录更新的窗口大小,并且只有在没有剩余事件需要处理的情况下,才在整个窗口(或至少只有两个矩形)上运行一次重绘操作。
不幸的是我看不到这样做的方法。我试过这个:
do {
XPeekEvent(display, &ev);
while (XCheckMaskEvent(display, ExposureMask | StructureNotifyMask, &ev)) {
switch (ev.type) {
// Process events, record but don't process redraw events
}
}
// No more events, do combined redraw here
}
哪个确实有效,但效率有点低,如果一个事件到来,我对XCheckMaskEvent
调用不感兴趣,就不会将它从队列中删除,所以它停在那里{{1}阻止,导致100%的CPU使用。
我只是想知道是否有一种标准方法来实现我追求的延迟/组合重绘?许多Xlib事件处理函数似乎都被阻塞了,所以如果你想在它们阻塞之前做一些处理它们就不适合使用它们,但只有当它们阻塞时才会使用它们!
编辑:为了记录,这是我使用的解决方案。它是n.m.的简化版本:
XPeekEvent
答案 0 :(得分:4)
FWIW像GTK +这样的UI工具包就是这样做的:
poll()
上的ConnectionNumber(dpy)
)在GTK +中,他们将在未来的版本中将其更改为更现代的3D引擎(清除垂直同步中的损坏区域),但它在上面以相当简单的方式工作多年。 / p>
当翻译为原始Xlib时,这看起来像是n.m.的答案:当你有一个伤害区域和!XPending()
时重绘。所以我可以随意接受这个答案,我只是想补充一些额外的信息。
如果你想要定时器和闲人之类的东西,你可以考虑一些lke libev http://software.schmorp.de/pkg/libev.html它只是为了在你的应用程序中删除几个源文件(它没有被设置为外部依赖)。您可以将显示的文件描述符添加到事件循环中。
为了跟踪损坏区域,人们经常剪切并粘贴来自X服务器中“机器无关”代码的文件“miregion.c”。只需google for miregion.c或下载X服务器源并查找它。这里的“区域”只是一个矩形列表,它支持诸如并集和交叉之类的操作。要增加伤害,请将它与旧区域结合,修复伤害,减去伤害等等。
答案 1 :(得分:2)
尝试以下内容(未经过实际测试):
while (TRUE) {
if (XPending(display) || !pendingRedraws) {
// if an event is pending, fetch it and process it
// otherwise, we have neither events nor pending redraws, so we can
// safely block on the event queue
XNextEvent (display, &ev);
if (isExposeEvent(&ev)) {
pendingRedraws = TRUE;
}
else {
processEvent(&ev);
}
}
else {
// we must have a pending redraw
redraw();
pendingRedraws = FALSE;
}
}
在进行重绘之前等待10 ms左右可能会有所帮助。不幸的是,原始Xlib没有定时器接口。您需要一个更高级别的工具包(包括Xt在内的所有工具包都有某种定时器接口),或者直接使用X11连接的底层套接字。