Hi,

I'm using cwm as a daily driver on my Linux desktop machine and have been maintaining a custom patchset for about half a year now. It mainly removes features I never use, but also has seen one or two bug fixes. In the hope that they are useful for upstream, I've attached a few of them. Whilst based on my own tree of the cwm source, I've made sure that these apply cleanly on top of the official xenocara tree with -p1.

PATCH 1/3) Fix string truncation in menu_draw

This one is pretty straightforward - the size calculation for dispstr from menu.c did not account for the prompt characters, leading to possible truncation.

I think I've also identified a string truncation problem at menu.c:207

                if (mi->text[0] != '\0')
                        snprintf(mr->text, sizeof(mr->text), "%s \"%s\"",
                            mc->searchstr, mi->text);

As far as I can see, mr->text may end up being used for u_spawn, possibly corrupting the quoted path if the string is truncated. I do not have a fix ready for this as my patchset removes the path completion functionality altogether.

PATCH 2/3) Plug memory leak in conf_clear

cargs and cargs->cmd were never freed in conf.c. My patch simply uses the already existing conf_unbind_key() function to free those properly.

Lastly, PATCH 3/3 exists more as a request for comments and is not meant for immediate inclusion. I am aware of a problem where certain windows' borders (and the size or position popup menus) do not render correctly when displayed with a compositor running.

I think this is because cwm uses the screen's default colormap and visual to draw borders and popup menus, when it should be using each window's colormap and visual instead. Borders and popup menus render fine for me with the attached patch (more details there), but I am unsure whether this is the correct solution.

I am very much not familiar with X11 programming and this patch is more than 6 months old at this point, so I may just be doing the wrong thing here. Nevertheless, maybe it's useful for further discussion.

Thanks a lot for your time,

--
Wolf
>From b87031f89bdbdaff956e307cc18dd3aa3b95aca3 Mon Sep 17 00:00:00 2001
From: Wynn Wolf Arbor <wolf@oriole.systems>
Date: Wed, 18 Mar 2020 19:47:54 +0100
Subject: [PATCH 1/3] Fix string truncation in menu_draw

The previous size calculation did not account for the prompt characters
(0xc2 0xbb and 0xc2 0xab respectively).
---
 app/cwm/menu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/cwm/menu.c b/app/cwm/menu.c
