如何退出阻止xlib的XNextEvent

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

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

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

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

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

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

 #include  #include  #include  #include  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); } 

您可以通过向自己发送虚拟事件来退出阻止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); ... } 

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

 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); 

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

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

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

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