In my patch there were some issues with unhandled events. I upload
here a hopefully better patch. Not pretty but fixes the issues.

New patch:

Index: calmwm.h
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
retrieving revision 1.379
diff -u -p -r1.379 calmwm.h
--- calmwm.h    20 Jul 2023 14:39:34 -0000      1.379
+++ calmwm.h    7 Feb 2024 20:25:12 -0000
@@ -481,7 +481,7 @@ struct geom          screen_area(struct screen_
 struct screen_ctx      *screen_find(Window);
 void                    screen_init(int);
 void                    screen_prop_win_create(struct screen_ctx *, Window);
-void                    screen_prop_win_destroy(struct screen_ctx *);
+void                    screen_prop_win_destroy(struct screen_ctx *, int);
 void                    screen_prop_win_draw(struct screen_ctx *,
                             const char *, ...)
                            __attribute__((__format__ (printf, 2, 3)))
@@ -558,6 +558,7 @@ void                         conf_screen(struct screen_ctx 
*)
 void                    conf_group(struct screen_ctx *);
 
 void                    xev_process(void);
+void                    xev_process_ev(XEvent *);
 
 int                     xu_get_prop(Window, Atom, Atom, long, unsigned char 
**);
 int                     xu_get_strprop(Window, Atom, char **);
Index: kbfunc.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
retrieving revision 1.174
diff -u -p -r1.174 kbfunc.c
--- kbfunc.c    20 Jul 2023 14:39:34 -0000      1.174
+++ kbfunc.c    7 Feb 2024 20:25:12 -0000
@@ -169,8 +169,8 @@ kbfunc_client_move_mb(void *ctx, struct 
 
        screen_prop_win_create(sc, cc->win);
        screen_prop_win_draw(sc, "%+5d%+5d", cc->geom.x, cc->geom.y);
-       while (move) {
-               XMaskEvent(X_Dpy, MOUSEMASK, &ev);
+       while (move > 0) {
+               XMaskEvent(X_Dpy, MOUSEMASK | SubstructureNotifyMask, &ev);
                switch (ev.type) {
                case MotionNotify:
                        /* not more than 60 times / second */
@@ -197,11 +197,28 @@ kbfunc_client_move_mb(void *ctx, struct 
                case ButtonRelease:
                        move = 0;
                        break;
+               /* check for destroy events, in case the client window
+                * gets destroyed, which forcefully closes the prop window.
+                */
+               case DestroyNotify:
+                       /* set move to -1 to specify abrupt exit */
+                       if (ev.xdestroywindow.window == cc->win) {
+                               screen_prop_win_destroy(sc, 1);
+                               move = -1; 
+                       } else if (ev.xdestroywindow.window == sc->prop.win) {
+                               screen_prop_win_destroy(sc, 0);
+                               move = -1; 
+                       }
+                       xev_process_ev(&ev);
+               default: /* process event anyway */
+                       xev_process_ev(&ev);
                }
        }
-       if (ltime)
-               client_move(cc);
-       screen_prop_win_destroy(sc);
+       if (move != -1) {
+               if (ltime)
+                       client_move(cc);
+               screen_prop_win_destroy(sc, 1);
+       }
        XUngrabPointer(X_Dpy, CurrentTime);
 }
 
@@ -258,7 +275,7 @@ kbfunc_client_resize_mb(void *ctx, struc
 
        screen_prop_win_create(sc, cc->win);
        screen_prop_win_draw(sc, "%4d x %-4d", cc->dim.w, cc->dim.h);
-       while (resize) {
+       while (resize > 0) {
                XMaskEvent(X_Dpy, MOUSEMASK, &ev);
                switch (ev.type) {
                case MotionNotify:
@@ -277,11 +294,27 @@ kbfunc_client_resize_mb(void *ctx, struc
                case ButtonRelease:
                        resize = 0;
                        break;
+               /* check for destroy events, in case the client window
+                * gets destroyed, which forcefully closes the prop window.
+                */
+               case DestroyNotify:
+                       if (ev.xdestroywindow.window == cc->win) {
+                               screen_prop_win_destroy(sc, 1);
+                               resize = -1; 
+                       } else if (ev.xdestroywindow.window == sc->prop.win) {
+                               screen_prop_win_destroy(sc, 0);
+                               resize = -1; 
+                       }
+               default: /* process event anyway */
+                       xev_process_ev(&ev);
+                       break;
                }
        }
-       if (ltime)
-               client_resize(cc, 1);
-       screen_prop_win_destroy(sc);
+       if (resize != -1) {
+               if (ltime)
+                       client_resize(cc, 1);
+               screen_prop_win_destroy(sc, 1);
+       }
        XUngrabPointer(X_Dpy, CurrentTime);
 
        /* Make sure the pointer stays within the window. */
Index: screen.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/screen.c,v
retrieving revision 1.98
diff -u -p -r1.98 screen.c
--- screen.c    27 Jan 2022 18:45:10 -0000      1.98
+++ screen.c    7 Feb 2024 20:25:12 -0000
@@ -278,10 +278,15 @@ screen_prop_win_create(struct screen_ctx
 }
 
 void
-screen_prop_win_destroy(struct screen_ctx *sc)
+screen_prop_win_destroy(struct screen_ctx *sc, int destroy_window)
 {
        XftDrawDestroy(sc->prop.xftdraw);
-       XDestroyWindow(X_Dpy, sc->prop.win);
+       /*
+        * In case the window was already destroyed
+        * (i.e. DestroyNotify event)
+        */
+       if (destroy_window)
+               XDestroyWindow(X_Dpy, sc->prop.win);
 }
 
 void
Index: xevents.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/xevents.c,v
retrieving revision 1.150
diff -u -p -r1.150 xevents.c
--- xevents.c   24 Mar 2020 14:47:29 -0000      1.150
+++ xevents.c   7 Feb 2024 20:25:12 -0000
@@ -485,9 +485,15 @@ xev_process(void)
 
        while (XPending(X_Dpy)) {
                XNextEvent(X_Dpy, &e);
-               if ((e.type - Conf.xrandr_event_base) == RRScreenChangeNotify)
-                       xev_handle_randr(&e);
-               else if ((e.type < LASTEvent) && (xev_handlers[e.type] != NULL))
-                       (*xev_handlers[e.type])(&e);
+               xev_process_ev(&e);
        }
+}
+
+void
+xev_process_ev(XEvent *ev)
+{
+       if ((ev->type - Conf.xrandr_event_base) == RRScreenChangeNotify)
+               xev_handle_randr(ev);
+       else if ((ev->type < LASTEvent) && (xev_handlers[ev->type] != NULL))
+               (*xev_handlers[ev->type])(ev);
 }

On Tuesday, February 6th, 2024 at 10:14 PM, ZenitDS <zeni...@proton.me> wrote:

> Hello,
> 
> This is my first time posting here so please forgive me if
> something is not correct.
> 
> When running cwm you can destroy the client window while
> you are moving or resizing it, leading to crash of the WM
> when the prop window is accessed (the one at the top-left that
> indicates the position/scale).
> 
> I include a demonstration for the crash and also a patch that
> fixes it. Hopefully someone with more experience can implement
> a better fix.
> 
> Also, should this go into the tech mailing list instead of misc?
> 
> Demonstration code for the crash:
> 
> #include <X11/Xlib.h>
> 
> 
> #include <err.h>
> 
> #include <unistd.h>
> 
> 
> int
> main(void)
> {
> Display *dpy;
> Window win;
> int scr;
> XEvent ev;
> 
> dpy = XOpenDisplay(NULL);
> if (!dpy)
> err(1, "XOpenDisplay");
> 
> scr = DefaultScreen(dpy);
> 
> win = XCreateSimpleWindow(dpy, RootWindow(dpy, scr), 0, 0, 500, 500, 0, 0, 
> WhitePixel(dpy, scr));
> if (!win)
> err(1, "XCreateSimpleWindow");
> 
> XSelectInput(dpy, win, StructureNotifyMask | SubstructureNotifyMask | 
> ExposureMask);
> XMapRaised(dpy, win);
> 
> while (1) {
> XNextEvent(dpy, &ev);
> switch (ev.type) {
> case CreateNotify:
> goto end;
> case Expose:
> XClearWindow(dpy, win);
> break;
> default:
> break;
> }
> }
> end:
> XDestroyWindow(dpy, win);
> 
> XCloseDisplay(dpy);
> 
> return 0;
> }
> 
> Here is the patch:
> 
> Index: calmwm.h
> ===================================================================
> RCS file: /cvs/xenocara/app/cwm/calmwm.h,v
> retrieving revision 1.379
> diff -u -p -r1.379 calmwm.h
> --- calmwm.h 20 Jul 2023 14:39:34 -0000 1.379
> +++ calmwm.h 6 Feb 2024 20:20:22 -0000
> @@ -481,7 +481,7 @@ struct geom screen_area(struct screen_
> struct screen_ctx *screen_find(Window);
> void screen_init(int);
> void screen_prop_win_create(struct screen_ctx *, Window);
> -void screen_prop_win_destroy(struct screen_ctx *);
> +void screen_prop_win_destroy(struct screen_ctx *, int);
> void screen_prop_win_draw(struct screen_ctx *,
> const char *, ...)
> attribute((format (printf, 2, 3)))
> Index: kbfunc.c
> ===================================================================
> RCS file: /cvs/xenocara/app/cwm/kbfunc.c,v
> retrieving revision 1.174
> diff -u -p -r1.174 kbfunc.c
> --- kbfunc.c 20 Jul 2023 14:39:34 -0000 1.174
> +++ kbfunc.c 6 Feb 2024 20:20:22 -0000
> @@ -169,9 +169,23 @@ kbfunc_client_move_mb(void *ctx, struct
> 
> screen_prop_win_create(sc, cc->win);
> 
> screen_prop_win_draw(sc, "%+5d%+5d", cc->geom.x, cc->geom.y);
> 
> - while (move) {
> - XMaskEvent(X_Dpy, MOUSEMASK, &ev);
> + while (move > 0) {
> 
> + XMaskEvent(X_Dpy, MOUSEMASK | SubstructureNotifyMask, &ev);
> switch (ev.type) {
> + /* check for destroy events, in case the client window
> + * gets destroyed, which forcefully closes the prop window.
> + /
> + case DestroyNotify:
> + / set move to -1 to specify abrupt exit */
> + if (ev.xdestroywindow.window == cc->win) {
> 
> + screen_prop_win_destroy(sc, 1);
> + client_remove(cc);
> + move = -1;
> + } else if (ev.xdestroywindow.window == sc->prop.win) {
> 
> + screen_prop_win_destroy(sc, 0);
> + move = -1;
> + }
> + break;
> case MotionNotify:
> /* not more than 60 times / second */
> if ((ev.xmotion.time - ltime) <= (1000 / 60))
> @@ -199,9 +213,11 @@ kbfunc_client_move_mb(void *ctx, struct
> break;
> }
> }
> - if (ltime)
> - client_move(cc);
> - screen_prop_win_destroy(sc);
> + if (move != -1) {
> + if (ltime)
> + client_move(cc);
> + screen_prop_win_destroy(sc, 1);
> + }
> XUngrabPointer(X_Dpy, CurrentTime);
> }
> 
> @@ -258,9 +274,22 @@ kbfunc_client_resize_mb(void *ctx, struc
> 
> screen_prop_win_create(sc, cc->win);
> 
> screen_prop_win_draw(sc, "%4d x %-4d", cc->dim.w, cc->dim.h);
> 
> - while (resize) {
> + while (resize > 0) {
> 
> XMaskEvent(X_Dpy, MOUSEMASK, &ev);
> switch (ev.type) {
> + /* check for destroy events, in case the client window
> + * gets destroyed, which forcefully closes the prop window.
> + */
> + case DestroyNotify:
> + if (ev.xdestroywindow.window == cc->win) {
> 
> + screen_prop_win_destroy(sc, 1);
> + client_remove(cc);
> + resize = -1;
> + } else if (ev.xdestroywindow.window == sc->prop.win) {
> 
> + screen_prop_win_destroy(sc, 0);
> + resize = -1;
> + }
> + break;
> case MotionNotify:
> /* not more than 60 times / second */
> if ((ev.xmotion.time - ltime) <= (1000 / 60))
> @@ -279,9 +308,11 @@ kbfunc_client_resize_mb(void ctx, struc
> break;
> }
> }
> - if (ltime)
> - client_resize(cc, 1);
> - screen_prop_win_destroy(sc);
> + if (resize != -1) {
> + if (ltime)
> + client_resize(cc, 1);
> + screen_prop_win_destroy(sc, 1);
> + }
> XUngrabPointer(X_Dpy, CurrentTime);
> 
> / Make sure the pointer stays within the window. */
> Index: screen.c
> ===================================================================
> RCS file: /cvs/xenocara/app/cwm/screen.c,v
> retrieving revision 1.98
> diff -u -p -r1.98 screen.c
> --- screen.c 27 Jan 2022 18:45:10 -0000 1.98
> +++ screen.c 6 Feb 2024 20:20:22 -0000
> @@ -278,10 +278,15 @@ screen_prop_win_create(struct screen_ctx
> }
> 
> void
> -screen_prop_win_destroy(struct screen_ctx *sc)
> +screen_prop_win_destroy(struct screen_ctx *sc, int destroy_window)
> {
> XftDrawDestroy(sc->prop.xftdraw);
> 
> - XDestroyWindow(X_Dpy, sc->prop.win);
> 
> + /*
> + * In case the window was already destroyed
> + * (i.e. DestroyNotify event)
> + */
> + if (destroy_window)
> + XDestroyWindow(X_Dpy, sc->prop.win);
> 
> }
> 
> void

Reply via email to