I have a small X11 application which has two threads.
In one thread, I am listening to X11 events using XGrabKey()
and then in a loop XNextEvent()
. The other thread is doing other stuff and is not related to X11.
Here's the code of the relevant thread:
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/XF86keysym.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
volatile bool loop = true;
void keyGrab(void)
{
Display *display = XOpenDisplay(0);
Window root = DefaultRootWindow(display);
int keycode = XKeysymToKeycode(display, XF86XK_AudioPlay);
XGrabKey(display, keycode, AnyModifier, root, False, GrabModeAsync, GrabModeAsync);
XSelectInput(display, root, KeyPressMask);
while (loop) {
XEvent event;
XNextEvent(display, &event);
switch (event.type) {
case KeyPress: puts("Play key pressed"); break;
}
}
XUngrabKey(display, keycode, AnyModifier, root);
XCloseDisplay(display);
}
The goal is that the other thread can tell this thread to stop.
Now the problem is that setting loop = false
in the other thread will of course not terminate this thread, at least not immediately. This thread is stuck in XNextEvent()
because that's a blocking call. So here's my question: What is the standard pattern how to get XNextEvent()
to return?
I guess I need the other Thread to use XSendEvent()
, but I couldn't find any hints on how to do that. I wouldn't even know which message type would be appropriate. Would it be ClientMessage
? Something else? I actually tried sending a ClientMessage
from the other thread, but I got the following error message:
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 25 (X_SendEvent)
Value in failed request: 0x0
Serial number of failed request: 12
Current serial number in output stream: 12
Here's the relevant code snippet from the other thread that I tried and triggered the error (display
and root
are initialized by the first thread):
XEvent event;
memset(&event, 0, sizeof(event));
event.type = ClientMessage;
XSendEvent(display, root, False, 0, &event);
Note that the other thread doesn't need any X11 code by itself. The only purpose why the other thread would use X11 is to tell this thread to terminate.
Please keep in mind that there is no window in context. The root window of course does not count, as this is only for globally catching keys. So, destroying the window is not a solution.