web-dev-qa-db-ja.com

xlibのXNextEventのブロックを終了する方法

Windowsでは、GUIスレッドは通常GetMessageを呼び出してメッセージを待機します。別のスレッドがPoseMessageを使用してメッセージをキューに入れると、GUIスレッドはGetMessageを返します(ブロックを終了します)。

XWindowsでXNextEventを使用してイベントを待機しているときに、別のスレッドでGUIスレッドを「ウェイクアップ」するにはどうすればよいですか。使用できるPoseMessageのようなAPIはありますか?.

27
Tom Wong

いいえ。これが、ほとんどの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);
}
43
Aaron Digulla

ダミーイベントを自分に送信することで、ブロックしている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);
9
Markus Kramer

使用する必要があります:Bool XCheckMaskEvent(Display *、long、XEvent)

XCheckMaskEvent関数は、最初にイベントキューを検索し、次にサーバー接続で使用可能なすべてのイベントで、指定されたマスクに一致する最初のイベントを検索します。

一致するものが見つかった場合、XCheckMaskEventはそのイベントを削除し、指定されたXEvent構造体にコピーして、Trueを返します。キューに保存されている他のイベントは破棄されません。

要求したイベントが利用できない場合、XCheckMaskEventFalseを返し、出力バッファーはフラッシュされます。

4
Kevin Mille