From 5cf50e5fcb40ef48a8a92c4a00714a1174e17fc9 Mon Sep 17 00:00:00 2001 From: Eddy Pedroni Date: Sat, 16 Dec 2023 17:06:19 +0100 Subject: Add patches from suckless.org --- patches/dwm-6.1-pertag-tab-v2b.diff | 841 ++++++++++++++++++++++++++++++++++++ patches/dwm-autoresize-6.1.diff | 35 ++ patches/dwm-statuscolors-6.1.diff | 194 +++++++++ 3 files changed, 1070 insertions(+) create mode 100644 patches/dwm-6.1-pertag-tab-v2b.diff create mode 100644 patches/dwm-autoresize-6.1.diff create mode 100644 patches/dwm-statuscolors-6.1.diff diff --git a/patches/dwm-6.1-pertag-tab-v2b.diff b/patches/dwm-6.1-pertag-tab-v2b.diff new file mode 100644 index 0000000..f289bde --- /dev/null +++ b/patches/dwm-6.1-pertag-tab-v2b.diff @@ -0,0 +1,841 @@ +diff --git a/config.def.h b/config.def.h +index 7054c06..f0b33c5 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -15,10 +15,21 @@ 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 */ ++/* Display modes of the tab bar: never shown, always shown, shown only in */ ++/* monocle mode in 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 Bool toptab = False; /* False means bottom tab bar */ + + /* tagging */ + static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + ++/* default layout per tags */ ++/* The first element is for all-tag view, following i-th element corresponds to */ ++/* tags[i]. Layout is referred using the layouts array index.*/ ++static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; ++ + static const Rule rules[] = { + /* xprop(1): + * WM_CLASS(STRING) = instance, class +@@ -62,6 +73,7 @@ static Key keys[] = { + { MODKEY, XK_p, spawn, {.v = dmenucmd } }, + { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY, XK_b, togglebar, {0} }, ++ { MODKEY, XK_w, tabmode, {-1} }, + { MODKEY, XK_j, focusstack, {.i = +1 } }, + { MODKEY, XK_k, focusstack, {.i = -1 } }, + { MODKEY, XK_i, incnmaster, {.i = +1 } }, +@@ -109,5 +121,6 @@ static Button buttons[] = { + { ClkTagBar, 0, Button3, toggleview, {0} }, + { ClkTagBar, MODKEY, Button1, tag, {0} }, + { ClkTagBar, MODKEY, Button3, toggletag, {0} }, ++ { ClkTabBar, 0, Button1, focuswin, {0} }, + }; + +diff --git a/dwm.1 b/dwm.1 +index 6687011..077d92b 100644 +--- a/dwm.1 ++++ b/dwm.1 +@@ -19,14 +19,22 @@ layout applied. + Windows are grouped by tags. Each window can be tagged with one or multiple + tags. Selecting certain tags displays all windows with these tags. + .P +-Each screen contains a small status bar which displays all available tags, the +-layout, the title of the focused window, and the text read from the root window +-name property, if the screen is focused. A floating window is indicated with an +-empty square and a maximised floating window is indicated with a filled square +-before the windows title. The selected tags are indicated with a different +-color. The tags of the focused window are indicated with a filled square in the +-top left corner. The tags which are applied to one or more windows are +-indicated with an empty square in the top left corner. ++Each screen contains two small status bars. ++.P ++One bar displays all available tags, the layout, the title of the focused ++window, and the text read from the root window name property, if the screen is ++focused. A floating window is indicated with an empty square and a maximised ++floating window is indicated with a filled square before the windows title. The ++selected tags are indicated with a different color. The tags of the focused ++window are indicated with a filled square in the top left corner. The tags ++which are applied to one or more windows are indicated with an empty square in ++the top left corner. ++.P ++Another bar contains a tab for each window of the current view and allows ++navigation between windows, especially in the monocle mode. The different ++display modes of this bar are described under the Mod1\-w Keybord command ++section. When a single tag is selected, that tag is indicated in the left corner ++of the tab bar. + .P + dwm draws a small border around windows to indicate the focus state. + .SH OPTIONS +@@ -43,7 +51,8 @@ command. + .TP + .B Button1 + click on a tag label to display all windows with that tag, click on the layout +-label toggles between tiled and floating layout. ++label toggles between tiled and floating layout, click on a window name in the ++tab bar brings focus to that window. + .TP + .B Button3 + click on a tag label adds/removes all windows with that tag to/from the view. +@@ -104,6 +113,12 @@ Increase master area size. + .B Mod1\-h + Decrease master area size. + .TP ++.B Mod1\-w ++Cycle over the tab bar display modes: never displayed, always displayed, ++displayed only in monocle mode when the view contains than one window (auto ++mode). Some display modes can be disabled in the configuration, config.h. In ++the default configuration only "never" and "auto" display modes are enabled. ++.TP + .B Mod1\-Return + Zooms/cycles focused window to/from master area (tiled layouts only). + .TP +diff --git a/dwm.c b/dwm.c +index 0362114..887a839 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, + NetWMFullscreen, NetActiveWindow, NetWMWindowType, + NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ + enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ +-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ++enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, + ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ + + typedef union { +@@ -111,25 +111,35 @@ typedef struct { + void (*arrange)(Monitor *); + } Layout; + ++#define MAXTABS 50 ++ ++typedef struct Pertag Pertag; + struct Monitor { + char ltsymbol[16]; + float mfact; + int nmaster; + int num; + int by; /* bar geometry */ ++ int ty; /* tab 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 showtab; + int topbar; ++ int toptab; + Client *clients; + Client *sel; + Client *stack; + Monitor *next; + Window barwin; ++ Window tabwin; ++ int ntabs; ++ int tab_widths[MAXTABS]; + const Layout *lt[2]; ++ Pertag *pertag; + }; + + typedef struct { +@@ -164,12 +174,15 @@ static void detachstack(Client *c); + static Monitor *dirtomon(int dir); + static void drawbar(Monitor *m); + static void drawbars(void); ++static void drawtab(Monitor *m); ++static void drawtabs(void); + static void enternotify(XEvent *e); + static void expose(XEvent *e); + static void focus(Client *c); + static void focusin(XEvent *e); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); ++static void focuswin(const Arg* arg); + static int getrootptr(int *x, int *y); + static long getstate(Window w); + static int gettextprop(Window w, Atom atom, char *text, unsigned int size); +@@ -206,6 +219,7 @@ static void setup(void); + static void showhide(Client *c); + static void sigchld(int unused); + static void spawn(const Arg *arg); ++static void tabmode(const Arg *arg); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); + static void tile(Monitor *); +@@ -240,6 +254,7 @@ 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 th = 0; /* tab bar geometry */ + static int (*xerrorxlib)(Display *, XErrorEvent *); + static unsigned int numlockmask = 0; + static void (*handler[LASTEvent]) (XEvent *) = { +@@ -270,6 +285,16 @@ static Window root; + /* configuration, allows nested code to access above variables */ + #include "config.h" + ++struct Pertag { ++ unsigned int curtag, prevtag; /* current and previous tag */ ++ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ ++ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ ++ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ ++ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ ++ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ ++ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */ ++}; ++ + /* compile-time check if all tags fit into an unsigned int bit array. */ + struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; + +@@ -393,6 +418,8 @@ arrange(Monitor *m) + void + arrangemon(Monitor *m) + { ++ updatebarpos(m); ++ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th); + strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol); + if (m->lt[m->sellt]->arrange) + m->lt[m->sellt]->arrange(m); +@@ -442,14 +469,33 @@ buttonpress(XEvent *e) + click = ClkStatusText; + else + click = ClkWinTitle; +- } else if ((c = wintoclient(ev->window))) { ++ } ++ if(ev->window == selmon->tabwin) { ++ i = 0; x = 0; ++ for(c = selmon->clients; c; c = c->next){ ++ if(!ISVISIBLE(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; ++ } ++ } ++ else if((c = wintoclient(ev->window))) { + focus(c); + click = ClkClientWin; + } +- 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); ++ 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 || click == ClkTabBar) ++ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg); ++ } + } + + void +@@ -469,23 +515,24 @@ cleanup(void) + Arg a = {.ui = ~0}; + Layout foo = { "", NULL }; + Monitor *m; +- size_t i; + + view(&a); + selmon->lt[selmon->sellt] = &foo; + for (m = mons; m; m = m->next) +- while (m->stack) +- unmanage(m->stack, 0); ++ while(m->stack) ++ unmanage(m->stack, False); + XUngrabKey(dpy, AnyKey, AnyModifier, root); + while (mons) + cleanupmon(mons); +- for (i = 0; i < CurLast; i++) +- drw_cur_free(drw, cursor[i]); +- for (i = 0; i < SchemeLast; i++) { +- drw_clr_free(scheme[i].border); +- drw_clr_free(scheme[i].bg); +- drw_clr_free(scheme[i].fg); +- } ++ drw_cur_free(drw, cursor[CurNormal]); ++ drw_cur_free(drw, cursor[CurResize]); ++ drw_cur_free(drw, cursor[CurMove]); ++ drw_clr_free(scheme[SchemeNorm].border); ++ drw_clr_free(scheme[SchemeNorm].bg); ++ drw_clr_free(scheme[SchemeNorm].fg); ++ drw_clr_free(scheme[SchemeSel].border); ++ drw_clr_free(scheme[SchemeSel].bg); ++ drw_clr_free(scheme[SchemeSel].fg); + drw_free(drw); + XSync(dpy, False); + XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); +@@ -505,6 +552,8 @@ cleanupmon(Monitor *mon) + } + XUnmapWindow(dpy, mon->barwin); + XDestroyWindow(dpy, mon->barwin); ++ XUnmapWindow(dpy, mon->tabwin); ++ XDestroyWindow(dpy, mon->tabwin); + free(mon); + } + +@@ -526,6 +575,7 @@ clientmessage(XEvent *e) + { + XClientMessageEvent *cme = &e->xclient; + Client *c = wintoclient(cme->window); ++ int i; + + if (!c) + return; +@@ -537,6 +587,8 @@ clientmessage(XEvent *e) + if (!ISVISIBLE(c)) { + c->mon->seltags ^= 1; + c->mon->tagset[c->mon->seltags] = c->tags; ++ for(i=0; !(c->tags & 1 << i); i++); ++ view(&(Arg){.ui = 1 << i}); + } + pop(c); + } +@@ -565,6 +617,7 @@ void + configurenotify(XEvent *e) + { + Monitor *m; ++ Client *c; + XConfigureEvent *ev = &e->xconfigure; + int dirty; + +@@ -576,8 +629,14 @@ configurenotify(XEvent *e) + if (updategeom() || dirty) { + drw_resize(drw, sw, bh); + updatebars(); +- for (m = mons; m; m = m->next) ++ //refreshing display of status bar. The tab bar is handled by the arrange() ++ //method, which is called below ++ for(m = mons; m; m = m->next){ ++ 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); ++ } + focus(NULL); + arrange(NULL); + } +@@ -640,16 +699,41 @@ Monitor * + createmon(void) + { + Monitor *m; ++ int i; + + m = ecalloc(1, sizeof(Monitor)); + m->tagset[0] = m->tagset[1] = 1; + m->mfact = mfact; + m->nmaster = nmaster; + m->showbar = showbar; ++ m->showtab = showtab; + m->topbar = topbar; +- m->lt[0] = &layouts[0]; ++ m->toptab = toptab; ++ m->ntabs = 0; ++ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)]; + m->lt[1] = &layouts[1 % LENGTH(layouts)]; + strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); ++ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag)))) ++ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag)); ++ m->pertag->curtag = m->pertag->prevtag = 1; ++ for(i=0; i <= LENGTH(tags); i++) { ++ /* init nmaster */ ++ m->pertag->nmasters[i] = m->nmaster; ++ ++ /* init mfacts */ ++ m->pertag->mfacts[i] = m->mfact; ++ ++ /* init layouts */ ++ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)]; ++ m->pertag->ltidxs[i][1] = m->lt[1]; ++ m->pertag->sellts[i] = m->sellt; ++ ++ /* init showbar */ ++ m->pertag->showbars[i] = m->showbar; ++ ++ /* swap focus and zoomswap*/ ++ m->pertag->prevzooms[i] = NULL; ++ } + return m; + } + +@@ -763,6 +847,104 @@ drawbars(void) + } + + 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 < LENGTH(tags); ++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 < LENGTH(tags)){ ++ snprintf(view_info, sizeof view_info, "[%s]", tags[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)) 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)) 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, (c == m->sel) ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_text(drw, x, 0, w, th, c->name, 0); ++ 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); ++ ++ /* view info */ ++ x += w; ++ w = view_info_w; ++ drw_text(drw, x, 0, w, th, view_info, 0); ++ ++ drw_map(drw, m->tabwin, 0, 0, m->ww, th); ++} ++ ++void + enternotify(XEvent *e) + { + Client *c; +@@ -787,8 +969,10 @@ 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); ++ drawtab(m); ++ } + } + + void +@@ -806,7 +990,7 @@ focus(Client *c) + clearurgent(c); + detachstack(c); + attachstack(c); +- grabbuttons(c, 1); ++ grabbuttons(c, True); + XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); + setfocus(c); + } else { +@@ -815,6 +999,7 @@ focus(Client *c) + } + selmon->sel = c; + drawbars(); ++ drawtabs(); + } + + /* there are some broken focus acquiring clients */ +@@ -868,6 +1053,19 @@ focusstack(const Arg *arg) + } + } + ++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)) --iwin; ++ }; ++ if(c) { ++ focus(c); ++ restack(selmon); ++ } ++} ++ + Atom + getatomprop(Client *c, Atom prop) + { +@@ -981,7 +1179,7 @@ grabkeys(void) + void + incnmaster(const Arg *arg) + { +- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0); ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0); + arrange(selmon); + } + +@@ -1139,7 +1337,7 @@ motionnotify(XEvent *e) + if (ev->window != root) + return; + if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { +- unfocus(selmon->sel, 1); ++ unfocus(selmon->sel, True); + selmon = m; + focus(NULL); + } +@@ -1159,11 +1357,13 @@ movemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support moving fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess) + return; + if (!getrootptr(&x, &y)) + return; +@@ -1250,12 +1450,14 @@ propertynotify(XEvent *e) + case XA_WM_HINTS: + updatewmhints(c); + drawbars(); ++ drawtabs(); + break; + } + if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { + updatetitle(c); + if (c == c->mon->sel) + drawbar(c->mon); ++ drawtab(c->mon); + } + if (ev->atom == netatom[NetWMWindowType]) + updatewindowtype(c); +@@ -1317,11 +1519,13 @@ resizemouse(const Arg *arg) + return; + if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */ + return; ++ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */ ++ return; + restack(selmon); + ocx = c->x; + ocy = c->y; + if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, +- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) ++ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess) + return; + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); + do { +@@ -1369,6 +1573,7 @@ restack(Monitor *m) + XWindowChanges wc; + + drawbar(m); ++ drawtab(m); + if (!m->sel) + return; + if (m->sel->isfloating || !m->lt[m->sellt]->arrange) +@@ -1477,11 +1682,11 @@ sendevent(Client *c, Atom proto) + void + setfocus(Client *c) + { +- if (!c->neverfocus) { ++ if(!c->neverfocus) { + XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); + XChangeProperty(dpy, root, netatom[NetActiveWindow], +- XA_WINDOW, 32, PropModeReplace, +- (unsigned char *) &(c->win), 1); ++ XA_WINDOW, 32, PropModeReplace, ++ (unsigned char *) &(c->win), 1); + } + sendevent(c, wmatom[WMTakeFocus]); + } +@@ -1517,10 +1722,13 @@ setfullscreen(Client *c, int fullscreen) + void + setlayout(const Arg *arg) + { +- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) +- selmon->sellt ^= 1; +- if (arg && arg->v) +- selmon->lt[selmon->sellt] = (Layout *)arg->v; ++ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) { ++ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ } ++ if(arg && arg->v) ++ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; + strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); + if (selmon->sel) + arrange(selmon); +@@ -1539,7 +1747,7 @@ setmfact(const Arg *arg) + f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; + if (f < 0.1 || f > 0.9) + return; +- selmon->mfact = f; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; + arrange(selmon); + } + +@@ -1559,8 +1767,9 @@ setup(void) + drw = drw_create(dpy, screen, root, sw, sh); + drw_load_fonts(drw, fonts, LENGTH(fonts)); + if (!drw->fontcount) +- die("no fonts could be loaded.\n"); ++ die("No fonts could be loaded.\n"); + bh = drw->fonts[0]->h + 2; ++ th = bh; + updategeom(); + /* init atoms */ + wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); +@@ -1632,10 +1841,10 @@ sigchld(int unused) + void + spawn(const Arg *arg) + { +- if (arg->v == dmenucmd) ++ if(arg->v == dmenucmd) + dmenumon[0] = '0' + selmon->num; +- if (fork() == 0) { +- if (dpy) ++ if(fork() == 0) { ++ if(dpy) + close(ConnectionNumber(dpy)); + setsid(); + execvp(((char **)arg->v)[0], (char **)arg->v); +@@ -1692,18 +1901,29 @@ tile(Monitor *m) + void + togglebar(const Arg *arg) + { +- selmon->showbar = !selmon->showbar; ++ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; + updatebarpos(selmon); + XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh); + arrange(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); ++} ++ ++ ++void + togglefloating(const Arg *arg) + { +- if (!selmon->sel) ++ if(!selmon->sel) + return; +- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */ ++ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */ + return; + selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed; + if (selmon->sel->isfloating) +@@ -1731,9 +1951,29 @@ void + toggleview(const Arg *arg) + { + unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); ++ int i; + + if (newtagset) { ++ if(newtagset == ~0) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = 0; ++ } ++ /* test if the user did not select the same tag */ ++ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ for (i=0; !(newtagset & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } + selmon->tagset[selmon->seltags] = newtagset; ++ ++ /* apply settings for this view */ ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -1744,7 +1984,7 @@ unfocus(Client *c, int setfocus) + { + if (!c) + return; +- grabbuttons(c, 0); ++ grabbuttons(c, False); + XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1809,20 +2049,44 @@ updatebars(void) + CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); + XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); + XMapRaised(dpy, m->barwin); ++ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen), ++ CopyFromParent, DefaultVisual(dpy, screen), ++ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); ++ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor); ++ XMapRaised(dpy, m->tabwin); + } + } + + void + updatebarpos(Monitor *m) + { ++ Client *c; ++ int nvis = 0; ++ + 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 ++ if ( m->topbar ) ++ m->wy += bh; ++ } else { + m->by = -bh; ++ } ++ ++ for(c = m->clients; c; c = c->next){ ++ if(ISVISIBLE(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; ++ } + } + + void +@@ -2004,9 +2268,9 @@ updatewindowtype(Client *c) + Atom wtype = getatomprop(c, netatom[NetWMWindowType]); + + if (state == netatom[NetWMFullscreen]) +- setfullscreen(c, 1); ++ setfullscreen(c, True); + if (wtype == netatom[NetWMWindowTypeDialog]) +- c->isfloating = 1; ++ c->isfloating = True; + } + + void +@@ -2031,11 +2295,33 @@ updatewmhints(Client *c) + void + view(const Arg *arg) + { +- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) ++ int i; ++ unsigned int tmptag; ++ ++ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) + return; + selmon->seltags ^= 1; /* toggle sel tagset */ +- if (arg->ui & TAGMASK) ++ if(arg->ui & TAGMASK) { ++ selmon->pertag->prevtag = selmon->pertag->curtag; + selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; ++ if(arg->ui == ~0) ++ selmon->pertag->curtag = 0; ++ else { ++ for (i=0; !(arg->ui & 1 << i); i++) ; ++ selmon->pertag->curtag = i + 1; ++ } ++ } else { ++ tmptag = selmon->pertag->prevtag; ++ selmon->pertag->prevtag = selmon->pertag->curtag; ++ selmon->pertag->curtag = tmptag; ++ } ++ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; ++ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; ++ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; ++ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; ++ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; ++ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) ++ togglebar(NULL); + focus(NULL); + arrange(selmon); + } +@@ -2063,7 +2349,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->tabwin) + return m; + if ((c = wintoclient(w))) + return c->mon; diff --git a/patches/dwm-autoresize-6.1.diff b/patches/dwm-autoresize-6.1.diff new file mode 100644 index 0000000..76530b9 --- /dev/null +++ b/patches/dwm-autoresize-6.1.diff @@ -0,0 +1,35 @@ +diff --git a/dwm.c b/dwm.c +index 0362114..e4e8514 100644 +--- a/dwm.c ++++ b/dwm.c +@@ -92,7 +92,7 @@ struct Client { + int basew, baseh, incw, inch, maxw, maxh, minw, minh; + int bw, oldbw; + unsigned int tags; +- int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; ++ int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen, needresize; + Client *next; + Client *snext; + Monitor *mon; +@@ -621,6 +621,8 @@ configurerequest(XEvent *e) + configure(c); + if (ISVISIBLE(c)) + XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ else ++ c->needresize = 1; + } else + configure(c); + } else { +@@ -1611,6 +1613,12 @@ showhide(Client *c) + if (ISVISIBLE(c)) { + /* show clients top down */ + XMoveWindow(dpy, c->win, c->x, c->y); ++ if (c->needresize) { ++ c->needresize = 0; ++ XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h); ++ } else { ++ XMoveWindow(dpy, c->win, c->x, c->y); ++ } + if ((!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) && !c->isfullscreen) + resize(c, c->x, c->y, c->w, c->h, 0); + showhide(c->snext); diff --git a/patches/dwm-statuscolors-6.1.diff b/patches/dwm-statuscolors-6.1.diff new file mode 100644 index 0000000..3aead49 --- /dev/null +++ b/patches/dwm-statuscolors-6.1.diff @@ -0,0 +1,194 @@ +diff -up dwm/drw.c dwm-statuscolors/drw.c +--- dwm/drw.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.c 2015-11-28 15:42:28.534399525 -0700 +@@ -206,6 +206,68 @@ drw_setscheme(Drw *drw, ClrScheme *schem + drw->scheme = scheme; + } + ++int ++drw_get_width(Drw *drw, int numcolors, const char *text) ++{ ++ int i; ++ Fnt *curfont = drw->fonts[0]; ++ int w = drw_text(drw, 0, 0, 0, 0, text, 0) + curfont->h; ++ ++ for (i = 0; i < strlen(text); i++) { ++ if (text[i] > 0 && text[i] <= numcolors) { ++ /* we found a color code ++ * drw_text counted it as a normal character and added one character's width ++ * we aren't going to render this character, so we remove one character's width */ ++ w -= curfont->xfont->max_advance_width; ++ ++ if (i == 0 || i + 1 == strlen(text)) { ++ /* we're on the first or the last character of the string ++ * drw_text already added one character's height (divided by 2) as padding to the beginning and end ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ if (text[i - 1] > 0 && text[i - 1] <= numcolors) { ++ /* the previous character was also a color code ++ * we already added padding in the previous iteration ++ * we don't want to double this padding, so we skip this character */ ++ continue; ++ } ++ ++ /* we are somewhere in the middle of the string and the color has changed ++ * we want to add one character's height (divided by 2) as padding to the end of the previous colored text ++ * and to the beginning of the new colored text */ ++ w += curfont->h; ++ } ++ } ++ ++ return w; ++} ++ ++void ++drw_colored_text(Drw *drw, ClrScheme *scheme, int numcolors, int x, int y, unsigned int w, unsigned int h, char *text) ++{ ++ if (!drw || !drw->fontcount || !drw->scheme) ++ return; ++ ++ char *buf = text, *ptr = buf, c = 1; ++ int i; ++ ++ while (*ptr) { ++ for (i = 0; *ptr < 0 || *ptr > numcolors; i++, ptr++); ++ if (!*ptr) ++ break; ++ c = *ptr; ++ *ptr = 0; ++ if (i) ++ x = drw_text(drw, x, y, w, h, buf, 0) + drw->fonts[0]->h; ++ *ptr = c; ++ drw_setscheme(drw, &scheme[c-1]); ++ buf = ++ptr; ++ } ++ drw_text(drw, x, y, w, h, buf, 0); ++} ++ + void + drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) + { +diff -up dwm/drw.h dwm-statuscolors/drw.h +--- dwm/drw.h 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/drw.h 2015-11-28 15:39:44.427726312 -0700 +@@ -67,6 +67,8 @@ void drw_setfont(Drw *, Fnt *); + void drw_setscheme(Drw *, ClrScheme *); + + /* Drawing functions */ ++int drw_get_width(Drw *, int, const char *); ++void drw_colored_text(Drw *, ClrScheme *, int, int, int, unsigned int, unsigned int, char *); + void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int); + int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int); + +diff -up dwm/dwm.c dwm-statuscolors/dwm.c +--- dwm/dwm.c 2015-11-08 15:39:37.000000000 -0700 ++++ dwm-statuscolors/dwm.c 2015-11-28 15:45:32.134406853 -0700 +@@ -51,6 +51,7 @@ + * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy))) + #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) + #define LENGTH(X) (sizeof X / sizeof X[0]) ++#define MAXCOLORS 9 + #define MOUSEMASK (BUTTONMASK|PointerMotionMask) + #define WIDTH(X) ((X)->w + 2 * (X)->bw) + #define HEIGHT(X) ((X)->h + 2 * (X)->bw) +@@ -261,7 +262,7 @@ static void (*handler[LASTEvent]) (XEven + static Atom wmatom[WMLast], netatom[NetLast]; + static int running = 1; + static Cur *cursor[CurLast]; +-static ClrScheme scheme[SchemeLast]; ++static ClrScheme scheme[MAXCOLORS]; + static Display *dpy; + static Drw *drw; + static Monitor *mons, *selmon; +@@ -718,35 +719,35 @@ drawbar(Monitor *m) + x = 0; + for (i = 0; i < LENGTH(tags); i++) { + w = TEXTW(tags[i]); +- drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]); +- drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i); ++ drw_setscheme(drw, &scheme[(m->tagset[m->seltags] & 1 << i) ? 1 : (urg & 1 << i ? 2 : 0)]); ++ drw_text(drw, x, 0, w, bh, tags[i], 0); + drw_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, +- occ & 1 << i, urg & 1 << i); ++ occ & 1 << i, 0); + x += w; + } + w = blw = TEXTW(m->ltsymbol); +- drw_setscheme(drw, &scheme[SchemeNorm]); ++ drw_setscheme(drw, &scheme[0]); + drw_text(drw, x, 0, w, bh, m->ltsymbol, 0); + x += w; + xx = x; + if (m == selmon) { /* status is only drawn on selected monitor */ +- w = TEXTW(stext); ++ w = drw_get_width(drw, NUMCOLORS, stext); + x = m->ww - w; + if (x < xx) { + x = xx; + w = m->ww - xx; + } +- drw_text(drw, x, 0, w, bh, stext, 0); ++ drw_colored_text(drw, scheme, NUMCOLORS, x, 0, w, bh, stext); + } else + x = m->ww; + if ((w = x - xx) > bh) { + x = xx; + if (m->sel) { +- drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); ++ drw_setscheme(drw, &scheme[m == selmon ? 1 : 0]); + drw_text(drw, x, 0, w, bh, m->sel->name, 0); + drw_rect(drw, x + 1, 1, dx, dx, m->sel->isfixed, m->sel->isfloating, 0); + } else { +- drw_setscheme(drw, &scheme[SchemeNorm]); ++ drw_setscheme(drw, &scheme[0]); + drw_rect(drw, x, 0, w, bh, 1, 0, 1); + } + } +@@ -807,7 +808,7 @@ focus(Client *c) + detachstack(c); + attachstack(c); + grabbuttons(c, 1); +- XSetWindowBorder(dpy, c->win, scheme[SchemeSel].border->pix); ++ XSetWindowBorder(dpy, c->win, scheme[1].border->pix); + setfocus(c); + } else { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); +@@ -1065,7 +1066,7 @@ manage(Window w, XWindowAttributes *wa) + + wc.border_width = c->bw; + XConfigureWindow(dpy, w, CWBorderWidth, &wc); +- XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->pix); ++ XSetWindowBorder(dpy, w, scheme[0].border->pix); + configure(c); /* propagates border_width, if size doesn't change */ + updatewindowtype(c); + updatesizehints(c); +@@ -1580,12 +1581,12 @@ setup(void) + cursor[CurResize] = drw_cur_create(drw, XC_sizing); + cursor[CurMove] = drw_cur_create(drw, XC_fleur); + /* init appearance */ +- scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor); +- scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor); +- scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor); +- scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor); +- scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor); +- scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor); ++ for(int i = 0; i < NUMCOLORS; i++){ ++ scheme[i].border = drw_clr_create(drw, colors[i][0]); ++ scheme[i].fg = drw_clr_create(drw, colors[i][1]); ++ scheme[i].bg = drw_clr_create(drw, colors[i][2]); ++ } ++ + /* init bars */ + updatebars(); + updatestatus(); +@@ -1745,7 +1746,7 @@ unfocus(Client *c, int setfocus) + if (!c) + return; + grabbuttons(c, 0); +- XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->pix); ++ XSetWindowBorder(dpy, c->win, scheme[0].border->pix); + if (setfocus) { + XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); + XDeleteProperty(dpy, root, netatom[NetActiveWindow]); -- cgit v1.2.3