Hello, I sent this patch two months ago but got no response. I send it again just in case. Some kind of response like, "ok, we have seen it but dont want to merge or mess with this", would be nice.
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 here can implement a better solution. 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 Apr 2024 15:26:37 -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 6 Apr 2024 15:26:37 -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,27 @@ 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; + } + 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 +274,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 +293,26 @@ 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); } } - 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 Apr 2024 15:26:37 -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 6 Apr 2024 15:26:37 -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); }