X:以固定间隔触发事件

时间:2013-06-23 15:17:07

标签: c opengl x11 glx

在X上等待一段时间的暴露事件的最佳方式是什么,然后唤醒并重新绘制,即使没有接收到暴露事件?目的是让opengl动画有时在其他地方运行,我只想在需要时重绘。这是我现在的代码,请查看下面我正在寻找的伪代码:

    do {
        XNextEvent(dpy, &event);
        switch(event.type) {
            ...
            case Expose:
               need_redraw = True;
               break;
        }
    } while(XPending(dpy)); /* loop to compress events */

    if ( need_redraw )
    {
        // do redraw
    } 

这是我想要的一个伪示例:

    bool animation_enabled = true;
    XPostTimeoutEventEvery( 0.3 ); // <-- X will send a "Timeout"
                                   // event each 0.3 seconds.

    do {
        XNextEvent(dpy, &event);
        switch(event.type) {
            ...
            case Expose:
               // Redraw if it is required
               need_redraw = True;
               break;
            // -- here -- 
            case Timeout:
               // Otherwise, after 0.3 seconds, redraw anyway if
               // the animation is running
               if ( animation_enabled )
               {
                  need_redraw = True;
               }
               break;


        }
    } while(XPending(dpy)); /* loop to compress events */

    if ( need_redraw )
    {
        // do redraw

        // potentially change "animation_enabled" value 
    } 

3 个答案:

答案 0 :(得分:3)

只需使用常规系统计时器;如果期望的事件没有及时到达,只要做你想做的事。

X不是应用程序框架,它是一种显示协议。定时器在X11的范围之外。

检查here和该答案中提供的link

答案 1 :(得分:1)

更简单的解决方案是使用XNextEvent的非阻塞Xlib等效项。这是我每次通过帧循环检查X事件时使用的内容:

mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask;
while (XCheckWindowEvent(xDisplay, xWin, mask, &evt) ||
       XCheckTypedWindowEvent(xDisplay, xWin, ClientMessage, &evt)) {
       /* Handle event */
}

希望这会有所帮助。完整的代码在我的演示OpenGL / GLX程序

http://cs.anu.edu.au/~Hugh.Fisher/3dteach/glxcube.tar

答案 2 :(得分:1)

XLib不提供XNextEvent的“超时”版本。 但是,可以轻松实现超时版本。

你需要一个功能 检查文件是否已更新 在给定的超时内, 您可以使用select实现它:

#include <sys/select.h>

static int wait_fd(int fd, double seconds)
{
    struct timeval tv;
    fd_set in_fds;
    FD_ZERO(&in_fds);
    FD_SET(fd, &in_fds);
    tv.tv_sec = trunc(seconds);
    tv.tv_usec = (seconds - trunc(seconds))*1000000;
    return select(fd+1, &in_fds, 0, 0, &tv);
}

然后,您可以使用wait_fd 在返回的文件描述符中 ConnectionNumber(display) 等待一个事件 在给定的时间限制内:

int XNextEventTimeout(Display *display, XEvent *event, double seconds)
{
    if (XPending(display) || wait_fd(ConnectionNumber(display),seconds)) {
        XNextEvent(display, event);
        return 0;
    } else {
        return 1;
    }
}

在你的主循环中, 您可以使用XNextEventTimeout功能 等待给定超时内的事件。 如果超时到期,您可以模拟所需的事件, 在你的情况下Expose事件:

for (;;) {
    if (XNextEventTimeout(dpy, &event, 1.)) {
        /* Handle timeout "event"
         * one option is to simulate an Expose event */
        e.type = Expose;
        e.xexpose.count = 0;
    }
    switch (event.type) {
        case Expose:
            /* Handle expose event */
            break;

        /* ... */
        /* Handle other events */
    }
}