From 2433e0499e4607d39a3f511449f9466886055914 Mon Sep 17 00:00:00 2001 From: Bakkeby Date: Mon, 10 Jan 2022 14:06:10 +0100 Subject: [PATCH 1/2] Bar Modules - splits the bar functionality into individual segments that can be re-arranged --- config.def.h | 20 +++ dwm.c | 393 ++++++++++++++++++++++++++++++++----------- patch/bar_ltsymbol.c | 17 ++ patch/bar_ltsymbol.h | 3 + patch/bar_status.c | 19 +++ patch/bar_status.h | 3 + patch/bar_tags.c | 55 ++++++ patch/bar_tags.h | 3 + patch/bar_wintitle.c | 31 ++++ patch/bar_wintitle.h | 3 + patch/include.c | 5 + patch/include.h | 5 + 12 files changed, 458 insertions(+), 99 deletions(-) create mode 100644 patch/bar_ltsymbol.c create mode 100644 patch/bar_ltsymbol.h create mode 100644 patch/bar_status.c create mode 100644 patch/bar_status.h create mode 100644 patch/bar_tags.c create mode 100644 patch/bar_tags.h create mode 100644 patch/bar_wintitle.c create mode 100644 patch/bar_wintitle.h create mode 100644 patch/include.c create mode 100644 patch/include.h diff --git a/config.def.h b/config.def.h index a2ac963..f870c41 100644 --- a/config.def.h +++ b/config.def.h @@ -31,6 +31,26 @@ static const Rule rules[] = { { "Firefox", NULL, NULL, 1 << 8, 0, -1 }, }; +/* Bar rules allow you to configure what is shown where on the bar, as well as + * introducing your own bar modules. + * + * monitor: + * -1 show on all monitors + * 0 show on monitor 0 + * 'A' show on active monitor (i.e. focused / selected) (or just -1 for active?) + * bar - bar index, 0 is default, 1 is extrabar + * alignment - how the module is aligned compared to other modules + * widthfunc, drawfunc, clickfunc - providing bar module width, draw and click functions + * name - does nothing, intended for visual clue and for logging / debugging + */ +static const BarRule barrules[] = { + /* monitor bar alignment widthfunc drawfunc clickfunc name */ + { -1, 0, BAR_ALIGN_LEFT, width_tags, draw_tags, click_tags, "tags" }, + { -1, 0, BAR_ALIGN_LEFT, width_ltsymbol, draw_ltsymbol, click_ltsymbol, "layout" }, + { 'A', 0, BAR_ALIGN_RIGHT, width_status, draw_status, click_status, "status" }, + { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" }, +}; + /* layout(s) */ static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */ static const int nmaster = 1; /* number of clients in master area */ diff --git a/dwm.c b/dwm.c index a96f33c..86763d8 100644 --- a/dwm.c +++ b/dwm.c @@ -45,6 +45,7 @@ #include "util.h" /* macros */ +#define BARRULES 20 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)) #define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ @@ -66,6 +67,19 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ +enum { + BAR_ALIGN_LEFT, + BAR_ALIGN_CENTER, + BAR_ALIGN_RIGHT, + BAR_ALIGN_LEFT_LEFT, + BAR_ALIGN_LEFT_RIGHT, + BAR_ALIGN_LEFT_CENTER, + BAR_ALIGN_NONE, + BAR_ALIGN_RIGHT_LEFT, + BAR_ALIGN_RIGHT_RIGHT, + BAR_ALIGN_RIGHT_CENTER, + BAR_ALIGN_LAST +}; /* bar alignment */ typedef union { int i; @@ -74,6 +88,46 @@ typedef union { const void *v; } Arg; +typedef struct Monitor Monitor; +typedef struct Bar Bar; +struct Bar { + Window win; + Monitor *mon; + Bar *next; + int idx; + int topbar; + int bx, by, bw, bh; /* bar geometry */ + int w[BARRULES]; // module width + int x[BARRULES]; // module position +}; + +typedef struct { + int max_width; +} BarWidthArg; + +typedef struct { + int x; + int w; +} BarDrawArg; + +typedef struct { + int rel_x; + int rel_y; + int rel_w; + int rel_h; +} BarClickArg; + +typedef struct { + int monitor; + int bar; + int alignment; // see bar alignment enum + int (*widthfunc)(Bar *bar, BarWidthArg *a); + int (*drawfunc)(Bar *bar, BarDrawArg *a); + int (*clickfunc)(Bar *bar, Arg *arg, BarClickArg *a); + char *name; // for debugging + int x, w; // position, width for internal use +} BarRule; + typedef struct { unsigned int click; unsigned int mask; @@ -82,7 +136,6 @@ typedef struct { const Arg arg; } Button; -typedef struct Monitor Monitor; typedef struct Client Client; struct Client { char name[256]; @@ -116,19 +169,17 @@ struct Monitor { float mfact; int nmaster; int num; - int by; /* bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; unsigned int sellt; unsigned int tagset[2]; int showbar; - int topbar; Client *clients; Client *sel; Client *stack; Monitor *next; - Window barwin; + Bar *bar; const Layout *lt[2]; }; @@ -163,6 +214,7 @@ static void detachstack(Client *c); static Monitor *dirtomon(int dir); static void drawbar(Monitor *m); static void drawbars(void); +static void drawbarwin(Bar *bar); static void enternotify(XEvent *e); static void expose(XEvent *e); static void focus(Client *c); @@ -235,12 +287,13 @@ static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); static void zoom(const Arg *arg); +#include "patch/include.h" /* variables */ static const char broken[] = "broken"; static char stext[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ -static int bh, blw = 0; /* bar geometry */ +static int bh; /* bar geometry */ static int lrpad; /* sum of left and right padding for text */ static int (*xerrorxlib)(Display *, XErrorEvent *); static unsigned int numlockmask = 0; @@ -272,6 +325,8 @@ static Window root, wmcheckwin; /* configuration, allows nested code to access above variables */ #include "config.h" +#include "patch/include.c" + /* compile-time check if all tags fit into an unsigned int bit array. */ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; @@ -417,43 +472,61 @@ attachstack(Client *c) void buttonpress(XEvent *e) { - unsigned int i, x, click; + int click, i, r, mi; Arg arg = {0}; Client *c; Monitor *m; + Bar *bar; XButtonPressedEvent *ev = &e->xbutton; + const BarRule *br; + BarClickArg carg = { 0, 0, 0, 0 }; click = ClkRootWin; /* focus monitor if necessary */ - if ((m = wintomon(ev->window)) && m != selmon) { + if ((m = wintomon(ev->window)) && m != selmon + ) { unfocus(selmon->sel, 1); selmon = m; focus(NULL); } - if (ev->window == selmon->barwin) { - i = x = 0; - do - x += TEXTW(tags[i]); - while (ev->x >= x && ++i < LENGTH(tags)); - if (i < LENGTH(tags)) { - click = ClkTagBar; - arg.ui = 1 << i; - } else if (ev->x < x + blw) - click = ClkLtSymbol; - else if (ev->x > selmon->ww - (int)TEXTW(stext)) - click = ClkStatusText; - else - click = ClkWinTitle; - } else if ((c = wintoclient(ev->window))) { + + for (mi = 0, m = mons; m && m != selmon; m = m->next, mi++); // get the monitor index + for (bar = selmon->bar; bar; bar = bar->next) { + if (ev->window == bar->win) { + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || (br->monitor == 'A' && m != selmon) || br->clickfunc == NULL) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi) + continue; + if (bar->x[r] <= ev->x && ev->x <= bar->x[r] + bar->w[r]) { + carg.rel_x = ev->x - bar->x[r]; + carg.rel_y = ev->y; + carg.rel_w = bar->w[r]; + carg.rel_h = bar->bh; + click = br->clickfunc(bar, &arg, &carg); + if (click < 0) + return; + break; + } + } + break; + } + } + + if (click == ClkRootWin && (c = wintoclient(ev->window))) { focus(c); restack(selmon); XAllowEvents(dpy, ReplayPointer, CurrentTime); click = ClkClientWin; } - for (i = 0; i < LENGTH(buttons); i++) + + for (i = 0; i < LENGTH(buttons); i++) { if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button - && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) + && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + } + } } void @@ -498,6 +571,7 @@ void cleanupmon(Monitor *mon) { Monitor *m; + Bar *bar; if (mon == mons) mons = mons->next; @@ -505,8 +579,12 @@ cleanupmon(Monitor *mon) for (m = mons; m && m->next != mon; m = m->next); m->next = mon->next; } - XUnmapWindow(dpy, mon->barwin); - XDestroyWindow(dpy, mon->barwin); + for (bar = mon->bar; bar; bar = mon->bar) { + XUnmapWindow(dpy, bar->win); + XDestroyWindow(dpy, bar->win); + mon->bar = bar->next; + free(bar); + } free(mon); } @@ -552,6 +630,7 @@ void configurenotify(XEvent *e) { Monitor *m; + Bar *bar; Client *c; XConfigureEvent *ev = &e->xconfigure; int dirty; @@ -568,7 +647,8 @@ configurenotify(XEvent *e) for (c = m->clients; c; c = c->next) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); - XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + for (bar = m->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); } focus(NULL); arrange(NULL); @@ -631,17 +711,40 @@ configurerequest(XEvent *e) Monitor * createmon(void) { - Monitor *m; + Monitor *m, *mon; + int i, n, mi, max_bars = 2, istopbar = topbar; + + const BarRule *br; + Bar *bar; m = ecalloc(1, sizeof(Monitor)); m->tagset[0] = m->tagset[1] = 1; m->mfact = mfact; m->nmaster = nmaster; m->showbar = showbar; - m->topbar = topbar; + + for (mi = 0, mon = mons; mon; mon = mon->next, mi++); // monitor index m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); + + /* Derive the number of bars for this monitor based on bar rules */ + for (n = -1, i = 0; i < LENGTH(barrules); i++) { + br = &barrules[i]; + if (br->monitor == 'A' || br->monitor == -1 || br->monitor == mi) + n = MAX(br->bar, n); + } + + for (i = 0; i <= n && i < max_bars; i++) { + bar = ecalloc(1, sizeof(Bar)); + bar->mon = m; + bar->idx = i; + bar->next = m->bar; + bar->topbar = istopbar; + m->bar = bar; + istopbar = !istopbar; + } + return m; } @@ -696,65 +799,117 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; - int boxs = drw->fonts->h / 9; - int boxw = drw->fonts->h / 6 + 2; - unsigned int i, occ = 0, urg = 0; - Client *c; - - if (!m->showbar) - return; - - /* draw status first so it can be overdrawn by tags later */ - if (m == selmon) { /* status is only drawn on selected monitor */ - drw_setscheme(drw, scheme[SchemeNorm]); - tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */ - drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0); - } - - for (c = m->clients; c; c = c->next) { - occ |= c->tags; - if (c->isurgent) - urg |= c->tags; - } - x = 0; - for (i = 0; i < LENGTH(tags); i++) { - w = TEXTW(tags[i]); - drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i); - if (occ & 1 << i) - drw_rect(drw, x + boxs, boxs, boxw, boxw, - m == selmon && selmon->sel && selmon->sel->tags & 1 << i, - urg & 1 << i); - x += w; - } - w = blw = TEXTW(m->ltsymbol); - drw_setscheme(drw, scheme[SchemeNorm]); - x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); - - if ((w = m->ww - tw - x) > bh) { - if (m->sel) { - drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); - drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); - if (m->sel->isfloating) - drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); - } else { - drw_setscheme(drw, scheme[SchemeNorm]); - drw_rect(drw, x, 0, w, bh, 1, 1); - } - } - drw_map(drw, m->barwin, 0, 0, m->ww, bh); + Bar *bar; + for (bar = m->bar; bar; bar = bar->next) + drawbarwin(bar); } void drawbars(void) { Monitor *m; - for (m = mons; m; m = m->next) drawbar(m); } +void +drawbarwin(Bar *bar) +{ + if (!bar->win) + return; + Monitor *mon; + int r, w, mi; + int rx, lx, rw, lw; // bar size, split between left and right if a center module is added + const BarRule *br; + BarWidthArg warg = { 0 }; + BarDrawArg darg = { 0, 0 }; + + for (mi = 0, mon = mons; mon && mon != bar->mon; mon = mon->next, mi++); // get the monitor index + rw = lw = bar->bw; + rx = lx = 0; + + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, lx, 0, lw, bh, 1, 1); + for (r = 0; r < LENGTH(barrules); r++) { + br = &barrules[r]; + if (br->bar != bar->idx || br->drawfunc == NULL || (br->monitor == 'A' && bar->mon != selmon)) + continue; + if (br->monitor != 'A' && br->monitor != -1 && br->monitor != mi) + continue; + drw_setscheme(drw, scheme[SchemeNorm]); + warg.max_width = (br->alignment < BAR_ALIGN_RIGHT_LEFT ? lw : rw); + w = br->widthfunc(bar, &warg); + w = MIN(warg.max_width, w); + + if (lw <= 0) { // if left is exhausted then switch to right side, and vice versa + lw = rw; + lx = rx; + } else if (rw <= 0) { + rw = lw; + rx = lx; + } + + switch(br->alignment) { + default: + case BAR_ALIGN_NONE: + case BAR_ALIGN_LEFT_LEFT: + case BAR_ALIGN_LEFT: + bar->x[r] = lx; + if (lx == rx) { + rx += w; + rw -= w; + } + lx += w; + lw -= w; + break; + case BAR_ALIGN_LEFT_RIGHT: + case BAR_ALIGN_RIGHT: + bar->x[r] = lx + lw - w; + if (lx == rx) + rw -= w; + lw -= w; + break; + case BAR_ALIGN_LEFT_CENTER: + case BAR_ALIGN_CENTER: + bar->x[r] = lx + lw / 2 - w / 2; + if (lx == rx) { + rw = rx + rw - bar->x[r] - w; + rx = bar->x[r] + w; + } + lw = bar->x[r] - lx; + break; + case BAR_ALIGN_RIGHT_LEFT: + bar->x[r] = rx; + if (lx == rx) { + lx += w; + lw -= w; + } + rx += w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_RIGHT: + bar->x[r] = rx + rw - w; + if (lx == rx) + lw -= w; + rw -= w; + break; + case BAR_ALIGN_RIGHT_CENTER: + bar->x[r] = rx + rw / 2 - w / 2; + if (lx == rx) { + lw = lx + lw - bar->x[r] + w; + lx = bar->x[r] + w; + } + rw = bar->x[r] - rx; + break; + } + bar->w[r] = w; + darg.x = bar->x[r]; + darg.w = bar->w[r]; + br->drawfunc(bar, &darg); + } + drw_map(drw, bar->win, 0, 0, bar->bw, bar->bh); +} + void enternotify(XEvent *e) { @@ -1049,7 +1204,7 @@ manage(Window w, XWindowAttributes *wa) c->y = c->mon->my + c->mon->mh - HEIGHT(c); c->x = MAX(c->x, c->mon->mx); /* only fix client y-offset, if the client center might cover the bar */ - c->y = MAX(c->y, ((c->mon->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) + c->y = MAX(c->y, ((c->mon->bar->by == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx) && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my); c->bw = borderpx; @@ -1236,7 +1391,8 @@ propertynotify(XEvent *e) break; case XA_WM_HINTS: updatewmhints(c); - drawbars(); + if (c->isurgent) + drawbars(); break; } if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { @@ -1362,7 +1518,7 @@ restack(Monitor *m) XRaiseWindow(dpy, m->sel->win); if (m->lt[m->sellt]->arrange) { wc.stack_mode = Below; - wc.sibling = m->barwin; + wc.sibling = m->bar->win; for (c = m->stack; c; c = c->snext) if (!c->isfloating && ISVISIBLE(c)) { XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc); @@ -1705,9 +1861,11 @@ tile(Monitor *m) void togglebar(const Arg *arg) { + Bar *bar; selmon->showbar = !selmon->showbar; updatebarpos(selmon); - XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + for (bar = selmon->bar; bar; bar = bar->next) + XMoveResizeWindow(dpy, bar->win, bar->bx, bar->by, bar->bw, bar->bh); arrange(selmon); } @@ -1807,22 +1965,37 @@ unmapnotify(XEvent *e) void updatebars(void) { + Bar *bar; Monitor *m; XSetWindowAttributes wa = { .override_redirect = True, + #if BAR_ALPHA_PATCH + .background_pixel = 0, + .border_pixel = 0, + .colormap = cmap, + #else .background_pixmap = ParentRelative, + #endif // BAR_ALPHA_PATCH .event_mask = ButtonPressMask|ExposureMask }; XClassHint ch = {"dwm", "dwm"}; for (m = mons; m; m = m->next) { - if (m->barwin) - continue; - m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), - CopyFromParent, DefaultVisual(dpy, screen), - CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); - XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); - XMapRaised(dpy, m->barwin); - XSetClassHint(dpy, m->barwin, &ch); + for (bar = m->bar; bar; bar = bar->next) { + if (!bar->win) { + #if BAR_ALPHA_PATCH + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, depth, + InputOutput, visual, + CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa); + #else + bar->win = XCreateWindow(dpy, root, bar->bx, bar->by, bar->bw, bar->bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + #endif // BAR_ALPHA_PATCH + XDefineCursor(dpy, bar->win, cursor[CurNormal]->cursor); + XMapRaised(dpy, bar->win); + XSetClassHint(dpy, bar->win, &ch); + } + } } } @@ -1831,12 +2004,30 @@ updatebarpos(Monitor *m) { m->wy = m->my; m->wh = m->mh; - if (m->showbar) { - m->wh -= bh; - m->by = m->topbar ? m->wy : m->wy + m->wh; - m->wy = m->topbar ? m->wy + bh : m->wy; - } else - m->by = -bh; + int num_bars; + Bar *bar; + int y_pad = 0; + int x_pad = 0; + + for (bar = m->bar; bar; bar = bar->next) { + bar->bx = m->mx + x_pad; + bar->bw = m->ww - 2 * x_pad; + bar->bh = bh; + } + + if (!m->showbar) { + for (bar = m->bar; bar; bar = bar->next) + bar->by = -bh - y_pad; + return; + } + + for (num_bars = 0, bar = m->bar; bar; bar = bar->next, num_bars++) + if (bar->topbar) + m->wy = m->my + bh + y_pad; + m->wh = m->wh - y_pad * num_bars - bh * num_bars; + + for (bar = m->bar; bar; bar = bar->next) + bar->by = (bar->topbar ? m->wy - bh : m->wy + m->wh); } void @@ -1993,9 +2184,11 @@ updatesizehints(Client *c) void updatestatus(void) { + Monitor *m; if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) strcpy(stext, "dwm-"VERSION); - drawbar(selmon); + for (m = mons; m; m = m->next) + drawbar(m); } void @@ -2069,12 +2262,14 @@ wintomon(Window w) int x, y; Client *c; Monitor *m; + Bar *bar; if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin) - return m; + for (bar = m->bar; bar; bar = bar->next) + if (w == bar->win) + return m; if ((c = wintoclient(w))) return c->mon; return selmon; diff --git a/patch/bar_ltsymbol.c b/patch/bar_ltsymbol.c new file mode 100644 index 0000000..6676a2a --- /dev/null +++ b/patch/bar_ltsymbol.c @@ -0,0 +1,17 @@ +int +width_ltsymbol(Bar *bar, BarWidthArg *a) +{ + return TEXTW(bar->mon->ltsymbol); +} + +int +draw_ltsymbol(Bar *bar, BarDrawArg *a) +{ + return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, bar->mon->ltsymbol, 0); +} + +int +click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkLtSymbol; +} diff --git a/patch/bar_ltsymbol.h b/patch/bar_ltsymbol.h new file mode 100644 index 0000000..d9c79bf --- /dev/null +++ b/patch/bar_ltsymbol.h @@ -0,0 +1,3 @@ +static int width_ltsymbol(Bar *bar, BarWidthArg *a); +static int draw_ltsymbol(Bar *bar, BarDrawArg *a); +static int click_ltsymbol(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_status.c b/patch/bar_status.c new file mode 100644 index 0000000..7d27282 --- /dev/null +++ b/patch/bar_status.c @@ -0,0 +1,19 @@ +int +width_status(Bar *bar, BarWidthArg *a) +{ + return TEXTW(stext); +} + + +int +draw_status(Bar *bar, BarDrawArg *a) +{ + return drw_text(drw, a->x, 0, a->w, bh, lrpad / 2, stext, 0); +} + + +int +click_status(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkStatusText; +} diff --git a/patch/bar_status.h b/patch/bar_status.h new file mode 100644 index 0000000..b02a4b8 --- /dev/null +++ b/patch/bar_status.h @@ -0,0 +1,3 @@ +static int width_status(Bar *bar, BarWidthArg *a); +static int draw_status(Bar *bar, BarDrawArg *a); +static int click_status(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_tags.c b/patch/bar_tags.c new file mode 100644 index 0000000..680e1fe --- /dev/null +++ b/patch/bar_tags.c @@ -0,0 +1,55 @@ +int +width_tags(Bar *bar, BarWidthArg *a) +{ + int w, i; + + for (w = 0, i = 0; i < LENGTH(tags); i++) { + w += TEXTW(tags[i]); + } + return w; +} + +int +draw_tags(Bar *bar, BarDrawArg *a) +{ + int invert; + int w, x = a->x; + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + unsigned int i, occ = 0, urg = 0; + Client *c; + Monitor *m = bar->mon; + + for (c = m->clients; c; c = c->next) { + occ |= c->tags; + if (c->isurgent) + urg |= c->tags; + } + + for (i = 0; i < LENGTH(tags); i++) { + invert = urg & 1 << i; + w = TEXTW(tags[i]); + drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert); + if (occ & 1 << i) + drw_rect(drw, x + boxs, boxs, boxw, boxw, + m == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert); + x += w; + } + + return x; +} + +int +click_tags(Bar *bar, Arg *arg, BarClickArg *a) +{ + int i = 0, x = lrpad / 2; + + do { + x += TEXTW(tags[i]); + } while (a->rel_x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + arg->ui = 1 << i; + } + return ClkTagBar; +} diff --git a/patch/bar_tags.h b/patch/bar_tags.h new file mode 100644 index 0000000..7ac04d8 --- /dev/null +++ b/patch/bar_tags.h @@ -0,0 +1,3 @@ +static int width_tags(Bar *bar, BarWidthArg *a); +static int draw_tags(Bar *bar, BarDrawArg *a); +static int click_tags(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/bar_wintitle.c b/patch/bar_wintitle.c new file mode 100644 index 0000000..3c11b75 --- /dev/null +++ b/patch/bar_wintitle.c @@ -0,0 +1,31 @@ +int +width_wintitle(Bar *bar, BarWidthArg *a) +{ + return a->max_width; +} + +int +draw_wintitle(Bar *bar, BarDrawArg *a) +{ + int boxs = drw->fonts->h / 9; + int boxw = drw->fonts->h / 6 + 2; + int x = a->x, w = a->w; + Monitor *m = bar->mon; + + if (m->sel) { + drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]); + drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0); + if (m->sel->isfloating) + drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0); + } else { + drw_setscheme(drw, scheme[SchemeNorm]); + drw_rect(drw, x, 0, w, bh, 1, 1); + } + return x + w; +} + +int +click_wintitle(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkWinTitle; +} diff --git a/patch/bar_wintitle.h b/patch/bar_wintitle.h new file mode 100644 index 0000000..266404c --- /dev/null +++ b/patch/bar_wintitle.h @@ -0,0 +1,3 @@ +static int width_wintitle(Bar *bar, BarWidthArg *a); +static int draw_wintitle(Bar *bar, BarDrawArg *a); +static int click_wintitle(Bar *bar, Arg *arg, BarClickArg *a); diff --git a/patch/include.c b/patch/include.c new file mode 100644 index 0000000..d422f56 --- /dev/null +++ b/patch/include.c @@ -0,0 +1,5 @@ +/* Bar functionality */ +#include "bar_ltsymbol.c" +#include "bar_status.c" +#include "bar_tags.c" +#include "bar_wintitle.c" \ No newline at end of file diff --git a/patch/include.h b/patch/include.h new file mode 100644 index 0000000..5f9a3fe --- /dev/null +++ b/patch/include.h @@ -0,0 +1,5 @@ +/* Bar functionality */ +#include "bar_ltsymbol.h" +#include "bar_status.h" +#include "bar_tags.h" +#include "bar_wintitle.h" \ No newline at end of file -- 2.19.1 From 54674a344665e893a72a81319b7caf9226a2180f Mon Sep 17 00:00:00 2001 From: Bakkeby Date: Mon, 10 Jan 2022 14:13:41 +0100 Subject: [PATCH 2/2] Adding wintitleactions patch --- config.def.h | 4 ++ dwm.c | 24 +++++----- patch/bar_wintitleactions.c | 90 +++++++++++++++++++++++++++++++++++++ patch/bar_wintitleactions.h | 7 +++ patch/include.c | 3 +- patch/include.h | 3 +- 6 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 patch/bar_wintitleactions.c create mode 100644 patch/bar_wintitleactions.h diff --git a/config.def.h b/config.def.h index f870c41..b8cbed0 100644 --- a/config.def.h +++ b/config.def.h @@ -16,6 +16,7 @@ static const char *colors[][3] = { /* fg bg border */ [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, [SchemeSel] = { col_gray4, col_cyan, col_cyan }, + [SchemeHid] = { col_cyan, col_gray1, col_cyan }, }; /* tagging */ @@ -93,6 +94,7 @@ static Key keys[] = { { MODKEY, XK_l, setmfact, {.f = +0.05} }, { MODKEY, XK_Return, zoom, {0} }, { MODKEY, XK_Tab, view, {0} }, + { MODKEY|ControlMask, XK_z, showhideclient, {0} }, { MODKEY|ShiftMask, XK_c, killclient, {0} }, { MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, { MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, @@ -123,7 +125,9 @@ static Button buttons[] = { /* click event mask button function argument */ { ClkLtSymbol, 0, Button1, setlayout, {0} }, { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, + { ClkWinTitle, 0, Button1, togglewin, {0} }, { ClkWinTitle, 0, Button2, zoom, {0} }, + { ClkWinTitle, 0, Button3, showhideclient, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, diff --git a/dwm.c b/dwm.c index 86763d8..5de793d 100644 --- a/dwm.c +++ b/dwm.c @@ -60,7 +60,7 @@ /* enums */ enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ -enum { SchemeNorm, SchemeSel }; /* color schemes */ +enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ @@ -524,7 +524,7 @@ buttonpress(XEvent *e) for (i = 0; i < LENGTH(buttons); i++) { if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) { - buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); + buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); } } } @@ -996,16 +996,16 @@ focusstack(const Arg *arg) if (!selmon->sel || (selmon->sel->isfullscreen && lockfullscreen)) return; if (arg->i > 0) { - for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); + for (c = selmon->sel->next; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); if (!c) - for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); + for (c = selmon->clients; c && (!ISVISIBLE(c) || (arg->i == 1 && HIDDEN(c))); c = c->next); } else { for (i = selmon->clients; i != selmon->sel; i = i->next) - if (ISVISIBLE(i)) + if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) c = i; if (!c) for (; i; i = i->next) - if (ISVISIBLE(i)) + if (ISVISIBLE(i) && !(arg->i == -1 && HIDDEN(i))) c = i; } if (c) { @@ -1226,12 +1226,14 @@ manage(Window w, XWindowAttributes *wa) XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, (unsigned char *) &(c->win), 1); XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ - setclientstate(c, NormalState); + if (!HIDDEN(c)) + setclientstate(c, NormalState); if (c->mon == selmon) unfocus(selmon->sel, 0); c->mon->sel = c; arrange(c->mon); - XMapWindow(dpy, c->win); + if (!HIDDEN(c)) + XMapWindow(dpy, c->win); focus(NULL); } @@ -1354,7 +1356,7 @@ movemouse(const Arg *arg) Client * nexttiled(Client *c) { - for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); + for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); return c; } @@ -2314,7 +2316,9 @@ xerrorstart(Display *dpy, XErrorEvent *ee) void zoom(const Arg *arg) { - Client *c = selmon->sel; + Client *c = (Client*)arg->v; + if (!c) + c = selmon->sel; if (!selmon->lt[selmon->sellt]->arrange || (selmon->sel && selmon->sel->isfloating)) diff --git a/patch/bar_wintitleactions.c b/patch/bar_wintitleactions.c new file mode 100644 index 0000000..a9ae3e1 --- /dev/null +++ b/patch/bar_wintitleactions.c @@ -0,0 +1,90 @@ +void +hide(Client *c) { + + Client *n; + if (!c || HIDDEN(c)) + return; + + Window w = c->win; + static XWindowAttributes ra, ca; + + // more or less taken directly from blackbox's hide() function + XGrabServer(dpy); + XGetWindowAttributes(dpy, root, &ra); + XGetWindowAttributes(dpy, w, &ca); + // prevent UnmapNotify events + XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); + XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); + XUnmapWindow(dpy, w); + setclientstate(c, IconicState); + XSelectInput(dpy, root, ra.your_event_mask); + XSelectInput(dpy, w, ca.your_event_mask); + XUngrabServer(dpy); + + if (c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) { + for (n = c->snext; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); + if (!n) + for (n = c->mon->stack; n && (!ISVISIBLE(n) || HIDDEN(n)); n = n->snext); + } else { + n = nexttiled(c); + if (!n) + n = prevtiled(c); + } + focus(n); + arrange(c->mon); +} + +void +show(Client *c) +{ + if (!c || !HIDDEN(c)) + return; + + XMapWindow(dpy, c->win); + setclientstate(c, NormalState); + arrange(c->mon); +} + +void +togglewin(const Arg *arg) +{ + Client *c = (Client*)arg->v; + if (!c) + return; + if (c == selmon->sel) + hide(c); + else { + if (HIDDEN(c)) + show(c); + focus(c); + restack(c->mon); + } +} + +Client * +prevtiled(Client *c) +{ + Client *p, *i; + for (p = NULL, i = c->mon->clients; c && i != c; i = i->next) + if (ISVISIBLE(i) && !HIDDEN(i)) + p = i; + return p; +} + +void +showhideclient(const Arg *arg) +{ + Client *c = (Client*)arg->v; + if (!c) + c = selmon->sel; + if (!c) + return; + + if (HIDDEN(c)) { + show(c); + focus(c); + restack(c->mon); + } else { + hide(c); + } +} \ No newline at end of file diff --git a/patch/bar_wintitleactions.h b/patch/bar_wintitleactions.h new file mode 100644 index 0000000..e37201e --- /dev/null +++ b/patch/bar_wintitleactions.h @@ -0,0 +1,7 @@ +#define HIDDEN(C) ((getstate(C->win) == IconicState)) + +static void hide(Client *c); +static void show(Client *c); +static void togglewin(const Arg *arg); +static Client * prevtiled(Client *c); +static void showhideclient(const Arg *arg); \ No newline at end of file diff --git a/patch/include.c b/patch/include.c index d422f56..8008552 100644 --- a/patch/include.c +++ b/patch/include.c @@ -2,4 +2,5 @@ #include "bar_ltsymbol.c" #include "bar_status.c" #include "bar_tags.c" -#include "bar_wintitle.c" \ No newline at end of file +#include "bar_wintitle.c" +#include "bar_wintitleactions.c" \ No newline at end of file diff --git a/patch/include.h b/patch/include.h index 5f9a3fe..be075b5 100644 --- a/patch/include.h +++ b/patch/include.h @@ -2,4 +2,5 @@ #include "bar_ltsymbol.h" #include "bar_status.h" #include "bar_tags.h" -#include "bar_wintitle.h" \ No newline at end of file +#include "bar_wintitle.h" +#include "bar_wintitleactions.h" \ No newline at end of file -- 2.19.1