wmaker: cycle ScreenSwitchKey across Xinerama/RandR heads

ScreenSwitchKey only looped over w_global.screen_count, which stays 1
on a single-screen multi-head display driven by Xinerama or RandR, so
the binding did nothing on such multi-monitor setups.

Treat monitors as the heads of all managed screens in (screen, head)
order and warp the pointer from the head it is on to the next one.
With one head per screen this behaves exactly as before.
This commit is contained in:
David Maciejak
2026-08-19 03:03:01 +01:00
committed by Carlos R. Mafra
parent c7ab42e183
commit 78b58d4418
2 changed files with 58 additions and 22 deletions
-2
View File
@@ -47,8 +47,6 @@ Never: (so, dont even bother to ask)
======
- different themes for each workspace. Unless you give us a SGI/Power Onyx
with 2 CPUs ;).
- anything that requires the mouse pointer to be jumped by WindowMaker to
somewhere. This is *terrible* behaviour. And it's not just IMO.
- rewrite to use Gtk... I wont even bother to explain why...
+58 -20
View File
@@ -1476,6 +1476,63 @@ static void startMarkCapture(WScreen *scr, Display *dpy, WMarkCaptureMode mode)
XGrabKeyboard(dpy, scr->root_win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
}
/*
* Warp pointer to the center of the next monitor, cycling.
*
* Monitors are the Xinerama/RandR heads of every managed screen,
* visited in (screen, head) order starting from the head the pointer
* is on. With one head per screen this reduces to hopping from X11
* screen to X11 screen as before.
*/
static void warpPointerToNextMonitor(WScreen *scr)
{
WMRect rect;
WScreen *target;
int total, current, next;
int i, h;
total = 0;
for (i = 0; i < w_global.screen_count; i++)
total += wXineramaHeads(wScreenWithNumber(i));
if (total <= 1)
return;
/* flat index of the monitor the pointer is currently on */
current = 0;
for (i = 0; i < w_global.screen_count; i++) {
if (wScreenWithNumber(i) == scr) {
h = wGetHeadForPointerLocation(scr);
if (h < 0 || h >= wXineramaHeads(scr))
h = 0;
current += h;
break;
}
current += wXineramaHeads(wScreenWithNumber(i));
}
next = (current + 1) % total;
/* map the flat index back to a (screen, head) pair */
target = NULL;
for (i = 0; i < w_global.screen_count; i++) {
target = wScreenWithNumber(i);
h = wXineramaHeads(target);
if (next < h)
break;
next -= h;
target = NULL;
}
if (!target)
return;
rect = wGetRectForHead(target, next);
XWarpPointer(dpy, None, target->root_win, 0, 0, 0, 0,
rect.pos.x + (int)rect.size.width / 2,
rect.pos.y + (int)rect.size.height / 2);
XFlush(dpy);
}
static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent *event)
{
short widx;
@@ -1898,26 +1955,7 @@ static void dispatchWKBDCommand(int command, WScreen *scr, WWindow *wwin, XEvent
break;
case WKBD_SWITCH_SCREEN:
if (w_global.screen_count > 1) {
WScreen *scr2;
int i;
/* find index of this screen */
for (i = 0; i < w_global.screen_count; i++) {
if (wScreenWithNumber(i) == scr)
break;
}
i++;
if (i >= w_global.screen_count) {
i = 0;
}
scr2 = wScreenWithNumber(i);
if (scr2) {
XWarpPointer(dpy, scr->root_win, scr2->root_win, 0, 0, 0, 0,
scr2->scr_width / 2, scr2->scr_height / 2);
}
}
warpPointerToNextMonitor(scr);
break;
case WKBD_RUN: