Harden DWM plugins against X11 stacking/keyboard grab races and speed up QMI status

This commit is contained in:
Luxferre
2026-10-25 14:14:21 +02:00
parent b2216c186f
commit e77be498bf
44 changed files with 432 additions and 211 deletions
+63 -6
View File
@@ -475,19 +475,21 @@ grabfocus(void)
static void
grabkeyboard(void)
{
struct timespec ts = { .tv_sec = 0, .tv_nsec = 2000000 };
struct timespec ts = { .tv_sec = 0, .tv_nsec = 3000000 };
Window grabwin;
int i;
if (embed || managed)
return;
grabwin = daemon_mode ? win : DefaultRootWindow(dpy);
for (i = 0; i < 25; i++) {
for (i = 0; i < 40; i++) {
if (XGrabKeyboard(dpy, grabwin, True, GrabModeAsync,
GrabModeAsync, CurrentTime) == GrabSuccess)
return;
break;
nanosleep(&ts, NULL);
}
if (win)
XSetInputFocus(dpy, win, RevertToPointerRoot, CurrentTime);
}
static void
@@ -2385,6 +2387,46 @@ open_builtin_menu(const char *menu_name, int keep_idx)
show_menu();
}
static int
any_other_plugin_active(void)
{
static const char *pid_files[] = {
"xdrawer.pid",
"xdialer.pid",
"xcalllog.pid",
"xcallscreen.pid",
"xcontacts.pid",
"xsms.pid",
"xfiles.pid",
"xcamera.pid",
"xthemes.pid",
"xmodem.pid",
"xnetworks.pid",
"xringtones.pid",
"xwallpapers.pid",
};
const char *rdir = getenv("XDG_RUNTIME_DIR");
const char *base = (rdir && rdir[0]) ? rdir : "/run/user/10000";
for (size_t i = 0; i < LENGTH(pid_files); i++) {
char ppath[256];
snprintf(ppath, sizeof(ppath), "%s/%s", base, pid_files[i]);
if (access(ppath, F_OK) != 0)
snprintf(ppath, sizeof(ppath), "/tmp/%s", pid_files[i]);
if (access(ppath, F_OK) == 0) {
FILE *pf = fopen(ppath, "r");
if (pf) {
int pid = -1;
if (fscanf(pf, "%d", &pid) == 1 && pid > 0 && kill(pid, 0) == 0) {
fclose(pf);
return 1;
}
fclose(pf);
}
}
}
return 0;
}
static void
close_other_active_plugins(void)
{
@@ -2639,6 +2681,8 @@ show_menu(void)
soft_deadline = 0;
if (!menu_active) {
menu_active = 1;
mark_menu_active(1);
close_other_active_plugins();
prevfocuswin = None;
Window fw = None;
@@ -2654,8 +2698,6 @@ show_menu(void)
read_softkey_state(&init_soft_mask, &init_soft_ms);
start_ignore = dmenu_now_ms() + 180;
initial_released = (query_trigger_keys_down() == 0);
menu_active = 1;
mark_menu_active(1);
drawmenu();
XMapRaised(dpy, win);
drawmenu();
@@ -2666,11 +2708,13 @@ show_menu(void)
XSetICFocus(xic);
XFlush(dpy);
} else {
close_other_active_plugins();
init_soft_mask = 0;
init_soft_ms = 0;
start_ignore = dmenu_now_ms() + 60;
initial_released = (query_trigger_keys_down() == 0);
XRaiseWindow(dpy, win);
grabkeyboard();
drawmenu();
if (xic && engage_ime)
XSetICFocus(xic);
@@ -2975,6 +3019,19 @@ process_x11_events(void)
if (ev.xexpose.count == 0 && (menu_active || !daemon_mode))
drw_map(drw, win, 0, 0, mw, mh);
break;
case VisibilityNotify:
if (ev.xvisibility.state != VisibilityUnobscured &&
(menu_active || !daemon_mode)) {
if (any_other_plugin_active()) {
if (daemon_mode)
cancel_session();
} else {
XRaiseWindow(dpy, win);
grabkeyboard();
drw_map(drw, win, 0, 0, mw, mh);
}
}
break;
case FocusIn:
if (menu_active || !daemon_mode) {
if (!daemon_mode && ev.xfocus.window != win)
@@ -3186,7 +3243,7 @@ setup(int map_immediately)
swa.override_redirect = managed ? False : True;
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask;
swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | VisibilityChangeMask;
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);