In this proposal, I included a behaviour I'd proposed with a previous
diff: when a window is closed pass the focus to the previous one in the
stack.  Now more than before it's necessary to raise that window.  If we
don't, the focused window can end totally obscured behind a bigger one.


Last update:


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    1 Jul 2026 08:53:35 -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    1 Jul 2026 08:53:35 -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,20 @@ 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_raise(prevcc);
+       client_set_active(prevcc);
+       client_flush_enter_events();
 }
 
 void
@@ -336,7 +351,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 +392,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 +425,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 +458,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 +531,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 +962,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 +1030,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 +1057,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    1 Jul 2026 08:53:36 -0000
@@ -154,6 +154,11 @@ kbfunc_client_move_mb(void *ctx, struct 
        struct screen_ctx       *sc = cc->sc;
        struct geom              area;
        int                      move = 1;
+       int                      x, y;
+
+       xu_ptr_get(cc->win, &x, &y);
+       if (!client_inbound(cc, x, y))
+               return;
 
        client_raise(cc);
 
@@ -242,6 +247,11 @@ kbfunc_client_resize_mb(void *ctx, struc
        Time                     ltime = 0;
        struct screen_ctx       *sc = cc->sc;
        int                      resize = 1;
+       int                      x, y;
+
+       xu_ptr_get(cc->win, &x, &y);
+       if (!client_inbound(cc, x, y))
+               return;
 
        if (cc->flags & CLIENT_FREEZE)
                return;
@@ -329,7 +339,7 @@ kbfunc_client_snap(void *ctx, struct car
                }
        }
        client_move(cc);
-       client_ptr_inbound(cc, 1);
+       client_flush_enter_events();
 }
 
 void
@@ -409,7 +419,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 +430,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 +459,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 +555,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    1 Jul 2026 08:53:36 -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   1 Jul 2026 08:53:36 -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

Reply via email to