A final tweak. When you restart cwm the focus still automatically goes
to the window under the pointer. In the update below I modified
screen_scan() to first check _NET_ACTIVE_WINDOW.
Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
diff -u -p -u -p -r1.380 calmwm.h
--- calmwm.h 20 Aug 2025 23:44:06 -0000 1.380
+++ calmwm.h 30 Jun 2026 09:37:13 -0000
@@ -405,6 +405,7 @@ void client_config(struct
client_ctx
struct client_ctx *client_current(struct screen_ctx *);
void client_draw_border(struct client_ctx *);
struct client_ctx *client_find(Window);
+void client_flush_enter_events(void);
void client_get_sizehints(struct client_ctx *);
void client_hide(struct client_ctx *);
void client_htile(struct client_ctx *);
Index: client.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/client.c,v
diff -u -p -u -p -r1.267 client.c
--- client.c 22 Mar 2023 08:27:36 -0000 1.267
+++ client.c 30 Jun 2026 09:37:13 -0000
@@ -210,6 +210,7 @@ client_remove(struct client_ctx *cc)
{
struct screen_ctx *sc = cc->sc;
struct winname *wn;
+ struct client_ctx *prevcc;
TAILQ_REMOVE(&sc->clientq, cc, entry);
@@ -230,6 +231,19 @@ client_remove(struct client_ctx *cc)
free(cc->res_class);
free(cc->res_name);
free(cc);
+
+ if (TAILQ_EMPTY(&sc->clientq))
+ return;
+
+ prevcc = TAILQ_FIRST(&sc->clientq);
+
+ /* Avoid windows with skip client flag or from other groups */
+ if ((prevcc->flags & (CLIENT_SKIP_CYCLE)) &&
+ ! (prevcc->flags & CWM_CYCLE_INGROUP))
+ return;
+
+ client_set_active(prevcc);
+ client_flush_enter_events();
}
void
@@ -336,7 +350,7 @@ client_toggle_fullscreen(struct client_c
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
- client_ptr_inbound(cc, 1);
+ client_flush_enter_events();
}
void
@@ -377,7 +391,7 @@ client_toggle_maximize(struct client_ctx
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
- client_ptr_inbound(cc, 1);
+ client_flush_enter_events();
}
void
@@ -410,7 +424,7 @@ client_toggle_vmaximize(struct client_ct
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
- client_ptr_inbound(cc, 1);
+ client_flush_enter_events();
}
void
@@ -443,7 +457,7 @@ client_toggle_hmaximize(struct client_ct
resize:
client_resize(cc, 0);
xu_ewmh_set_net_wm_state(cc);
- client_ptr_inbound(cc, 1);
+ client_flush_enter_events();
}
void
@@ -516,8 +530,6 @@ client_ptr_inbound(struct client_ctx *cc
cc->ptr.y = 0;
else if (cc->ptr.y > cc->geom.h - 1)
cc->ptr.y = cc->geom.h - 1;
-
- client_ptr_warp(cc);
}
void
@@ -949,7 +961,6 @@ client_htile(struct client_ctx *cc)
if (Conf.htile > 0)
cc->geom.h = ((area.h - (cc->bwidth * 2)) * Conf.htile) / 100;
client_resize(cc, 1);
- client_ptr_warp(cc);
mh = cc->geom.h + (cc->bwidth * 2);
x = area.x;
@@ -1018,7 +1029,6 @@ client_vtile(struct client_ctx *cc)
cc->geom.w = ((area.w - (cc->bwidth * 2)) * Conf.vtile) / 100;
cc->geom.h = area.h - (cc->bwidth * 2);
client_resize(cc, 1);
- client_ptr_warp(cc);
mw = cc->geom.w + (cc->bwidth * 2);
y = area.y;
@@ -1046,4 +1056,14 @@ client_vtile(struct client_ctx *cc)
i++;
client_resize(ci, 1);
}
+}
+
+void
+client_flush_enter_events(void)
+{
+ XEvent ev;
+
+ XSync(X_Dpy, False);
+ while (XCheckMaskEvent(X_Dpy, EnterWindowMask, &ev))
+ LOG_DEBUG3("Discarding stale EnterNotify event");
}
Index: kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
diff -u -p -u -p -r1.176 kbfunc.c
--- kbfunc.c 20 Aug 2025 23:44:06 -0000 1.176
+++ kbfunc.c 30 Jun 2026 09:37:13 -0000
@@ -409,7 +409,7 @@ void
kbfunc_client_cycle(void *ctx, struct cargs *cargs)
{
struct screen_ctx *sc = ctx;
- struct client_ctx *newcc, *oldcc, *prevcc;
+ struct client_ctx *newcc, *oldcc;
int again = 1, flags = cargs->flag;
/* For X apps that ignore/steal events. */
@@ -420,7 +420,6 @@ kbfunc_client_cycle(void *ctx, struct ca
if (TAILQ_EMPTY(&sc->clientq))
return;
- prevcc = TAILQ_FIRST(&sc->clientq);
oldcc = client_current(sc);
if (oldcc == NULL)
oldcc = (flags & CWM_CYCLE_REVERSE) ?
@@ -450,24 +449,17 @@ kbfunc_client_cycle(void *ctx, struct ca
}
}
- /* Reset when cycling mod is released. XXX I hate this hack */
+ /* Reset when cycling mod is released */
sc->cycling = 1;
- client_ptr_save(oldcc);
- client_raise(prevcc);
- client_raise(newcc);
- if (!client_inbound(newcc, newcc->ptr.x, newcc->ptr.y)) {
- newcc->ptr.x = newcc->geom.w / 2;
- newcc->ptr.y = newcc->geom.h / 2;
- }
- /* When no client is active, warp pointer to last active. */
- if (oldcc->flags & (CLIENT_ACTIVE))
- client_ptr_warp(newcc);
- else if (oldcc->flags & (CLIENT_SKIP_CYCLE))
- client_ptr_warp(newcc);
- else {
+ /* When no client is active, activate last active. */
+ if (oldcc->flags & (CLIENT_ACTIVE) ||
+ oldcc->flags & (CLIENT_SKIP_CYCLE)) {
+ client_raise(newcc);
+ client_set_active(newcc);
+ } else {
client_raise(oldcc);
- client_ptr_warp(oldcc);
+ client_set_active(oldcc);
}
}
@@ -553,7 +545,7 @@ kbfunc_menu_client(void *ctx, struct car
client_show(cc);
if ((old_cc = client_current(sc)) != NULL)
client_ptr_save(old_cc);
- client_ptr_warp(cc);
+ client_set_active(cc);
}
menuq_clear(&menuq);
Index: screen.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/screen.c,v
diff -u -p -u -p -r1.98 screen.c
--- screen.c 27 Jan 2022 18:45:10 -0000 1.98
+++ screen.c 30 Jun 2026 09:37:13 -0000
@@ -87,22 +87,52 @@ screen_init(int which)
static void
screen_scan(struct screen_ctx *sc)
{
- struct client_ctx *cc, *active = NULL;
- Window *wins, w0, w1, rwin, cwin;
- unsigned int nwins, i, mask;
- int rx, ry, wx, wy;
+ struct client_ctx *active = NULL, *cc;
+ Atom actual_type;
+ Atom net_active_win;
+ int actual_format, rx, ry, wx, wy;
+ unsigned int i, mask, nwins;
+ unsigned long bytes_after, nitems;
+ unsigned char *prop_return = NULL;
+ Window *wins, cwin, ewmh_active_win = None;
+ Window rwin, w0, w1;
+ /* Try to get the window active before the restart via EWMH */
+ net_active_win = XInternAtom(X_Dpy, "_NET_ACTIVE_WINDOW", False);
+
+ if (XGetWindowProperty(X_Dpy, sc->rootwin, net_active_win, 0, 1,
+ False, XA_WINDOW, &actual_type, &actual_format, &nitems,
+ &bytes_after, &prop_return) == Success && prop_return != NULL) {
+ if (nitems > 0)
+ ewmh_active_win = *(Window *)prop_return;
+ XFree(prop_return);
+ }
+
+ /* Query the current pointer position as a fallback */
XQueryPointer(X_Dpy, sc->rootwin, &rwin, &cwin,
&rx, &ry, &wx, &wy, &mask);
+ /* Scan the window tree and initialize clients */
if (XQueryTree(X_Dpy, sc->rootwin, &w0, &w1, &wins, &nwins)) {
for (i = 0; i < nwins; i++) {
- if ((cc = client_init(wins[i], sc)) != NULL)
- if (cc->win == cwin)
- active = cc;
+ if ((cc = client_init(wins[i], sc)) != NULL) {
+ /*
+ * If EWMH told us which window was active,
+ * match against that. Otherwise, fall back
+ * to the window under the pointer.
+ */
+ if (ewmh_active_win != None) {
+ if (cc->win == ewmh_active_win)
+ active = cc;
+ } else {
+ if (cc->win == cwin)
+ active = cc;
+ }
+ }
}
XFree(wins);
}
+
if (active)
client_set_active(active);
}
Index: xevents.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/xevents.c,v
diff -u -p -u -p -r1.151 xevents.c
--- xevents.c 5 Jan 2026 14:46:59 -0000 1.151
+++ xevents.c 30 Jun 2026 09:37:13 -0000
@@ -93,7 +93,7 @@ xev_handle_maprequest(XEvent *ee)
cc = client_init(e->window, NULL);
if ((cc != NULL) && (!(cc->flags & CLIENT_IGNORE)))
- client_ptr_warp(cc);
+ client_set_active(cc);
}
static void
@@ -330,8 +330,8 @@ xev_handle_keypress(XEvent *ee)
kb->cargs->xev = CWM_XEV_KEY;
switch (kb->context) {
case CWM_CONTEXT_CC:
- if (((cc = client_find(e->subwindow)) == NULL) &&
- ((cc = client_current(sc)) == NULL))
+ if (((cc = client_current(sc)) == NULL) &&
+ ((cc = client_find(e->subwindow)) == NULL))
return;
(*kb->callback)(cc, kb->cargs);
break;
@@ -404,7 +404,6 @@ xev_handle_clientmessage(XEvent *ee)
if ((old_cc = client_current(NULL)) != NULL)
client_ptr_save(old_cc);
client_show(cc);
- client_ptr_warp(cc);
}
} else if (e->message_type == ewmh[_NET_WM_DESKTOP]) {
if ((cc = client_find(e->window)) != NULL) {
--
Walter