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 97343b7b17a3bdc111768f026e8532b93143d409 Mon Sep 17 00:00:00 2001 From: Bakkeby Date: Mon, 10 Jan 2022 14:08:58 +0100 Subject: [PATCH 2/2] Adding powerline module --- config.def.h | 10 ++- drw.c | 41 +++++++++++ drw.h | 2 + dwm.c | 7 ++ patch/bar_powerline_status.c | 121 +++++++++++++++++++++++++++++++++ patch/bar_powerline_status.h | 11 +++ patch/bar_powerline_tags.c | 127 +++++++++++++++++++++++++++++++++++ patch/bar_powerline_tags.h | 3 + patch/include.c | 8 ++- patch/include.h | 8 ++- 10 files changed, 330 insertions(+), 8 deletions(-) create mode 100644 patch/bar_powerline_status.c create mode 100644 patch/bar_powerline_status.h create mode 100644 patch/bar_powerline_tags.c create mode 100644 patch/bar_powerline_tags.h diff --git a/config.def.h b/config.def.h index f870c41..1187340 100644 --- a/config.def.h +++ b/config.def.h @@ -18,6 +18,12 @@ static const char *colors[][3] = { [SchemeSel] = { col_gray4, col_cyan, col_cyan }, }; +static const char *statuscolors[][3] = { + /* fg bg border */ + [SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, + [SchemeSel] = { col_gray4, col_cyan, col_cyan }, +}; + /* tagging */ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; @@ -45,9 +51,9 @@ static const Rule rules[] = { */ 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_pwrl_tags, draw_pwrl_tags, click_pwrl_tags, "powerline_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" }, + { 'A', 0, BAR_ALIGN_RIGHT, width_pwrl_status, draw_pwrl_status, click_pwrl_status, "powerline_status" }, { -1, 0, BAR_ALIGN_NONE, width_wintitle, draw_wintitle, click_wintitle, "wintitle" }, }; diff --git a/drw.c b/drw.c index 4cdbcbe..522fc79 100644 --- a/drw.c +++ b/drw.c @@ -15,6 +15,7 @@ static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0} static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; +Clr transcheme[3]; static long utf8decodebyte(const char c, size_t *i) @@ -236,6 +237,15 @@ drw_setscheme(Drw *drw, Clr *scm) drw->scheme = scm; } +void +drw_settrans(Drw *drw, Clr *psc, Clr *nsc) +{ + if (drw) { + transcheme[0] = psc[ColBg]; transcheme[1] = nsc[ColBg]; transcheme[2] = psc[ColBorder]; + drw->scheme = transcheme; + } +} + void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert) { @@ -379,6 +389,37 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp return x + (render ? w : 0); } +void +drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash) +{ + if (!drw || !drw->scheme) + return; + + /* direction=1 draws right arrow */ + x = direction ? x : x + w; + w = direction ? w : -w; + /* slash=1 draws slash instead of arrow */ + unsigned int hh = slash ? (direction ? 0 : h) : h/2; + + XPoint points[] = { + {x , y }, + {x + w, y + hh }, + {x , y + h }, + }; + + XPoint bg[] = { + {x , y }, + {x + w, y }, + {x + w, y + h}, + {x , y + h}, + }; + + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel); + XFillPolygon(drw->dpy, drw->drawable, drw->gc, bg, 4, Convex, CoordModeOrigin); + XSetForeground(drw->dpy, drw->gc, drw->scheme[ColFg].pixel); + XFillPolygon(drw->dpy, drw->drawable, drw->gc, points, 3, Nonconvex, CoordModeOrigin); +} + void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) { diff --git a/drw.h b/drw.h index 4bcd5ad..4a42557 100644 --- a/drw.h +++ b/drw.h @@ -48,10 +48,12 @@ void drw_cur_free(Drw *drw, Cur *cursor); /* Drawing context manipulation */ void drw_setfontset(Drw *drw, Fnt *set); void drw_setscheme(Drw *drw, Clr *scm); +void drw_settrans(Drw *drw, Clr *psc, Clr *nsc); /* Drawing functions */ void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert); int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert); +void drw_arrow(Drw *drw, int x, int y, unsigned int w, unsigned int h, int direction, int slash); /* Map functions */ void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h); diff --git a/dwm.c b/dwm.c index 86763d8..48905e3 100644 --- a/dwm.c +++ b/dwm.c @@ -1730,6 +1730,13 @@ setup(void) scheme = ecalloc(LENGTH(colors), sizeof(Clr *)); for (i = 0; i < LENGTH(colors); i++) scheme[i] = drw_scm_create(drw, colors[i], 3); + statusscheme = ecalloc(LENGTH(statuscolors), sizeof(Clr *)); + for (i = 0; i < LENGTH(statuscolors); i++) + #if BAR_ALPHA_PATCH + statusscheme[i] = drw_scm_create(drw, statuscolors[i], alphas[0], ColCount); + #else + statusscheme[i] = drw_scm_create(drw, statuscolors[i], 3); + #endif // BAR_ALPHA_PATCH /* init bars */ updatebars(); updatestatus(); diff --git a/patch/bar_powerline_status.c b/patch/bar_powerline_status.c new file mode 100644 index 0000000..3e2ee6a --- /dev/null +++ b/patch/bar_powerline_status.c @@ -0,0 +1,121 @@ +static Clr **statusscheme; + +int +width_pwrl_status(Bar *bar, BarWidthArg *a) +{ + #if BAR_STATUSCMD_PATCH + return widthpowerlinestatus(rawstext); + #else + return widthpowerlinestatus(stext); + #endif // BAR_STATUSCMD_PATCH +} + +#if BAR_EXTRASTATUS_PATCH +int +width_pwrl_status_es(Bar *bar, BarWidthArg *a) +{ + #if BAR_STATUSCMD_PATCH + return widthpowerlinestatus(rawestext); + #else + return widthpowerlinestatus(estext); + #endif // BAR_STATUSCMD_PATCH +} +#endif // BAR_EXTRASTATUS_PATCH + +int +draw_pwrl_status(Bar *bar, BarDrawArg *a) +{ + #if BAR_STATUSCMD_PATCH + return drawpowerlinestatus(a->x + a->w, rawstext); + #else + return drawpowerlinestatus(a->x + a->w, stext); + #endif // BAR_STATUSCMD_PATCH +} + +#if BAR_EXTRASTATUS_PATCH +int +draw_pwrl_status_es(Bar *bar, BarDrawArg *a) +{ + #if BAR_STATUSCMD_PATCH + return drawpowerlinestatus(a->x + a->w, rawestext); + #else + return drawpowerlinestatus(a->x + a->w, estext); + #endif // BAR_STATUSCMD_PATCH +} +#endif // BAR_EXTRASTATUS_PATCH + +int +click_pwrl_status(Bar *bar, Arg *arg, BarClickArg *a) +{ + return ClkStatusText; +} + +int +widthpowerlinestatus(char *stext) +{ + char status[512]; + int w = 0, i, n = strlen(stext); + int plw = drw->fonts->h / 2 + 1; + char *bs, bp = '|'; + strcpy(status, stext); + + for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) { + if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */ + if (bp != '|') + w += plw; + w += TEXTW(bs+2); + bp = *bs; + *bs = 0; + } + } + if (bp != '|') + w += plw * 2; + + return w; +} + +int +drawpowerlinestatus(int xpos, char *stext) +{ + char status[512]; + int i, n = strlen(stext), cn = 0; + int x = xpos, w = 0; + int plw = drw->fonts->h / 2 + 1; + char *bs, bp = '|'; + Clr *prevscheme = statusscheme[0], *nxtscheme; + strcpy(status, stext); + + for (i = n, bs = &status[n-1]; i >= 0; i--, bs--) { + if (*bs == '<' || *bs == '/' || *bs == '\\' || *bs == '>' || *bs == '|') { /* block start */ + cn = ((int) *(bs+1)) - 1; + + if (cn < LENGTH(statuscolors)) { + drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[cn])); + } else { + drw_settrans(drw, prevscheme, (nxtscheme = statusscheme[0])); + } + + if (bp != '|') { + drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1); + x -= plw; + } + + drw_setscheme(drw, nxtscheme); + w = TEXTW(bs+2); + drw_text(drw, x - w, 0, w, bh, lrpad / 2, bs+2, 0); + x -= w; + + bp = *bs; + *bs = 0; + prevscheme = nxtscheme; + } + } + if (bp != '|') { + drw_settrans(drw, prevscheme, scheme[SchemeNorm]); + drw_arrow(drw, x - plw, 0, plw, bh, bp == '\\' || bp == '>' ? 1 : 0, bp == '<' ? 0 : 1); + drw_rect(drw, x - 2 * plw, 0, plw, bh, 1, 1); + x -= plw * 2; + } + + return xpos - x; +} \ No newline at end of file diff --git a/patch/bar_powerline_status.h b/patch/bar_powerline_status.h new file mode 100644 index 0000000..2ff5ad2 --- /dev/null +++ b/patch/bar_powerline_status.h @@ -0,0 +1,11 @@ +static int width_pwrl_status(Bar *bar, BarWidthArg *a); +#if BAR_EXTRASTATUS_PATCH +static int width_pwrl_status_es(Bar *bar, BarWidthArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int draw_pwrl_status(Bar *bar, BarDrawArg *a); +#if BAR_EXTRASTATUS_PATCH +static int draw_pwrl_status_es(Bar *bar, BarDrawArg *a); +#endif // BAR_EXTRASTATUS_PATCH +static int click_pwrl_status(Bar *bar, Arg *arg, BarClickArg *a); +static int drawpowerlinestatus(int x, char *stext); +static int widthpowerlinestatus(char *stext); \ No newline at end of file diff --git a/patch/bar_powerline_tags.c b/patch/bar_powerline_tags.c new file mode 100644 index 0000000..a85559b --- /dev/null +++ b/patch/bar_powerline_tags.c @@ -0,0 +1,127 @@ +int +width_pwrl_tags(Bar *bar, BarWidthArg *a) +{ + int w, i; + int plw = drw->fonts->h / 2 + 1; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + for (w = 0, i = 0; i < LENGTH(tags); i++) { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + #if BAR_ALTERNATIVE_TAGS_PATCH + w += selmon->alttag ? TEXTW(tagsalt[i]) : TEXTW(tags[i]) + plw; + #else + w += TEXTW(tags[i]) + plw; + #endif // BAR_ALTERNATIVE_TAGS_PATCH + } + return w + lrpad; +} + +int +draw_pwrl_tags(Bar *bar, BarDrawArg *a) +{ + int x, w; + int invert; + int plw = drw->fonts->h / 2 + 1; + unsigned int i, occ = 0, urg = 0; + Client *c; + Clr *prevscheme, *nxtscheme; + #if !BAR_HIDEVACANTTAGS_PATCH + #if !BAR_ACTIVETAGINDICATORBAR_PATCH && !BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH + int boxs = drw->fonts->h / 9; + #endif // BAR_ACTIVETAGINDICATORBAR_PATCH | BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH + int boxw = drw->fonts->h / 6 + 2; + #endif // BAR_HIDEVACANTTAGS_PATCH + + for (c = bar->mon->clients; c; c = c->next) { + #if BAR_HIDEVACANTTAGS_PATCH + occ |= c->tags == 255 ? 0 : c->tags; + #else + occ |= c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + if (c->isurgent) + urg |= c->tags; + } + x = a->x; + prevscheme = scheme[SchemeNorm]; + for (i = 0; i < LENGTH(tags); i++) { + #if BAR_HIDEVACANTTAGS_PATCH + /* do not draw vacant tags */ + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + #if URGENTBORDER_PATCH + invert = 0; + #else + invert = urg & 1 << i; + #endif // URGENTBORDER_PATCH + w = TEXTW(tags[i]); + drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm])); + #if BAR_POWERLINE_TAGS_SLASH_PATCH + drw_arrow(drw, x, 0, plw, bh, 1, 1); + #else + drw_arrow(drw, x, 0, plw, bh, 1, 1); + #endif // BAR_POWERLINE_TAGS_SLASH_PATCH + x += plw; + drw_setscheme(drw, nxtscheme); + drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], invert); + #if !BAR_HIDEVACANTTAGS_PATCH + if (occ & 1 << i) + #if BAR_ACTIVETAGINDICATORBAR_PATCH + drw_rect(drw, x + boxw, 0, w - ( 2 * boxw + 1), boxw, + #elif BAR_ACTIVETAGINDICATORBAR_ALT1_PATCH + drw_rect(drw, x + boxw, bh - boxw/2, w - ( 2 * boxw + 1), boxw/2, + #else + drw_rect(drw, x + boxs, boxs, boxw, boxw, + #endif // BAR_ACTIVETAGINDICATORBAR_PATCH + bar->mon == selmon && selmon->sel && selmon->sel->tags & 1 << i, invert); + #endif // BAR_HIDEVACANTTAGS_PATCH + x += w; + prevscheme = nxtscheme; + } + nxtscheme = scheme[SchemeNorm]; + + drw_settrans(drw, prevscheme, nxtscheme); + #if BAR_POWERLINE_TAGS_SLASH_PATCH + drw_arrow(drw, x, 0, plw, bh, 1, 1); + #else + drw_arrow(drw, x, 0, plw, bh, 1, 0); + #endif // BAR_POWERLINE_TAGS_SLASH_PATCH + return a->x + a->w; +} + +int +click_pwrl_tags(Bar *bar, Arg *arg, BarClickArg *a) +{ + int i = 0, x = lrpad / 2; + int plw = drw->fonts->h / 2 + 1; + #if BAR_HIDEVACANTTAGS_PATCH + Client *c; + unsigned int occ = 0; + for (c = bar->mon->clients; c; c = c->next) + occ |= c->tags == 255 ? 0 : c->tags; + #endif // BAR_HIDEVACANTTAGS_PATCH + + do { + #if BAR_HIDEVACANTTAGS_PATCH + if (!(occ & 1 << i || bar->mon->tagset[bar->mon->seltags] & 1 << i)) + continue; + #endif // BAR_HIDEVACANTTAGS_PATCH + #if BAR_ALTERNATIVE_TAGS_PATCH + x += selmon->alttag ? TEXTW(tagsalt[i]) : TEXTW(tags[i]) + plw; + #else + x += TEXTW(tags[i]) + plw; + #endif + } while (a->rel_x >= x && ++i < LENGTH(tags)); + if (i < LENGTH(tags)) { + arg->ui = 1 << i; + } + return ClkTagBar; +} \ No newline at end of file diff --git a/patch/bar_powerline_tags.h b/patch/bar_powerline_tags.h new file mode 100644 index 0000000..b1e0389 --- /dev/null +++ b/patch/bar_powerline_tags.h @@ -0,0 +1,3 @@ +static int width_pwrl_tags(Bar *bar, BarWidthArg *a); +static int draw_pwrl_tags(Bar *bar, BarDrawArg *a); +static int click_pwrl_tags(Bar *bar, Arg *arg, BarClickArg *a); \ No newline at end of file diff --git a/patch/include.c b/patch/include.c index d422f56..48ce1cb 100644 --- a/patch/include.c +++ b/patch/include.c @@ -1,5 +1,7 @@ /* Bar functionality */ #include "bar_ltsymbol.c" -#include "bar_status.c" -#include "bar_tags.c" -#include "bar_wintitle.c" \ No newline at end of file +//#include "bar_status.c" +//#include "bar_tags.c" +#include "bar_wintitle.c" +#include "bar_powerline_tags.c" +#include "bar_powerline_status.c" \ No newline at end of file diff --git a/patch/include.h b/patch/include.h index 5f9a3fe..b313ca4 100644 --- a/patch/include.h +++ b/patch/include.h @@ -1,5 +1,7 @@ /* Bar functionality */ #include "bar_ltsymbol.h" -#include "bar_status.h" -#include "bar_tags.h" -#include "bar_wintitle.h" \ No newline at end of file +//#include "bar_status.h" +//#include "bar_tags.h" +#include "bar_wintitle.h" +#include "bar_powerline_tags.h" +#include "bar_powerline_status.h" \ No newline at end of file -- 2.19.1