index 60ee46a..f2eddc3 100644
--- a/app/cwm/menu.c
+++ b/app/cwm/menu.c
@@ -53,7 +53,7 @@ struct menu_ctx {
 	XftDraw			*xftdraw;
 	struct geom		 geom;
 	char			 searchstr[MENU_MAXENTRY + 1];
-	char			 dispstr[MENU_MAXENTRY*2 + 1];
+	char			 dispstr[MENU_MAXENTRY*2 + 5];
 	char			 promptstr[MENU_MAXENTRY + 1];
 	int			 list;
 	int			 listing;
-- 
2.26.2

>From dc6573f7a15d09a7d985271c45398edacae9090b Mon Sep 17 00:00:00 2001
From: Wynn Wolf Arbor <wolf@oriole.systems>
Date: Wed, 18 Mar 2020 19:47:55 +0100
Subject: [PATCH 2/3] Plug a memory leak in conf_clear

These loops never freed cargs and cargs->cmd from bind_ctx. Instead of
adding more calls to free() manually, replace the whole loops with the
conf_unbind_* functions which free the struct properly.
---
 app/cwm/conf.c | 11 ++---------
 1 file changed, 2 insertions(+), 9 deletions(-)

diff --git a/app/cwm/conf.c b/app/cwm/conf.c
index 597dd79..ad097f3 100644
--- a/app/cwm/conf.c
+++ b/app/cwm/conf.c
@@ -326,7 +326,6 @@ void
 conf_clear(struct conf *c)
 {
 	struct autogroup	*ag;
-	struct bind_ctx		*kb, *mb;
 	struct winname		*wn;
 	struct cmd_ctx		*cmd, *wm;
 	int			 i;
@@ -343,10 +342,7 @@ conf_clear(struct conf *c)
 		free(wm->path);
 		free(wm);
 	}
-	while ((kb = TAILQ_FIRST(&c->keybindq)) != NULL) {
-		TAILQ_REMOVE(&c->keybindq, kb, entry);
-		free(kb);
-	}
+	conf_unbind_key(c, NULL);
 	while ((ag = TAILQ_FIRST(&c->autogroupq)) != NULL) {
 		TAILQ_REMOVE(&c->autogroupq, ag, entry);
 		free(ag->class);
@@ -358,10 +354,7 @@ conf_clear(struct conf *c)
 		free(wn->name);
 		free(wn);
 	}
-	while ((mb = TAILQ_FIRST(&c->mousebindq)) != NULL) {
-		TAILQ_REMOVE(&c->mousebindq, mb, entry);
-		free(mb);
-	}
+	conf_unbind_mouse(c, NULL);
 	for (i = 0; i < CWM_COLOR_NITEMS; i++)
 		free(c->color[i]);
 
-- 
2.26.2

>From da176f9f5e2f4a762d08e639c3edb0e8dee8224c Mon Sep 17 00:00:00 2001
From: Wynn Wolf Arbor <wolf@oriole.systems>
Date: Wed, 18 Mar 2020 19:47:55 +0100
Subject: [PATCH 3/3] Calculate colors using the client's visual and colormap

As cwm was using the screen's default visual and colormap to draw all
client borders, borders for windows that had a depth of 32 bits were not
rendered correctly. The same happened with text in the popup menus which
were recently changed to be drawn in the context of the client.

This commit introduces a Visual reference for each client, and allocates
all potential colors for a client's specific visual and colormap in the
client_ctx struct. These colors are then used to draw client borders and
popup menus.
---
 app/cwm/calmwm.h |  4 +++-
 app/cwm/client.c | 16 ++++++++++------
 app/cwm/conf.c   | 21 +++++++++++++++++++++
 app/cwm/kbfunc.c |  4 ++--
 app/cwm/screen.c | 10 +++++-----
 5 files changed, 41 insertions(+), 14 deletions(-)

diff --git a/app/cwm/calmwm.h b/app/cwm/calmwm.h
index 521f8d8..261cf29 100644
--- a/app/cwm/calmwm.h
+++ b/app/cwm/calmwm.h
@@ -139,6 +139,7 @@ struct client_ctx {
 	struct group_ctx	*gc;
 	Window			 win;
 	Colormap		 colormap;
+	Visual			*visual;
 	int			 bwidth; /* border width */
 	int			 obwidth; /* original border width */
 	struct geom		 geom, savegeom, fullgeom;
@@ -193,6 +194,7 @@ struct client_ctx {
 	char			*res_class; /* class hint */
 	char			*res_name; /* class hint */
 	int			 initial_state; /* wm hint */
+	XftColor		 xftcolor[CWM_COLOR_NITEMS];
 };
 TAILQ_HEAD(client_q, client_ctx);
 
@@ -489,7 +491,7 @@ void			 screen_assert_clients_within(struct screen_ctx *);
 struct geom		 screen_area(struct screen_ctx *, int, int, int);
 struct screen_ctx	*screen_find(Window);
 void			 screen_init(int);
-void			 screen_prop_win_create(struct screen_ctx *, Window);
+void			 screen_prop_win_create(struct screen_ctx *, struct client_ctx *);
 void			 screen_prop_win_destroy(struct screen_ctx *);
 void			 screen_prop_win_draw(struct screen_ctx *,
 			     const char *, ...)
diff --git a/app/cwm/client.c b/app/cwm/client.c
index 4121ee1..1bd98ca 100644
--- a/app/cwm/client.c
+++ b/app/cwm/client.c
@@ -80,6 +80,7 @@ client_init(Window win, struct screen_ctx *sc)
 	cc->geom.w = wattr.width;
 	cc->geom.h = wattr.height;
 	cc->colormap = wattr.colormap;
+	cc->visual = wattr.visual;
 	cc->obwidth = wattr.border_width;
 	cc->bwidth = Conf.bwidth;
 
@@ -210,6 +211,10 @@ client_remove(struct client_ctx *cc)
 {
 	struct screen_ctx	*sc = cc->sc;
 	struct winname		*wn;
+	unsigned int		 i;
+
+	for (i = 0; i < CWM_COLOR_NITEMS; i++)
+		XftColorFree(X_Dpy, cc->visual, cc->colormap, &cc->xftcolor[i]);
 
 	TAILQ_REMOVE(&sc->clientq, cc, entry);
 
@@ -570,26 +575,25 @@ client_urgency(struct client_ctx *cc)
 void
 client_draw_border(struct client_ctx *cc)
 {
-	struct screen_ctx	*sc = cc->sc;
 	unsigned long		 pixel;
 
 	if (cc->flags & CLIENT_ACTIVE)
 		switch (cc->flags & CLIENT_HIGHLIGHT) {
 		case CLIENT_GROUP:
-			pixel = sc->xftcolor[CWM_COLOR_BORDER_GROUP].pixel;
+			pixel = cc->xftcolor[CWM_COLOR_BORDER_GROUP].pixel;
 			break;
 		case CLIENT_UNGROUP:
-			pixel = sc->xftcolor[CWM_COLOR_BORDER_UNGROUP].pixel;
+			pixel = cc->xftcolor[CWM_COLOR_BORDER_UNGROUP].pixel;
 			break;
 		default:
-			pixel = sc->xftcolor[CWM_COLOR_BORDER_ACTIVE].pixel;
+			pixel = cc->xftcolor[CWM_COLOR_BORDER_ACTIVE].pixel;
 			break;
 		}
 	else
-		pixel = sc->xftcolor[CWM_COLOR_BORDER_INACTIVE].pixel;
+		pixel = cc->xftcolor[CWM_COLOR_BORDER_INACTIVE].pixel;
 
 	if (cc->flags & CLIENT_URGENCY)
-		pixel = sc->xftcolor[CWM_COLOR_BORDER_URGENCY].pixel;
+		pixel = cc->xftcolor[CWM_COLOR_BORDER_URGENCY].pixel;
 
 	XSetWindowBorderWidth(X_Dpy, cc->win, (unsigned int)cc->bwidth);
 	XSetWindowBorder(X_Dpy, cc->win, pixel);
diff --git a/app/cwm/conf.c b/app/cwm/conf.c
index ad097f3..6828032 100644
--- a/app/cwm/conf.c
+++ b/app/cwm/conf.c
@@ -454,6 +454,8 @@ void
 conf_client(struct client_ctx *cc)
 {
 	struct winname	*wn;
+	unsigned int	 i;
+	XftColor	 xc;
 
 	TAILQ_FOREACH(wn, &Conf.ignoreq, entry) {
 		if (strncasecmp(wn->name, cc->name, strlen(wn->name)) == 0) {
@@ -461,6 +463,25 @@ conf_client(struct client_ctx *cc)
 			break;
 		}
 	}
+
+	for (i = 0; i < nitems(color_binds); i++) {
+		if (i == CWM_COLOR_MENU_FONT_SEL && *Conf.color[i] == '\0') {
+			xu_xorcolor(cc->xftcolor[CWM_COLOR_MENU_BG],
+			    cc->xftcolor[CWM_COLOR_MENU_FG], &xc);
+			xu_xorcolor(cc->xftcolor[CWM_COLOR_MENU_FONT], xc, &xc);
+			if (!XftColorAllocValue(X_Dpy, cc->visual, cc->colormap,
+			    &xc.color, &cc->xftcolor[CWM_COLOR_MENU_FONT_SEL]))
+				warnx("XftColorAllocValue: %s", Conf.color[i]);
+			break;
+		}
+		if (!XftColorAllocName(X_Dpy, cc->visual, cc->colormap,
+		    Conf.color[i], &cc->xftcolor[i])) {
+			warnx("XftColorAllocName: %s", Conf.color[i]);
+			XftColorAllocName(X_Dpy, cc->visual, cc->colormap,
+			    color_binds[i], &cc->xftcolor[i]);
+		}
+	}
+
 }
 
 void
diff --git a/app/cwm/kbfunc.c b/app/cwm/kbfunc.c
index eeeee20..699afe7 100644
--- a/app/cwm/kbfunc.c
+++ b/app/cwm/kbfunc.c
@@ -167,7 +167,7 @@ kbfunc_client_move_mb(void *ctx, struct cargs *cargs)
 	    CurrentTime) != GrabSuccess)
 		return;
 
-	screen_prop_win_create(sc, cc->win);
+	screen_prop_win_create(sc, cc);
 	screen_prop_win_draw(sc, "%+5d%+5d", cc->geom.x, cc->geom.y);
 	while (move) {
 		XMaskEvent(X_Dpy, MOUSEMASK, &ev);
@@ -256,7 +256,7 @@ kbfunc_client_resize_mb(void *ctx, struct cargs *cargs)
 	    CurrentTime) != GrabSuccess)
 		return;
 
-	screen_prop_win_create(sc, cc->win);
+	screen_prop_win_create(sc, cc);
 	screen_prop_win_draw(sc, "%4d x %-4d", cc->dim.w, cc->dim.h);
 	while (resize) {
 		XMaskEvent(X_Dpy, MOUSEMASK, &ev);
diff --git a/app/cwm/screen.c b/app/cwm/screen.c
index afd294c..b208d07 100644
--- a/app/cwm/screen.c
+++ b/app/cwm/screen.c
@@ -265,13 +265,13 @@ screen_assert_clients_within(struct screen_ctx *sc)
 }
 
 void
-screen_prop_win_create(struct screen_ctx *sc, Window win)
+screen_prop_win_create(struct screen_ctx *sc, struct client_ctx *cc)
 {
-	sc->prop.win = XCreateSimpleWindow(X_Dpy, win, 0, 0, 1, 1, 0,
-	    sc->xftcolor[CWM_COLOR_MENU_BG].pixel,
-	    sc->xftcolor[CWM_COLOR_MENU_BG].pixel);
+	sc->prop.win = XCreateSimpleWindow(X_Dpy, cc->win, 0, 0, 1, 1, 0,
+	    cc->xftcolor[CWM_COLOR_MENU_FG].pixel,
+	    cc->xftcolor[CWM_COLOR_MENU_BG].pixel);
 	sc->prop.xftdraw = XftDrawCreate(X_Dpy, sc->prop.win,
-	    sc->visual, sc->colormap);
+	    cc->visual, cc->colormap);
 
 	XMapWindow(X_Dpy, sc->prop.win);
 }
-- 
2.26.2

Reply via email to