'Non blocking event handling in X11 without swallowing event
Sorry for the poor title, it wasn't easy to describe it better. I am learning C and as a toy project I am building a simple status bar for my window manager. Basically it just outputs text to the root X11 window name, which gets picked up by the wm (DWM).
Now I wanted to add simple click detected, so that I can do something when a specific area is clicked. The polling of the mouse happens in a while loop; and the update of the status bar also lives in the while loop, but with a different (less frequent) interval. Everything works, except that no other X11 applications are receiving the mouse clicks I listen to in my while loop.
I used XNextEvent first but found out that was blocking the while loop if the mouse was idle. Then I learned about XCheckWindowEvent which returns a boolean if the event I want to poll matches, then I can handle it. But the loop will not pause when the mouse is idle (which is most of the time).
However since doing so, whenever I move the mouse, I cannot click on any other window anymore. The cursor moves just fine, but clicks do not seem to work.
Am I making any sense?
This is the listing of my program (slightly simplified as for the status setting part, since that probably will distract).
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h>
#include <unistd.h>
#include <fcntl.h>
#include <X11/Xlib.h>
#define EVTMASK (ButtonPressMask | PointerMotionMask)
void set_status(Display *display, Window window, char *str);
void process_mouse(Display *display, Window window, XEvent xevent);
char *key_name[] = {
"first",
"second (or middle)",
"third"
};
int
main(void)
{
const int MSIZE = 1024;
Display *display;
XEvent xevent;
Window window;
char *status;
char *bg_color = "#000000";
char *clr_yellow = "#ecbe7b";
time_t previousTime = time(NULL);
time_t interval_status = 1;
time_t currentTime;
if (!(display = XOpenDisplay(NULL))) {
fprintf(stderr, "Cannot open display.\n");
return EXIT_FAILURE;
}
// Setup X11 for mouse grabbing
window = DefaultRootWindow(display);
XAllowEvents(display, AsyncBoth, CurrentTime);
XGrabPointer(display,
window,
1,
PointerMotionMask | ButtonPressMask | ButtonReleaseMask ,
GrabModeAsync,
GrabModeAsync,
None,
None,
CurrentTime);
status = (char*) malloc(sizeof(char)*MSIZE);
if(!status)
return EXIT_FAILURE;
while(1)
{
process_mouse(display, window, xevent);
if((time(¤tTime) - previousTime) >= interval_status)
{
int ret = snprintf(status, MSIZE, "^b%s^^c%s^%s Status me!", bg_color, clr_yellow);
set_status(display, window, status);
previousTime += interval_status;
}
}
return 0;
}
void
set_status(Display *display, Window window, char *str)
{
XStoreName(display, window, str);
XSync(display, False);
}
void
process_mouse(Display *display, Window window, XEvent xevent)
{
if(XCheckWindowEvent(display, window, EVTMASK, &xevent)) {
switch (xevent.type) {
case MotionNotify:
printf("Mouse move : [%d, %d]\n", xevent.xmotion.x_root, xevent.xmotion.y_root);
break;
case ButtonPress:
printf("Button pressed : %s\n", key_name[xevent.xbutton.button - 1]);
break;
case ButtonRelease:
printf("Button released : %s\n", key_name[xevent.xbutton.button - 1]);
break;
}
XPutBackEvent(display, &xevent);
}
}
Open question: should I go back to the NextEvent method and listen to the mouse on a different thread?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
