如何退出阻止xlib的XNextEvent

Tom*_*ong 26 c x11 user-interface xlib

在windows下,GUI线程通常调用GetMessage来等待消息,当另一个线程使用PoseMessage将消息放入队列时,GUI线程将返回GetMessage(退出阻塞).

有没有人能告诉我,当我在XWindows下使用XNextEvent等待事件时,如何在另一个线程中"唤醒"GUI线程.有没有像我可以使用的PoseMessage这样的API?

Aar*_*lla 43

不.这就是为什么大多数UI框架(Gtk,KDE等)使用自定义主循环来监听更多事件源的原因.

在内部,XNextEvent使用套接字,因此它调用select()以了解输入何时可用.所以你可以:调用ConnectionNumber(display)以获取需要传递的文件描述符select()

这允许您侦听多个文件描述符.

示例代码来自http://www.linuxquestions.org/questions/showthread.php?p=2431345#post2431345

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

Display *dis;
Window win;
int x11_fd;
fd_set in_fds;

struct timeval tv;
XEvent ev;

int main() {
    dis = XOpenDisplay(NULL);
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 256, 256, \
        0, BlackPixel (dis, 0), BlackPixel(dis, 0));

    // You don't need all of these. Make the mask as you normally would.
    XSelectInput(dis, win, 
        ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask |
        ButtonPressMask | ButtonReleaseMask  | StructureNotifyMask 
        );

    XMapWindow(dis, win);
    XFlush(dis);

    // This returns the FD of the X11 display (or something like that)
    x11_fd = ConnectionNumber(dis);

    // Main loop
    while(1) {
        // Create a File Description Set containing x11_fd
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);

        // Set our timer.  One second sounds good.
        tv.tv_usec = 0;
        tv.tv_sec = 1;

        // Wait for X Event or a Timer
        int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
        if (num_ready_fds > 0)
            printf("Event Received!\n");
        else if (num_ready_fds == 0)
            // Handle timer here
            printf("Timer Fired!\n");
        else
            printf("An error occured!\n");

        // Handle XEvents and flush the input 
        while(XPending(dis))
            XNextEvent(dis, &ev);
    }
    return(0);
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*mer 9

您可以通过向自己发送虚拟事件来退出阻止XNextEvent.

Window interClientCommunicationWindow;
Bool x11EventLoopActive = True;

// create a dummy window, that we can use to end the blocking XNextEvent call
interClientCommunicationWindow = XCreateSimpleWindow(dpy, root, 10, 10, 10, 10, 0, 0, 0);
XSelectInput(dpy, interClientCommunicationWindow, StructureNotifyMask);

XEvent event;
while(x11EventLoopActive) {
  XNextEvent(dpy, &event);
  ...
}
Run Code Online (Sandbox Code Playgroud)

在另一个线程中,您可以执行此操作以结束循环:

x11EventLoopActive = False;
// push a dummy event into the queue so that the event loop has a chance to stop
XClientMessageEvent dummyEvent;
memset(&dummyEvent, 0, sizeof(XClientMessageEvent));
dummyEvent.type = ClientMessage;
dummyEvent.window = interClientCommunicationWindow;
dummyEvent.format = 32;
XSendEvent(dpy, interClientCommunicationWindow, 0, 0, (XEvent*)&dummyEvent);
XFlush(dpy);
Run Code Online (Sandbox Code Playgroud)

  • 威尔罗宾逊,危险!Xlib*不是线程安全*!上面的代码看起来很有效,但实际上会以一种非常难以调试的方式随机和偶尔崩溃.不要这样做! (10认同)
  • @DavidGiven如果我们调用`XInitThreads`会怎么样? (2认同)

小智 5

您应该使用: Bool XCheckMaskEvent(Display*, long, XEvent)

XCheckMaskEvent函数首先搜索事件队列,然后搜索与指定掩码匹配的第一个事件的服务器连接上可用的任何事件。

如果找到匹配项,则XCheckMaskEvent删除该事件,将其复制到指定的XEvent结构中,然后返回True。存储在队列中的其他事件不会被丢弃。

如果您请求的事件不可用,则XCheckMaskEvent返回False,并且输出缓冲区将被刷新。