Index | Thread | Search

From:
Walter Alejandro Iglesias <wai@roquesor.com>
Subject:
cwm(1): save original size of maximized windows when restarting
To:
tech@openbsd.org
Date:
Sun, 21 Jun 2026 11:48:05 +0200

Download raw body.

Thread
  • Walter Alejandro Iglesias:

    cwm(1): save original size of maximized windows when restarting

Currently, if you maximize (fullscreen, vmax or hmax) a window and then
restart cwm, you can't toggle its state to its orignal size.  This is
because while its maximized state is preserved, the original size is
lost.

This diff also fixes a bug.  When the active client is not maximized and
there is a vertically or horizontally maximized window in the same
group, the pointer warps to the latter when restarting.


Index: calmwm.c
===================================================================
RCS file: /cvs/xenocara/app/cwm/calmwm.c,v
diff -u -p -u -p -r1.115 calmwm.c
--- calmwm.c	26 Feb 2022 15:19:18 -0000	1.115
+++ calmwm.c	21 Jun 2026 09:46:02 -0000
@@ -51,6 +51,8 @@ static int	x_init(const char *);
 static void	x_teardown(void);
 static int	x_wmerrorhandler(Display *, XErrorEvent *);
 
+int		startup_in_progress = 0;
+
 int
 main(int argc, char **argv)
 {
@@ -103,7 +105,10 @@ main(int argc, char **argv)
 	if (nflag)
 		return 0;
 
+	startup_in_progress = 1;
 	xfd = x_init(display_name);
+	startup_in_progress = 0;
+
 	cwm_status = CWM_RUNNING;
 
 	if (pledge("stdio rpath proc exec", NULL) == -1)
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	21 Jun 2026 09:46:02 -0000
@@ -403,6 +403,7 @@ void			 client_apply_sizehints(struct cl
 void			 client_close(struct client_ctx *);
 void			 client_config(struct client_ctx *);
 struct client_ctx	*client_current(struct screen_ctx *);
+void			 client_delete_geometry_prop(struct client_ctx *);
 void			 client_draw_border(struct client_ctx *);
 struct client_ctx	*client_find(Window);
 void			 client_get_sizehints(struct client_ctx *);
@@ -435,6 +436,7 @@ void			 client_toggle_skip_taskbar(struc
 void			 client_toggle_sticky(struct client_ctx *);
 void			 client_toggle_vmaximize(struct client_ctx *);
 void			 client_transient(struct client_ctx *);
+void			 client_update_savegeom_prop(struct client_ctx *, int);
 void			 client_urgency(struct client_ctx *);
 void 			 client_vtile(struct client_ctx *);
 void			 client_wm_hints(struct client_ctx *);
@@ -607,5 +609,11 @@ int			 xasprintf(char **, const char *, 
 			    __attribute__((__nonnull__ (2)));
 int			 xvasprintf(char **, const char *, va_list)
 			    __attribute__((__nonnull__ (2)));
+
+/* Global startup tracker to prevent pointer warping and state loss */
+extern int		 startup_in_progress;
+
+/* Store original geometry on windows over restarts */
+#define _CWM_SAVE_GEOM	"_CWM_SAVE_GEOM"
 
 #endif /* _CALMWM_H_ */
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	21 Jun 2026 09:46:02 -0000
@@ -43,6 +43,11 @@ client_init(Window win, struct screen_ct
 	XWindowAttributes	 wattr;
 	int			 mapped;
 	long			 state;
+	Atom			 prop;
+	Atom			 actual_type;
+	int			 actual_format;
+	unsigned long		 nitems, bytes_after;
+	unsigned char		*prop_data = NULL;
 
 	if (win == None)
 		return NULL;
@@ -83,6 +88,23 @@ client_init(Window win, struct screen_ct
 	cc->obwidth = wattr.border_width;
 	cc->bwidth = Conf.bwidth;
 
+	/* Try to restore pre-maximized layout from the custom property */
+	prop = XInternAtom(X_Dpy, _CWM_SAVE_GEOM, False);
+
+	if (XGetWindowProperty(X_Dpy, cc->win, prop, 0, 4, False, XA_CARDINAL,
+	    &actual_type, &actual_format, &nitems, &bytes_after,
+	    &prop_data) == Success && prop_data != NULL) {
+		if (nitems == 4) {
+			long *geom = (long *)prop_data;
+			cc->savegeom.x = geom[0];
+			cc->savegeom.y = geom[1];
+			cc->savegeom.w = geom[2];
+			cc->savegeom.h = geom[3];
+		}
+		XFree(prop_data);
+	} else
+		cc->savegeom = cc->geom;
+
 	client_set_name(cc);
 	conf_client(cc);
 
@@ -318,12 +340,15 @@ client_toggle_fullscreen(struct client_c
 	if (cc->flags & CLIENT_FULLSCREEN) {
 		if (!(cc->flags & CLIENT_IGNORE))
 			cc->bwidth = Conf.bwidth;
-		cc->geom = cc->fullgeom;
+		cc->geom = cc->savegeom;
 		cc->flags &= ~(CLIENT_FULLSCREEN | CLIENT_FREEZE);
+		client_delete_geometry_prop(cc);
 		goto resize;
 	}
 
-	cc->fullgeom = cc->geom;
+	if (!startup_in_progress)
+		cc->savegeom = cc->geom;
+	client_update_savegeom_prop(cc, 1);
 
 	area = screen_area(sc,
 	    cc->geom.x + cc->geom.w / 2,
@@ -336,14 +361,15 @@ client_toggle_fullscreen(struct client_c
 resize:
 	client_resize(cc, 0);
 	xu_ewmh_set_net_wm_state(cc);
-	client_ptr_inbound(cc, 1);
+	if (!startup_in_progress)
+		client_ptr_inbound(cc, 1);
 }
 
 void
 client_toggle_maximize(struct client_ctx *cc)
 {
-	struct screen_ctx	*sc = cc->sc;
-	struct geom		 area;
+	struct screen_ctx       *sc = cc->sc;
+	struct geom              area;
 
 	if (cc->flags & CLIENT_FREEZE)
 		return;
@@ -351,18 +377,15 @@ client_toggle_maximize(struct client_ctx
 	if ((cc->flags & CLIENT_MAXFLAGS) == CLIENT_MAXIMIZED) {
 		cc->geom = cc->savegeom;
 		cc->flags &= ~CLIENT_MAXIMIZED;
+		client_delete_geometry_prop(cc);
 		goto resize;
 	}
 
-	if (!(cc->flags & CLIENT_VMAXIMIZED)) {
-		cc->savegeom.h = cc->geom.h;
-		cc->savegeom.y = cc->geom.y;
-	}
+	if (!(cc->flags & CLIENT_VMAXIMIZED))
+		client_update_savegeom_prop(cc, 1);
 
-	if (!(cc->flags & CLIENT_HMAXIMIZED)) {
-		cc->savegeom.w = cc->geom.w;
-		cc->savegeom.x = cc->geom.x;
-	}
+	if (!(cc->flags & CLIENT_HMAXIMIZED))
+		client_update_savegeom_prop(cc, 0);
 
 	area = screen_area(sc,
 	    cc->geom.x + cc->geom.w / 2,
@@ -377,14 +400,15 @@ client_toggle_maximize(struct client_ctx
 resize:
 	client_resize(cc, 0);
 	xu_ewmh_set_net_wm_state(cc);
-	client_ptr_inbound(cc, 1);
+	if (!startup_in_progress)
+		client_ptr_inbound(cc, 1);
 }
 
 void
 client_toggle_vmaximize(struct client_ctx *cc)
 {
-	struct screen_ctx	*sc = cc->sc;
-	struct geom		 area;
+	struct screen_ctx       *sc = cc->sc;
+	struct geom              area;
 
 	if (cc->flags & CLIENT_FREEZE)
 		return;
@@ -393,11 +417,10 @@ client_toggle_vmaximize(struct client_ct
 		cc->geom.y = cc->savegeom.y;
 		cc->geom.h = cc->savegeom.h;
 		cc->flags &= ~CLIENT_VMAXIMIZED;
+		client_delete_geometry_prop(cc);
 		goto resize;
 	}
-
-	cc->savegeom.y = cc->geom.y;
-	cc->savegeom.h = cc->geom.h;
+	client_update_savegeom_prop(cc, 1);
 
 	area = screen_area(sc,
 	    cc->geom.x + cc->geom.w / 2,
@@ -410,14 +433,15 @@ client_toggle_vmaximize(struct client_ct
 resize:
 	client_resize(cc, 0);
 	xu_ewmh_set_net_wm_state(cc);
-	client_ptr_inbound(cc, 1);
+	if (!startup_in_progress)
+		client_ptr_inbound(cc, 1);
 }
 
 void
 client_toggle_hmaximize(struct client_ctx *cc)
 {
-	struct screen_ctx	*sc = cc->sc;
-	struct geom		 area;
+	struct screen_ctx       *sc = cc->sc;
+	struct geom              area;
 
 	if (cc->flags & CLIENT_FREEZE)
 		return;
@@ -426,11 +450,11 @@ client_toggle_hmaximize(struct client_ct
 		cc->geom.x = cc->savegeom.x;
 		cc->geom.w = cc->savegeom.w;
 		cc->flags &= ~CLIENT_HMAXIMIZED;
+		client_delete_geometry_prop(cc);
 		goto resize;
 	}
 
-	cc->savegeom.x = cc->geom.x;
-	cc->savegeom.w = cc->geom.w;
+	client_update_savegeom_prop(cc, 0);
 
 	area = screen_area(sc,
 	    cc->geom.x + cc->geom.w / 2,
@@ -443,7 +467,8 @@ client_toggle_hmaximize(struct client_ct
 resize:
 	client_resize(cc, 0);
 	xu_ewmh_set_net_wm_state(cc);
-	client_ptr_inbound(cc, 1);
+	if (!startup_in_progress)
+		client_ptr_inbound(cc, 1);
 }
 
 void
@@ -1046,4 +1071,37 @@ client_vtile(struct client_ctx *cc)
 		i++;
 		client_resize(ci, 1);
 	}
+}
+
+void
+client_update_savegeom_prop(struct client_ctx *cc, int update_y_axis)
+{
+	Atom	prop;
+
+	if (startup_in_progress)
+		return;
+
+	if (update_y_axis) {
+		cc->savegeom.h = cc->geom.h;
+		cc->savegeom.y = cc->geom.y;
+	} else {
+		cc->savegeom.w = cc->geom.w;
+		cc->savegeom.x = cc->geom.x;
+	}
+
+	long geom_data[4] = { cc->savegeom.x, cc->savegeom.y,
+		cc->savegeom.w, cc->savegeom.h };
+
+	prop = XInternAtom(X_Dpy, _CWM_SAVE_GEOM, False);
+	XChangeProperty(X_Dpy, cc->win, prop, XA_CARDINAL, 32,
+	    PropModeReplace, (unsigned char *)geom_data, 4);
+}
+
+void
+client_delete_geometry_prop(struct client_ctx *cc)
+{
+	Atom prop;
+
+	prop = XInternAtom(X_Dpy, _CWM_SAVE_GEOM, False);
+	XDeleteProperty(X_Dpy, cc->win, prop);
 }



-- 
Walter