summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorbakkeby <[email protected]>2021-03-09 13:23:39 +0100
committerbakkeby <[email protected]>2021-03-09 13:23:39 +0100
commit0f9104285bab49c1e701ea429380ace9230309f0 (patch)
treeec62230fb58bde98c2a284cfda1891b3ce2ef658
parent27185a74c4b2311350d029b5aefaa326dd143adf (diff)
downloaddwm-flexipatch-0f9104285bab49c1e701ea429380ace9230309f0.tar.gz
dwm-flexipatch-0f9104285bab49c1e701ea429380ace9230309f0.zip
Adding tab patch
-rw-r--r--README.md9
-rw-r--r--config.def.h14
-rw-r--r--dwm.c123
-rw-r--r--patch/bar_powerline_tags.c2
-rw-r--r--patch/include.c3
-rw-r--r--patch/include.h3
-rw-r--r--patch/tab.c132
-rw-r--r--patch/tab.h4
-rw-r--r--patches.def.h8
9 files changed, 290 insertions, 8 deletions
diff --git a/README.md b/README.md
index fef9468..7cfdc2d 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,8 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t
### Changelog:
+2021-03-09 - Added the tab patch
+
2021-02-11 - Added the riodraw and focusdir patches
2021-01-22 - Added the placemouse patch
@@ -575,6 +577,13 @@ Refer to [https://dwm.suckless.org/](https://dwm.suckless.org/) for details on t
- [systray](https://dwm.suckless.org/patches/systray/)
- adds system tray in the status bar
+ - [tab](https://dwm.suckless.org/patches/tab/)
+ - transforms the monocle layout into a "tabbed" layout if more than one window is present on the monocle view
+ - this is essentially just a specific bar
+ - the patch has been added for demonstration purposes only and has limited compatibility with other patches
+ - it will conflict space-wise with a second bar
+ - note that fancybar, awesomebar, bartabgroups and similar patches make the tab patch redundant
+
- [tagall](https://dwm.suckless.org/patches/tagall/)
- adds keyboard shortcuts to move all (or only floating) windows from one tag to another
diff --git a/config.def.h b/config.def.h
index ab03439..ce368ee 100644
--- a/config.def.h
+++ b/config.def.h
@@ -38,6 +38,14 @@ static const int showbar = 0; /* 0 means no bar */
static const int showbar = 1; /* 0 means no bar */
#endif // BAR_HOLDBAR_PATCH
static const int topbar = 1; /* 0 means bottom bar */
+#if TAB_PATCH
+/* Display modes of the tab bar: never shown, always shown, shown only in */
+/* monocle mode in the presence of several windows. */
+/* Modes after showtab_nmodes are disabled. */
+enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
+static const int showtab = showtab_auto; /* Default tab bar show mode */
+static const int toptab = False; /* False means bottom tab bar */
+#endif // TAB_PATCH
#if BAR_HEIGHT_PATCH
static const int bar_height = 0; /* 0 means derive from font, >= 1 explicit height */
#endif // BAR_HEIGHT_PATCH
@@ -769,6 +777,9 @@ static Key keys[] = {
{ MODKEY, XK_s, rioresize, {0} },
#endif // RIODRAW_PATCH
{ MODKEY, XK_b, togglebar, {0} },
+ #if TAB_PATCH
+ { MODKEY|ControlMask, XK_b, tabmode, {-1} },
+ #endif // TAB_PATCH
#if FOCUSMASTER_PATCH
{ MODKEY|ControlMask, XK_space, focusmaster, {0} },
#endif // FOCUSMASTER_PATCH
@@ -1206,6 +1217,9 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ #if TAB_PATCH
+ { ClkTabBar, 0, Button1, focuswin, {0} },
+ #endif // TAB_PATCH
};
#if DWMC_PATCH
diff --git a/dwm.c b/dwm.c
index 8199199..9cabc5b 100644
--- a/dwm.c
+++ b/dwm.c
@@ -69,6 +69,9 @@
#define Button9 9
#define NUMTAGS 9
#define BARRULES 20
+#if TAB_PATCH
+#define MAXTABS 50
+#endif // TAB_PATCH
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#if BAR_ANYBAR_PATCH
@@ -205,6 +208,9 @@ enum {
#if BAR_STATUSBUTTON_PATCH
ClkButton,
#endif // BAR_STATUSBUTTON_PATCH
+ #if TAB_PATCH
+ ClkTabBar,
+ #endif // TAB_PATCH
ClkTagBar,
ClkLtSymbol,
ClkStatusText,
@@ -414,6 +420,9 @@ struct Monitor {
int num;
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
+ #if TAB_PATCH
+ int ty; /* tab bar geometry */
+ #endif // TAB_PATCH
#if VANITYGAPS_PATCH
int gappih; /* horizontal gap between windows */
int gappiv; /* vertical gap between windows */
@@ -427,6 +436,13 @@ struct Monitor {
unsigned int sellt;
unsigned int tagset[2];
int showbar;
+ #if TAB_PATCH
+ int showtab;
+ int toptab;
+ Window tabwin;
+ int ntabs;
+ int tab_widths[MAXTABS];
+ #endif // TAB_PATCH
Client *clients;
Client *sel;
Client *stack;
@@ -973,6 +989,10 @@ arrange(Monitor *m)
void
arrangemon(Monitor *m)
{
+ #if TAB_PATCH
+ updatebarpos(m);
+ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
+ #endif // TAB_PATCH
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
@@ -1000,7 +1020,7 @@ attachstack(Client *c)
void
buttonpress(XEvent *e)
{
- int click, i, r;
+ int click, i, x, r;
Arg arg = {0};
Client *c;
Monitor *m;
@@ -1043,6 +1063,26 @@ buttonpress(XEvent *e)
}
}
+ #if TAB_PATCH
+ if (ev->window == selmon->tabwin) {
+ for (i = 0, x = 0, c = selmon->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ x += selmon->tab_widths[i];
+ if (ev->x > x)
+ ++i;
+ else
+ break;
+ if (i >= m->ntabs)
+ break;
+ }
+ if (c) {
+ click = ClkTabBar;
+ arg.ui = i;
+ }
+ }
+ #endif // TAB_PATCH
+
if (click == ClkRootWin && (c = wintoclient(ev->window))) {
#if FOCUSONCLICK_PATCH
if (focusonwheel || (ev->button != Button4 && ev->button != Button5))
@@ -1058,11 +1098,17 @@ 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)) {
- #if BAR_WINTITLEACTIONS_PATCH
- buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
- #else
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
- #endif // BAR_WINTITLEACTIONS_PATCH
+ buttons[i].func(
+ (
+ click == ClkTagBar
+ #if TAB_PATCH
+ || click == ClkTabBar
+ #endif // TAB_PATCH
+ #if BAR_WINTITLEACTIONS_PATCH
+ || click == ClkWinTitle
+ #endif // BAR_WINTITLEACTIONS_PATCH
+ ) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg
+ );
}
}
}
@@ -1149,6 +1195,10 @@ cleanupmon(Monitor *mon)
#endif // BAR_SYSTRAY_PATCH
free(bar);
}
+ #if TAB_PATCH
+ XUnmapWindow(dpy, mon->tabwin);
+ XDestroyWindow(dpy, mon->tabwin);
+ #endif // TAB_PATCH
free(mon);
}
@@ -1413,6 +1463,11 @@ createmon(void)
m->nstack = nstack;
#endif // FLEXTILE_DELUXE_LAYOUT
m->showbar = showbar;
+ #if TAB_PATCH
+ m->showtab = showtab;
+ m->toptab = toptab;
+ m->ntabs = 0;
+ #endif // TAB_PATCH
#if SETBORDERPX_PATCH
m->borderpx = borderpx;
#endif // SETBORDERPX_PATCH
@@ -1807,8 +1862,12 @@ expose(XEvent *e)
Monitor *m;
XExposeEvent *ev = &e->xexpose;
- if (ev->count == 0 && (m = wintomon(ev->window)))
+ if (ev->count == 0 && (m = wintomon(ev->window))) {
drawbar(m);
+ #if TAB_PATCH
+ drawtabs();
+ #endif // TAB_PATCH
+ }
}
void
@@ -2567,12 +2626,18 @@ propertynotify(XEvent *e)
updatewmhints(c);
if (c->isurgent)
drawbars();
+ #if TAB_PATCH
+ drawtabs();
+ #endif // TAB_PATCH
break;
}
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c);
if (c == c->mon->sel)
drawbar(c->mon);
+ #if TAB_PATCH
+ drawtab(c->mon);
+ #endif // TAB_PATCH
}
#if DECORATION_HINTS_PATCH
if (ev->atom == motifatom)
@@ -2864,6 +2929,9 @@ restack(Monitor *m)
#endif // WARP_PATCH
drawbar(m);
+ #if TAB_PATCH
+ drawtab(m);
+ #endif // TAB_PATCH
if (!m->sel)
return;
if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
@@ -3345,6 +3413,9 @@ setup(void)
bh = drw->fonts->h + 2;
#endif // BAR_HEIGHT_PATCH
#endif // BAR_STATUSPADDING_PATCH
+ #if TAB_PATCH
+ th = bh;
+ #endif // TAB_PATCH
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@@ -4069,12 +4140,32 @@ updatebars(void)
XSetClassHint(dpy, bar->win, &ch);
}
}
+ #if TAB_PATCH
+ if (!m->tabwin) {
+ #if BAR_ALPHA_PATCH
+ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, depth,
+ InputOutput, visual,
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
+ #else
+ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ #endif // BAR_ALPHA_PATCH
+ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->tabwin);
+ }
+ #endif // TAB_PATCH
}
}
void
updatebarpos(Monitor *m)
{
+ #if TAB_PATCH
+ Client *c;
+ int nvis = 0;
+ #endif // TAB_PATCH
+
m->wx = m->mx;
m->wy = m->my;
m->ww = m->mw;
@@ -4105,6 +4196,24 @@ updatebarpos(Monitor *m)
for (bar = m->bar; bar; bar = bar->next)
if (!m->showbar || !bar->showbar)
bar->by = -bar->bh - y_pad;
+
+ #if TAB_PATCH
+ for (c = m->clients; c; c = c->next) {
+ if (ISVISIBLE(c) && !HIDDEN(c))
+ ++nvis;
+ }
+
+ if (m->showtab == showtab_always
+ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))) {
+ m->wh -= th;
+ m->ty = m->toptab ? m->wy : m->wy + m->wh;
+ if (m->toptab)
+ m->wy += th;
+ } else {
+ m->ty = -th;
+ }
+ #endif // TAB_PATCH
+
if (!m->showbar)
return;
for (bar = m->bar; bar; bar = bar->next) {
diff --git a/patch/bar_powerline_tags.c b/patch/bar_powerline_tags.c
index f4dd923..7806725 100644
--- a/patch/bar_powerline_tags.c
+++ b/patch/bar_powerline_tags.c
@@ -52,7 +52,7 @@ draw_pwrl_tags(Bar *bar, BarArg *a)
icon = tagicon(bar->mon, i);
invert = 0;
w = TEXTW(icon);
- if (urg & 1 << i ) {
+ if (urg & 1 << i) {
drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeUrg]));
} else {
drw_settrans(drw, prevscheme, (nxtscheme = scheme[bar->mon->tagset[bar->mon->seltags] & 1 << i ? SchemeSel : SchemeNorm]));
diff --git a/patch/include.c b/patch/include.c
index 7f79624..73c3536 100644
--- a/patch/include.c
+++ b/patch/include.c
@@ -253,6 +253,9 @@
#if SWITCHCOL_PATCH
#include "switchcol.c"
#endif
+#if TAB_PATCH
+#include "tab.c"
+#endif
#if TAGALL_PATCH
#include "tagall.c"
#endif
diff --git a/patch/include.h b/patch/include.h
index 9b3de50..27cf77b 100644
--- a/patch/include.h
+++ b/patch/include.h
@@ -249,6 +249,9 @@
#if SWITCHCOL_PATCH
#include "switchcol.h"
#endif
+#if TAB_PATCH
+#include "tab.h"
+#endif
#if TAGALL_PATCH
#include "tagall.h"
#endif
diff --git a/patch/tab.c b/patch/tab.c
new file mode 100644
index 0000000..be6a59a
--- /dev/null
+++ b/patch/tab.c
@@ -0,0 +1,132 @@
+static int th = 0; /* tab bar geometry */
+
+void
+drawtabs(void)
+{
+ Monitor *m;
+
+ for (m = mons; m; m = m->next)
+ drawtab(m);
+}
+
+static int
+cmpint(const void *p1, const void *p2)
+{
+ /* The actual arguments to this function are "pointers to
+ pointers to char", but strcmp(3) arguments are "pointers
+ to char", hence the following cast plus dereference */
+ return *((int*) p1) > * (int*) p2;
+}
+
+void
+drawtab(Monitor *m)
+{
+ Client *c;
+ int i;
+ int itag = -1;
+ char view_info[50];
+ int view_info_w = 0;
+ int sorted_label_widths[MAXTABS];
+ int tot_width;
+ int maxsize = bh;
+ int x = 0;
+ int w = 0;
+
+ // view_info: indicate the tag which is displayed in the view
+ for (i = 0; i < NUMTAGS; ++i) {
+ if ((selmon->tagset[selmon->seltags] >> i) & 1) {
+ if (itag >=0) { // more than one tag selected
+ itag = -1;
+ break;
+ }
+ itag = i;
+ }
+ }
+
+ if (0 <= itag && itag < NUMTAGS) {
+ snprintf(view_info, sizeof view_info, "[%s]", tagicon(m, itag));
+ } else {
+ strncpy(view_info, "[...]", sizeof view_info);
+ }
+ view_info[sizeof(view_info) - 1 ] = 0;
+ view_info_w = TEXTW(view_info);
+ tot_width = view_info_w;
+
+ /* Calculates number of labels and their width */
+ m->ntabs = 0;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ m->tab_widths[m->ntabs] = TEXTW(c->name);
+ tot_width += m->tab_widths[m->ntabs];
+ ++m->ntabs;
+ if (m->ntabs >= MAXTABS)
+ break;
+ }
+
+ if (tot_width > m->ww) { // not enough space to display the labels, they need to be truncated
+ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
+ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
+ tot_width = view_info_w;
+ for (i = 0; i < m->ntabs; ++i) {
+ if (tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
+ break;
+ tot_width += sorted_label_widths[i];
+ }
+ maxsize = (m->ww - tot_width) / (m->ntabs - i);
+ } else {
+ maxsize = m->ww;
+ }
+ i = 0;
+ for (c = m->clients; c; c = c->next) {
+ if (!ISVISIBLE(c) || HIDDEN(c))
+ continue;
+ if (i >= m->ntabs)
+ break;
+ if (m->tab_widths[i] > maxsize)
+ m->tab_widths[i] = maxsize;
+ w = m->tab_widths[i];
+ drw_setscheme(drw, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
+ drw_text(drw, x, 0, w, th, 0, c->name, 0, False);
+ x += w;
+ ++i;
+ }
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+
+ /* cleans interspace between window names and current viewed tag label */
+ w = m->ww - view_info_w - x;
+ drw_text(drw, x, 0, w, th, 0, "", 0, False);
+
+ /* view info */
+ x += w;
+ w = view_info_w;
+ drw_text(drw, x, 0, w, th, 0, view_info, 0, False);
+
+ drw_map(drw, m->tabwin, 0, 0, m->ww, th);
+}
+
+void
+focuswin(const Arg* arg)
+{
+ int iwin = arg->i;
+ Client* c = NULL;
+ for (c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next) {
+ if (ISVISIBLE(c) && !HIDDEN(c))
+ --iwin;
+ };
+ if (c) {
+ focus(c);
+ restack(selmon);
+ }
+}
+
+void
+tabmode(const Arg *arg)
+{
+ if (arg && arg->i >= 0)
+ selmon->showtab = arg->ui % showtab_nmodes;
+ else
+ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
+ arrange(selmon);
+} \ No newline at end of file
diff --git a/patch/tab.h b/patch/tab.h
new file mode 100644
index 0000000..7b4d20f
--- /dev/null
+++ b/patch/tab.h
@@ -0,0 +1,4 @@
+static void drawtab(Monitor *m);
+static void drawtabs(void);
+static void focuswin(const Arg* arg);
+static void tabmode(const Arg *arg);
diff --git a/patches.def.h b/patches.def.h
index 0a27b1c..ef1a0d6 100644
--- a/patches.def.h
+++ b/patches.def.h
@@ -963,6 +963,14 @@
*/
#define SWITCHTAG_PATCH 0
+/* This patch transforms the monocle layout into a "tabbed" layout if more than one window is
+ * present on the monocle view. This patch has been added for demonstration purposes only and has
+ * limited compatibility with other patches. It will conflict space-wise with a second bar.
+ * Note that fancybar, awesomebar, bartabgroups and similar patches make the tab patch redundant.
+ * https://dwm.suckless.org/patches/tab/
+ */
+#define TAB_PATCH 0
+
/* Adds keyboard shortcuts to move all (or only floating) windows from one tag to another.
* https://dwm.suckless.org/patches/tagall/
*/