diff --git a/config.def.h b/config.def.h --- a/config.def.h +++ b/config.def.h @@ -3,8 +3,10 @@ /* appearance */ static const unsigned int borderpx = 1; /* border pixel of 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 */ +static const int showbar = 1; /* 0 means no standard bar */ +static const int topbar = 1; /* 0 means standard bar at bottom */ +static const int extrabar = 1; /* 0 means no extra bar */ +static const char statussep = ';'; /* separator between statuses */ static const char *fonts[] = { "monospace:size=10" }; static const char dmenufont[] = "monospace:size=10"; static const char col_gray1[] = "#222222"; @@ -65,6 +67,7 @@ static Key keys[] = { { MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, + { MODKEY|ShiftMask, XK_b, toggleextrabar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } }, @@ -105,6 +108,9 @@ static Button buttons[] = { { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, { ClkWinTitle, 0, Button2, zoom, {0} }, { ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, + { ClkExBarLeftStatus, 0, Button2, spawn, {.v = termcmd } }, + { ClkExBarMiddle, 0, Button2, spawn, {.v = termcmd } }, + { ClkExBarRightStatus, 0, Button2, spawn, {.v = termcmd } }, { ClkClientWin, MODKEY, Button1, movemouse, {0} }, { ClkClientWin, MODKEY, Button2, togglefloating, {0} }, { ClkClientWin, MODKEY, Button3, resizemouse, {0} }, diff --git a/dwm.c b/dwm.c --- a/dwm.c +++ b/dwm.c @@ -65,6 +65,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck, NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkExBarLeftStatus, ClkExBarMiddle, ClkExBarRightStatus, ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ typedef union { @@ -117,6 +118,7 @@ struct Monitor { int nmaster; int num; int by; /* bar geometry */ + int eby; /* extra bar geometry */ int mx, my, mw, mh; /* screen size */ int wx, wy, ww, wh; /* window area */ unsigned int seltags; @@ -124,11 +126,13 @@ struct Monitor { unsigned int tagset[2]; int showbar; int topbar; + int extrabar; Client *clients; Client *sel; Client *stack; Monitor *next; Window barwin; + Window extrabarwin; const Layout *lt[2]; }; @@ -211,6 +215,7 @@ static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); static void togglebar(const Arg *arg); +static void toggleextrabar(const Arg *arg); static void togglefloating(const Arg *arg); static void toggletag(const Arg *arg); static void toggleview(const Arg *arg); @@ -238,6 +243,8 @@ static void zoom(const Arg *arg); /* variables */ static const char broken[] = "broken"; static char stext[256]; +static char estextl[256]; +static char estextr[256]; static int screen; static int sw, sh; /* X display screen geometry width, height */ static int bh, blw = 0; /* bar geometry */ @@ -444,6 +451,13 @@ buttonpress(XEvent *e) click = ClkStatusText; else click = ClkWinTitle; + } else if (ev->window == selmon->extrabarwin) { + if (ev->x < (int)TEXTW(estextl)) + click = ClkExBarLeftStatus; + else if (ev->x > selmon->ww - (int)TEXTW(estextr)) + click = ClkExBarRightStatus; + else + click = ClkExBarMiddle; } else if ((c = wintoclient(ev->window))) { focus(c); restack(selmon); @@ -506,7 +520,9 @@ cleanupmon(Monitor *mon) m->next = mon->next; } XUnmapWindow(dpy, mon->barwin); + XUnmapWindow(dpy, mon->extrabarwin); XDestroyWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->extrabarwin); free(mon); } @@ -569,6 +585,7 @@ configurenotify(XEvent *e) if (c->isfullscreen) resizeclient(c, m->mx, m->my, m->mw, m->mh); XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); + XMoveResizeWindow(dpy, m->extrabarwin, m->wx, m->eby, m->ww, bh); } focus(NULL); arrange(NULL); @@ -639,6 +656,7 @@ createmon(void) m->nmaster = nmaster; m->showbar = showbar; m->topbar = topbar; + m->extrabar = extrabar; m->lt[0] = &layouts[0]; m->lt[1] = &layouts[1 % LENGTH(layouts)]; strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); @@ -696,7 +714,7 @@ dirtomon(int dir) void drawbar(Monitor *m) { - int x, w, tw = 0; + int x, w, tw = 0, etwl = 0, etwr = 0; int boxs = drw->fonts->h / 9; int boxw = drw->fonts->h / 6 + 2; unsigned int i, occ = 0, urg = 0; @@ -741,6 +759,17 @@ drawbar(Monitor *m) } } drw_map(drw, m->barwin, 0, 0, m->ww, bh); + + if (m == selmon) { /* extra status is only drawn on selected monitor */ + drw_setscheme(drw, scheme[SchemeNorm]); + /* clear default bar draw buffer by drawing a blank rectangle */ + drw_rect(drw, 0, 0, m->ww, bh, 1, 1); + etwr = TEXTW(estextr) - lrpad + 2; /* 2px right padding */ + drw_text(drw, m->ww - etwr, 0, etwr, bh, 0, estextr, 0); + etwl = TEXTW(estextl); + drw_text(drw, 0, 0, etwl, bh, 0, estextl, 0); + drw_map(drw, m->extrabarwin, 0, 0, m->ww, bh); + } } void @@ -1708,6 +1737,15 @@ togglebar(const Arg *arg) arrange(selmon); } +void +toggleextrabar(const Arg *arg) +{ + selmon->extrabar = !selmon->extrabar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->extrabarwin, selmon->wx, selmon->eby, selmon->ww, bh); + arrange(selmon); +} + void togglefloating(const Arg *arg) { @@ -1812,14 +1850,22 @@ updatebars(void) }; 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); + if (!m->barwin) { + 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); + } + if (!m->extrabarwin) { + m->extrabarwin = XCreateWindow(dpy, root, m->wx, m->eby, m->ww, bh, 0, DefaultDepth(dpy, screen), + CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->extrabarwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->extrabarwin); + XSetClassHint(dpy, m->extrabarwin, &ch); + } } } @@ -1834,6 +1880,12 @@ updatebarpos(Monitor *m) m->wy = m->topbar ? m->wy + bh : m->wy; } else m->by = -bh; + if (m->extrabar) { + m->wh -= bh; + m->eby = !m->topbar ? m->wy : m->wy + m->wh; + m->wy = !m->topbar ? m->wy + bh : m->wy; + } else + m->eby = -bh; } void @@ -1990,8 +2042,26 @@ updatesizehints(Client *c) void updatestatus(void) { - if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) + char text[768]; + if (!gettextprop(root, XA_WM_NAME, text, sizeof(text))) { strcpy(stext, "dwm-"VERSION); + estextl[0] = '\0'; + estextr[0] = '\0'; + } else { + char *l = strchr(text, statussep); + if (l) { + *l = '\0'; l++; + strncpy(estextl, l, sizeof(estextl) - 1); + } else + estextl[0] = '\0'; + char *r = strchr(estextl, statussep); + if (r) { + *r = '\0'; r++; + strncpy(estextr, r, sizeof(estextr) - 1); + } else + estextr[0] = '\0'; + strncpy(stext, text, sizeof(stext) - 1); + } drawbar(selmon); } @@ -2070,7 +2140,7 @@ wintomon(Window w) if (w == root && getrootptr(&x, &y)) return recttomon(x, y, 1, 1); for (m = mons; m; m = m->next) - if (w == m->barwin) + if (w == m->barwin || w == m->extrabarwin) return m; if ((c = wintoclient(w))) return c->mon;