2

在 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 
    } 
4

3 回答 3

3

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

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

检查此处以及该答案中提供的链接。

于 2013-06-23T18:15:37.797 回答
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

于 2013-06-24T22:56:15.410 回答
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 */
    }
}
于 2015-09-13T15:15:48.817 回答