Download raw body.
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
cwm(1): save original size of maximized windows when restarting