commit fcd4b314c820030f4883d3ac43434e3bf92ab895
parent 5c00cb3ee9ca244625a5c617fd7c68a2af26cf91
Author: wh1tepearl <wh1tepearl@gmail.com>
Date: Fri, 27 Mar 2026 12:21:32 +0000
support for external bars, some toggle bar improvement (hello picom users), bump version to 2.2
Diffstat:
8 files changed, 284 insertions(+), 27 deletions(-)
diff --git a/Makefile b/Makefile
@@ -23,7 +23,7 @@ vxwm: ${OBJ}
${CC} -o $@ ${OBJ} ${LDFLAGS}
clean:
- rm -f vxwm ${OBJ} dwm-${VERSION}.tar.gz
+ rm -f vxwm ${OBJ} vxwm-${VERSION}.tar.gz
dist: clean
mkdir -p vxwm-${VERSION}
diff --git a/config.mk b/config.mk
@@ -1,5 +1,5 @@
# vxwm version
-VERSION = 2.1
+VERSION = 2.2
# Customize below to fit your system
diff --git a/modules.def.h b/modules.def.h
@@ -18,10 +18,10 @@ Instead of managing "layers" or "hidden states," you manage position.
Want more space? Slide the view over.
Can't find a window? Switch your focus to it, and the world slides until that window is right under your nose.
Lost? Hit the "homecanvas" keybind to snap your view back to the start.
-Even though this sounds complex, it is actually pretty lightweight ~250 l.o.c, and is very easy to use.
+Even though this sounds complex, it is actually pretty lightweight, and is very easy to use.
*/
-#define IT_SHOW_COORDINATES_IN_BAR 1 // Shows your coordinates in the bar.
+#define IT_SHOW_COORDINATES_IN_BAR 1 // Shows your coordinates in the bar, pretty impossible to use infinite tags without this.
@@ -30,19 +30,21 @@ Even though this sounds complex, it is actually pretty lightweight ~250 l.o.c, a
#define BR_CHANGE_CURSOR 1 // When resizing windows while having BETTER_RESIZE set to 1, the cursor will change depending on from which side you are resizing.
#define LOCK_MOVE_RESIZE_REFRESH_RATE 1 // Recommended to use on every pc, because cpu (software) rendered apps like ST will lag when resizing even if you have a good pc.
#define USE_RESIZECLIENT_FUNC 0 // Use resizeclient function instead of resize function which ignores window's resize hints, not recommended.
-#define RESIZING_WINDOWS_IN_ALL_LAYOUTS_FLOATS_THEM 0 // yeah.
+#define RESIZING_WINDOWS_IN_ALL_LAYOUTS_FLOATS_THEM 1 // yeah.
#define MOVE_RESIZE_WITH_KEYBOARD 1 // Allows to move and resize windows with keyboard.
+
+
/* Kind of eye candy */
-#define GAPS 0 // Gaps support.
-#define XRDB 0 // Xrdb support.
+#define GAPS 1 // Gaps support.
+#define XRDB 1 // Xrdb support.
/* Tagging */
-#define TAG_TO_TAG 0 // If you switch to tag where you already are, it'll switch to previous tag.
+#define TAG_TO_TAG 1 // If you switch to tag where you already are, it'll switch to previous tag.
#define SLOWER_TAGS_ANIMATION 0 // This slows down tags animation speed, which results in smoother tags animations (requires picom to see any difference).
-#define WINDOWMAP 0
+#define WINDOWMAP 1
/* This makes the windows get mapped or unmapped in X11. This results in certain
behaviour being enabled, some examples are: fix issues with some applications
losing input forever after a tag change or when you use a compositor like picom,
@@ -55,11 +57,16 @@ Even though this sounds complex, it is actually pretty lightweight ~250 l.o.c, a
/* Bar */
-#define ALT_CENTER_OF_BAR_COLOR 0 // changes center of bar color to a dark color.
-#define BAR_HEIGHT 0 // Support for changing bar height.
-#define BAR_PADDING 0 // Support for changing the bar padding.
+/* Internal */
+#define ALT_CENTER_OF_BAR_COLOR 1 // changes center of bar color to a dark color.
+#define BAR_HEIGHT 1 // Support for changing bar height.
+#define BAR_PADDING 1 // Support for changing the bar padding.
#define OCCUPIED_TAGS_DECORATION 0 // This provides the ability to use an alternative text for tags which contain at least one window aka occupied tags.
+/* External */
+#define EXTERNAL_BARS 1 // Support for external bars, essencial if you want to use external bars.
+#define EWMH_TAGS 1 // Support for EWMH tags, recommended if you want to use external bars with less pain
+
/* Warp to client */
@@ -76,11 +83,10 @@ Even though this sounds complex, it is actually pretty lightweight ~250 l.o.c, a
/* Misc */
#define AUTOSTART 0 // Support for vxwm being able to start apps defined in config.h in startup.
-#define FULLSCREEN 0 // Support for toggling fullscreen.
-#define MOVE_IN_TILED 0 // Support for moving windows in tiled mode.
-#define EWMH_TAGS 0 // Support for EWMH tags, recommended if you want to use external bars with less pain
-#define DIRECTIONAL_FOCUS 0 // yeah.
-#define DIRECTIONAL_MOVE 0
+#define FULLSCREEN 1 // Support for toggling fullscreen.
+#define MOVE_IN_TILED 1 // Support for moving windows in tiled mode.
+#define DIRECTIONAL_FOCUS 1 // yeah.
+#define DIRECTIONAL_MOVE 1
/* Makes moving windows in tiled layout possible with keyboard and it is directional,
bind for move is in #if MOVE_RESIZE_WITH_KEYBOARD section which makes it depending on
MOVE_RESIZE_WITH_KEYBOARD at the first sight but, it doesn't. You can bind the movedir
@@ -98,22 +104,23 @@ Even though this sounds complex, it is actually pretty lightweight ~250 l.o.c, a
/* Floating */
/* Recomended to use with ALWAYS_CENTER_NEW_FLOATING_WINDOWS set to 1. */
-#define ALWAYS_CENTER_NEW_FLOATING_WINDOWS 0 // so, basically, it does what it says.
+#define ALWAYS_CENTER_NEW_FLOATING_WINDOWS 1 // so, basically, it does what it says.
-#define FLOATING_LAYOUT_FLOATS_WINDOWS 0
+#define FLOATING_LAYOUT_FLOATS_WINDOWS 1
/* By default, in floating layout, windows appear to be floating, but, for dwm,
they are not. Because of this, when switching to tiled layout after floating
layout, windows will be tiled, enable this if you don't want that behaviour. */
-#define ENHANCED_TOGGLE_FLOATING 0
+#define ENHANCED_TOGGLE_FLOATING 1
/* Support for enhanced toggle floating, when toggling floating window will
resize to its natural size, and in floating layout, window will be tiled.
REQUIRES "FLOATING_LAYOUT_FLOATS_WINDOWS" SET TO 1 TO WORK PROPERLY. */
-#define RESTORE_SIZE_AND_POS_ETF 0 // Restore previous size and position of window when toggling floating
+#define RESTORE_SIZE_AND_POS_ETF 1 // Restore previous size and position of window when toggling floating
/* Dependency list */
/* INFINITE_TAGS requires WINDOWMAP, please set WINDOWMAP to 1, if not, it will be automatically enabled.
* ENHANCED_TOGGLE_FLOATING requires FLOATING_LAYOUT_FLOATS_WINDOWS, please set FLOATING_LAYOUT_FLOATS_WINDOWS to 1, if not, it will be automatically enabled. */
+
diff --git a/modules/externalbars/externalbars.c b/modules/externalbars/externalbars.c
@@ -0,0 +1,176 @@
+static ExternalBarStrut *ebarstruts = NULL;
+static Atom eb_atom_strut = None;
+static Atom eb_atom_strut_partial = None;
+
+void
+externalbars_init_atoms(void)
+{
+ if (eb_atom_strut == None)
+ eb_atom_strut = XInternAtom(dpy, "_NET_WM_STRUT", False);
+ if (eb_atom_strut_partial == None)
+ eb_atom_strut_partial = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
+}
+
+int
+externalbars_read(Window w, ExternalBarStrut *out)
+{
+ Atom real;
+ int fmt;
+ unsigned long n, extra;
+ unsigned char *p = NULL;
+
+ externalbars_init_atoms();
+ memset(out, 0, sizeof *out);
+ out->win = w;
+
+ if (XGetWindowProperty(dpy, w, eb_atom_strut_partial, 0L, 12L, False,
+ XA_CARDINAL, &real, &fmt, &n, &extra, &p) == Success && p) {
+ if (n >= 4) {
+ long *s = (long *)p;
+ out->left = (int)s[0]; out->right = (int)s[1];
+ out->top = (int)s[2]; out->bottom = (int)s[3];
+ if (n >= 12) {
+ out->left_start_y = (int)s[4]; out->left_end_y = (int)s[5];
+ out->right_start_y = (int)s[6]; out->right_end_y = (int)s[7];
+ out->top_start_x = (int)s[8]; out->top_end_x = (int)s[9];
+ out->bottom_start_x = (int)s[10]; out->bottom_end_x = (int)s[11];
+ } else {
+ out->left_start_y = 0; out->left_end_y = sh;
+ out->right_start_y = 0; out->right_end_y = sh;
+ out->top_start_x = 0; out->top_end_x = sw;
+ out->bottom_start_x = 0; out->bottom_end_x = sw;
+ }
+ XFree(p);
+ if (out->left == 0 && out->right == 0 &&
+ out->top == 0 && out->bottom == 0)
+ return 0;
+ return 1;
+ }
+ XFree(p);
+ p = NULL;
+ }
+
+ if (XGetWindowProperty(dpy, w, eb_atom_strut, 0L, 4L, False,
+ XA_CARDINAL, &real, &fmt, &n, &extra, &p) == Success && p) {
+ if (n >= 4) {
+ long *s = (long *)p;
+ out->left = (int)s[0]; out->right = (int)s[1];
+ out->top = (int)s[2]; out->bottom = (int)s[3];
+ out->left_start_y = 0; out->left_end_y = sh;
+ out->right_start_y = 0; out->right_end_y = sh;
+ out->top_start_x = 0; out->top_end_x = sw;
+ out->bottom_start_x = 0; out->bottom_end_x = sw;
+ XFree(p);
+ if (out->left == 0 && out->right == 0 &&
+ out->top == 0 && out->bottom == 0)
+ return 0;
+ return 1;
+ }
+ XFree(p);
+ }
+ return 0;
+}
+
+int
+externalbars_hasstrut(Window w)
+{
+ ExternalBarStrut tmp;
+ return externalbars_read(w, &tmp);
+}
+
+void
+externalbars_register(Window w)
+{
+ ExternalBarStrut tmp, *sw;
+
+ if (!externalbars_read(w, &tmp))
+ return;
+
+ for (sw = ebarstruts; sw; sw = sw->next) {
+ if (sw->win == w) {
+ ExternalBarStrut *nxt = sw->next;
+ *sw = tmp;
+ sw->next = nxt;
+ externalbars_reapply_all();
+ return;
+ }
+ }
+
+ sw = ecalloc(1, sizeof(ExternalBarStrut));
+ *sw = tmp;
+ sw->next = ebarstruts;
+ ebarstruts = sw;
+ externalbars_reapply_all();
+}
+
+void
+externalbars_unregister(Window w)
+{
+ ExternalBarStrut **prev = &ebarstruts, *sw;
+
+ while ((sw = *prev)) {
+ if (sw->win == w) {
+ *prev = sw->next;
+ free(sw);
+ externalbars_reapply_all();
+ return;
+ }
+ prev = &sw->next;
+ }
+}
+
+void
+externalbars_apply(Monitor *m)
+{
+ ExternalBarStrut *s;
+ int top = 0, bottom = 0, left = 0, right = 0;
+
+ for (s = ebarstruts; s; s = s->next) {
+ if (s->top > 0) {
+ if (s->top_start_x < m->mx + m->mw && s->top_end_x > m->mx) {
+ int local = s->top - m->my;
+ if (local > 0)
+ top = MAX(top, MIN(local, m->mh));
+ }
+ }
+ if (s->bottom > 0) {
+ if (s->bottom_start_x < m->mx + m->mw && s->bottom_end_x > m->mx) {
+ int local = s->bottom - (sh - (m->my + m->mh));
+ if (local > 0)
+ bottom = MAX(bottom, MIN(local, m->mh));
+ }
+ }
+ if (s->left > 0) {
+ if (s->left_start_y < m->my + m->mh && s->left_end_y > m->my) {
+ int local = s->left - m->mx;
+ if (local > 0)
+ left = MAX(left, MIN(local, m->mw));
+ }
+ }
+ if (s->right > 0) {
+ if (s->right_start_y < m->my + m->mh && s->right_end_y > m->my) {
+ int local = s->right - (sw - (m->mx + m->mw));
+ if (local > 0)
+ right = MAX(right, MIN(local, m->mw));
+ }
+ }
+ }
+
+ m->strut_top = top;
+ m->strut_bottom = bottom;
+ m->strut_left = left;
+ m->strut_right = right;
+}
+
+void
+externalbars_reapply_all(void)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next) {
+ externalbars_apply(m);
+ updatebarpos(m);
+ }
+ if (selmon)
+ arrange(NULL);
+}
diff --git a/modules/externalbars/externalbars.h b/modules/externalbars/externalbars.h
@@ -0,0 +1,16 @@
+typedef struct ExternalBarStrut ExternalBarStrut;
+struct ExternalBarStrut {
+ Window win;
+ int left, right, top, bottom;
+ int left_start_y, left_end_y;
+ int right_start_y, right_end_y;
+ int top_start_x, top_end_x;
+ int bottom_start_x, bottom_end_x;
+ ExternalBarStrut *next;
+};
+
+static int externalbars_hasstrut(Window w);
+static void externalbars_register(Window w);
+static void externalbars_unregister(Window w);
+static void externalbars_apply(Monitor *m);
+static void externalbars_reapply_all(void);
diff --git a/modules/vxwm_includes.c b/modules/vxwm_includes.c
@@ -51,3 +51,7 @@
#if AUTOSTART
#include "autostart/autostart.c"
#endif
+
+#if EXTERNAL_BARS
+#include "externalbars/externalbars.c"
+#endif
diff --git a/modules/vxwm_includes.h b/modules/vxwm_includes.h
@@ -47,3 +47,7 @@
#if AUTOSTART
#include "autostart/autostart.h"
#endif
+
+#if EXTERNAL_BARS
+#include "externalbars/externalbars.h"
+#endif
diff --git a/vxwm.c b/vxwm.c
@@ -194,6 +194,9 @@ struct Monitor {
#if INFINITE_TAGS
CanvasOffset *canvas;
#endif
+#if EXTERNAL_BARS
+ int strut_top, strut_bottom, strut_left, strut_right;
+#endif
};
typedef struct {
@@ -763,6 +766,9 @@ destroynotify(XEvent *e)
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+#if EXTERNAL_BARS
+ externalbars_unregister(ev->window);
+#endif
}
void
@@ -1319,9 +1325,17 @@ maprequest(XEvent *e)
{
static XWindowAttributes wa;
XMapRequestEvent *ev = &e->xmaprequest;
-
+
if (!XGetWindowAttributes(dpy, ev->window, &wa) || wa.override_redirect)
return;
+#if EXTERNAL_BARS
+ if (externalbars_hasstrut(ev->window)) {
+ externalbars_register(ev->window);
+ XMapWindow(dpy, ev->window);
+ XSelectInput(dpy, ev->window, PropertyChangeMask|StructureNotifyMask);
+ return;
+ }
+#endif
if (!wintoclient(ev->window))
manage(ev->window, &wa);
}
@@ -1558,6 +1572,17 @@ propertynotify(XEvent *e)
Window trans;
XPropertyEvent *ev = &e->xproperty;
+#if EXTERNAL_BARS
+ if (ev->atom == XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False) ||
+ ev->atom == XInternAtom(dpy, "_NET_WM_STRUT", False)) {
+ if (ev->state == PropertyNewValue)
+ externalbars_register(ev->window);
+ else
+ externalbars_unregister(ev->window);
+ return;
+ }
+#endif
+
if ((ev->window == root) && (ev->atom == XA_WM_NAME))
updatestatus();
else if (ev->state == PropertyDelete)
@@ -2210,14 +2235,28 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
- selmon->showbar = !selmon->showbar;
- updatebarpos(selmon);
+ selmon->showbar = !selmon->showbar;
+ updatebarpos(selmon);
+
+ int bar_y;
+ if (selmon->showbar) {
+ bar_y = selmon->by;
+ } else {
+ if (topbar) {
+ bar_y = -bh;
+ } else {
+ bar_y = selmon->mh + bh;
+ }
+ }
+
#if !BAR_PADDING
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, bar_y, selmon->ww, bh);
#else
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh);
+ int final_y = (selmon->showbar) ? (bar_y + vp) : bar_y;
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, final_y, selmon->ww - 2 * sp, bh);
#endif
- arrange(selmon);
+
+ arrange(selmon);
}
void
@@ -2325,6 +2364,9 @@ unmapnotify(XEvent *e)
else
unmanage(c, 0);
}
+#if EXTERNAL_BARS
+ externalbars_unregister(ev->window);
+#endif
}
void
@@ -2374,6 +2416,14 @@ updatebarpos(Monitor *m)
#else
m->by = -bh - vp;
#endif
+#if EXTERNAL_BARS
+ m->wx += m->strut_left;
+ m->ww -= m->strut_left + m->strut_right;
+ m->wy += m->strut_top;
+ m->wh -= m->strut_top + m->strut_bottom;
+ if (m->ww < 1) m->ww = 1;
+ if (m->wh < 1) m->wh = 1;
+ #endif
}
void