On Sat 2024.04.06 at 15:40 +0000, ZenitDS wrote:
> 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.

Hi - I saw this and was at first confused.

> 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.

Looking again, I'm still confused as to why this sample is essentialy
pulling events from the x event queue, rather than using XWindowEvent();
it seems a contrived example. What is the use-case outside of this example?

Best regards,
Okan

> 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);
>  }
> 

Reply via email to