Skip to content

Instantly share code, notes, and snippets.

@udiboy1209
Created May 7, 2018 10:59
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save udiboy1209/c4a47c3bb1bbfa5498032dee34bc144a to your computer and use it in GitHub Desktop.
Save udiboy1209/c4a47c3bb1bbfa5498032dee34bc144a to your computer and use it in GitHub Desktop.
DWM powerline statusbar, gaps, padding, no vacant tags, all titles patch
diff --git a/config.def.h b/config.def.h
index a9ac303..51e2ab0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,7 @@
/* appearance */
static const unsigned int borderpx = 1; /* border pixel of windows */
+static const unsigned int gappx = 1; /* gap pixel between windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
diff --git a/drw.c b/drw.c
index c638323..7e794b1 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)
@@ -222,6 +223,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)
{
@@ -364,6 +374,30 @@ 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)
+ 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 },
+ };
+
+ XSetForeground(drw->dpy, drw->gc, drw->scheme[ColBg].pixel);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ 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..fc4f3bb 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 c98678d..2ad914e 100644
--- a/dwm.c
+++ b/dwm.c
@@ -59,7 +59,7 @@
/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { SchemeNorm, SchemeSel, SchemeTitle, SchemeTitleSel }; /* color schemes */
enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
@@ -162,6 +162,7 @@ static void detach(Client *c);
static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
+static int drawstatus(Monitor *m);
static void drawbars(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
@@ -239,7 +240,7 @@ 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, plw, blw = 0; /* bar geometry */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
@@ -263,6 +264,7 @@ static Atom wmatom[WMLast], netatom[NetLast];
static int running = 1;
static Cur *cursor[CurLast];
static Clr **scheme;
+static Clr **statusscheme;
static Display *dpy;
static Drw *drw;
static Monitor *mons, *selmon;
@@ -430,10 +432,16 @@ buttonpress(XEvent *e)
focus(NULL);
}
if (ev->window == selmon->barwin) {
- i = x = 0;
- do
- x += TEXTW(tags[i]);
- while (ev->x >= x && ++i < LENGTH(tags));
+ i = 0; x = plw;
+ unsigned int occ = 0;
+ for(c = m->clients; c; c = c->next)
+ occ |= c->tags;
+ do {
+ /* do not reserve space for vacant tags */
+ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
+ x += TEXTW(tags[i]) + plw;
+ } while (ev->x >= x && ++i < LENGTH(tags));
if (i < LENGTH(tags)) {
click = ClkTagBar;
arg.ui = 1 << i;
@@ -695,51 +703,117 @@ dirtomon(int dir)
void
drawbar(Monitor *m)
{
- int x, w, sw = 0;
- int boxs = drw->fonts->h / 9;
- int boxw = drw->fonts->h / 6 + 2;
- unsigned int i, occ = 0, urg = 0;
+ int x, w, wt, sw = 0;
+ unsigned int i, occ = 0, urg = 0, n = 0;
+ plw = drw->fonts->h / 2 + 1;
Client *c;
+ Clr *prevscheme, *nxtscheme;
/* 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]);
- sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
- drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0);
+ sw = drawstatus(m);
}
for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c)) n++;
occ |= c->tags;
if (c->isurgent)
urg |= c->tags;
}
x = 0;
+
+ prevscheme = scheme[SchemeNorm];
for (i = 0; i < LENGTH(tags); i++) {
+ /* do not draw vacant tags */
+ if(!(occ & 1 << i || m->tagset[m->seltags] & 1 << i))
+ continue;
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;
+ drw_settrans(drw, prevscheme, (nxtscheme = scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]));
+ drw_arrow(drw, x, 0, plw, bh, 1, 0);
+ x += plw;
+
+ drw_setscheme(drw, nxtscheme);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ x += w;
+
+ prevscheme = nxtscheme;
}
+ nxtscheme = scheme[SchemeNorm];
+
+ drw_settrans(drw, prevscheme, nxtscheme);
+ drw_arrow(drw, x, 0, plw, bh, 1, 0);
+ x += plw;
+
w = blw = TEXTW(m->ltsymbol);
drw_setscheme(drw, scheme[SchemeNorm]);
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+
+ if ((m->ww - sw - x) > bh && n > 0) {
+ wt = (m->ww - sw - x) / n - 2 * plw;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c)) continue; /* only show titles of windows on current tag */
- if ((w = m->ww - sw - 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);
+ drw_setscheme(drw, c == m->sel ? scheme[SchemeTitleSel] : scheme[SchemeTitle]);
+ drw_text(drw, x + plw, 0, wt, bh, lrpad / 2, c->name, 0);
+
+ drw_settrans(drw, c == m->sel ? scheme[SchemeTitleSel] : scheme[SchemeTitle], scheme[SchemeNorm]);
+ drw_arrow(drw, x, 0, plw, bh, 0, 1);
+ drw_arrow(drw, x + wt + plw, 0, plw, bh, 1, 1);
+
+ x += wt + 2 * plw;
+ }
+ } else { /* when empty or not enough space to draw, clear out the title space */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+ drw_rect(drw, x, 0, m->ww - sw - x, bh, 1, 1);
+ }
+ drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+}
+
+int
+drawstatus(Monitor* m)
+{
+ char status[256];
+ int i, n = strlen(stext), cn = 0;
+ int x = m->ww, w = 0;
+ 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 == '|') { /* 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 == '\\' ? 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 == '\\' ? 1 : 0, bp == '<' ? 0 : 1);
+ drw_rect(drw, x - 2 * plw, 0, plw, bh, 1, 1);
+ x -= plw * 2;
+ }
+
+ return m->ww - x;
}
void
@@ -1112,7 +1186,7 @@ monocle(Monitor *m)
if (n > 0) /* override layout symbol */
snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
for (c = nexttiled(m->clients); c; c = nexttiled(c->next))
- resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, 0);
+ resize(c, m->wx + padpx, m->wy + padpx, m->ww - 2 * padpx - 2 * c->bw, m->wh - 2 * padpx - 2 * c->bw, 0);
}
void
@@ -1570,6 +1644,9 @@ 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++)
+ statusscheme[i] = drw_scm_create(drw, statuscolors[i], 3);
/* init bars */
updatebars();
updatestatus();
@@ -1673,26 +1750,29 @@ tagmon(const Arg *arg)
void
tile(Monitor *m)
{
- unsigned int i, n, h, mw, my, ty;
+ unsigned int i, n, h, r, g = 0, mw, my, ty;
Client *c;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
if (n == 0)
return;
- if (n > m->nmaster)
- mw = m->nmaster ? m->ww * m->mfact : 0;
+ if(n > m->nmaster)
+ mw = m->nmaster ? (m->ww - (g = gappx) - 2*padpx) * m->mfact : 0;
else
- mw = m->ww;
- for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
- if (i < m->nmaster) {
- h = (m->wh - my) / (MIN(n, m->nmaster) - i);
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
- my += HEIGHT(c);
- } else {
- h = (m->wh - ty) / (n - i);
- resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0);
- ty += HEIGHT(c);
+ mw = m->ww - 2*padpx;
+ for(i = 0, my = ty = padpx, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if(i < m->nmaster) {
+ r = MIN(n, m->nmaster) - i;
+ h = (m->wh - my - gappx * (r - 1) - 2*padpx) / r;
+ resize(c, m->wx + padpx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
+ my += HEIGHT(c) + gappx;
+ }
+ else {
+ r = n - i;
+ h = (m->wh - ty - gappx * (r - 1) - 2*padpx) / r;
+ resize(c, m->wx + padpx + mw + g, m->wy + ty, m->ww - 2*padpx - mw - g - (2*c->bw), h - (2*c->bw), False);
+ ty += HEIGHT(c) + gappx;
}
}
@HackedPixels
Copy link

First of all, great patch!
But, this patch fails against a clean dwm-6.1.
dwm.c does not get applied.

Also the code seems broken because ColBg, ColFg are nowhere defined.
Would much appreciate an updated version of this gist!

@udiboy1209
Copy link
Author

@HackedPixels this patch doesn't apply to dwm-6.1 and I apologize for the confusing naming. The patch applies cleanly to this commit in the development repo.

Also a recent bug has cropped up in statusbar and here is a fix which will apply over this patch.

@Derevi
Copy link

Derevi commented May 6, 2020

when you are focused on a window, the selected item in the bar also changes color. but when changing tags/desktops the color does not refresh in the last few pixels at the end. did you manage to resolve this?

I have manually applied it to the current dwm 6.2 if you want my diff

@udiboy1209
Copy link
Author

The fix I had linked was for that bug I guess.

When drawing the triangle, the background rectangle draw does not take effect for some reason. The hack I had used was to draw two triangles instead of drawing one triangle over one rectangle. Will need to find this fix again though. Looks like the pastebin expired.

Triangle over rectangle
*----*
|   *|
|  /||
| / ||
|*--*|
*----*

Two triangles
*---*
|  /*
| //|
|// |
*/  |
*---*

@Derevi
Copy link

Derevi commented May 10, 2020

That makes sense. post it if you find it. When you do I can patch it to the current version of dwm, and send you the diff to post if you want.

@udiboy1209
Copy link
Author

@Derevi you can refer to the updated patch here for powerline statusbar: https://gitlab.com/udiboy1209-suckless/dwm/-/commit/071f5063e8ac4280666828179f92788d893eea40

@ZaheenJ
Copy link

ZaheenJ commented Jul 17, 2020

I manually applied your powerline patch from gitlab, but now the status won't show. Other than that, this patch is awesome! Thanks for sharing it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment