tAdd customize - dwm - [fork] customized build of dwm, the dynamic window manager
 (HTM) git clone git://src.adamsgaard.dk/dwm
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 7c099bd74e3f1691da859a1277a501ebe4d53fd6
 (DIR) parent f09418bbb6651ab4c299cfefbe1d18de401f630e
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Sat, 23 May 2020 20:35:34 +0200
       
       Add customize
       
       Diffstat:
         M LICENSE                             |       1 +
         A config.h                            |     241 +++++++++++++++++++++++++++++++
         M config.mk                           |       2 +-
         M dwm.c                               |     185 +++++++++++++++++++++++++------
       
       4 files changed, 396 insertions(+), 33 deletions(-)
       ---
 (DIR) diff --git a/LICENSE b/LICENSE
       t@@ -17,6 +17,7 @@ MIT/X Consortium License
        © 2015-2016 Quentin Rameau <quinq@fifth.space>
        © 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
        © 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
       +© 2019-2020 Anders Damsgaard <anders@adamsgaard.dk>
        
        Permission is hereby granted, free of charge, to any person obtaining a
        copy of this software and associated documentation files (the "Software"),
 (DIR) diff --git a/config.h b/config.h
       t@@ -0,0 +1,241 @@
       +/* See LICENSE file for copyright and license details. */
       +
       +/* appearance */
       +static const unsigned int borderpx  = 0;        /* border pixel of windows */
       +static const unsigned int gappx     = 0;        /* gaps 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 */
       +static const char *fonts[]          = { "dina:size=9:antialias=false" };
       +static const char col_gray1[] = "#1d1f21";
       +static const char col_gray2[] = "#444444";
       +static const char col_gray3[] = "#c5c8c6";
       +static const char col_gray4[] = "#1d1f21";
       +static const char col_cyan[] = "#8abeb7";
       +static const char *colors[][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" };
       +/* static const char *tags[] = { "一", "二", "三", "四", "五", "六", "七", "八", "九" }; */
       +
       +
       +/* floatpos:
       + *    1--2--3
       + *    4--5--6
       + *    7--8--9 
       + * 0: disabled */
       +static const Rule rules[] = {
       +        /* xprop(1):
       +         *        WM_CLASS(STRING) = instance, class
       +         *        WM_NAME(STRING) = title
       +         */
       +        /* class         instance  title         tags   floatpos  isfloating  monitor */
       +        { "Tor Browser", NULL,     NULL,         0,     5,        1,          -1 },
       +        { "tabbed",      NULL,     NULL,         1<<1,  0,        0,          -1 },
       +        { "Firefox",     NULL,     NULL,         1<<1,  0,        0,          -1 },
       +        { "Signal",      NULL,     NULL,         1<<8,  0,        0,          -1 },
       +        { NULL,          NULL,     "video",      ~0,    9,        1,          -1 },
       +        { NULL,          NULL,     "topleft",    0,     1,        1,          -1 },
       +        { NULL,          NULL,     "topcenter",  0,     2,        1,          -1 },
       +        { NULL,          NULL,     "topright",   0,     3,        1,          -1 },
       +        { NULL,          NULL,     "midleft",    0,     4,        1,          -1 },
       +        { NULL,          NULL,     "midcenter",  0,     5,        1,          -1 },
       +        { NULL,          NULL,     "midright",   0,     6,        1,          -1 },
       +        { NULL,          NULL,     "botleft",    0,     7,        1,          -1 },
       +        { NULL,          NULL,     "botcenter",  0,     8,        1,          -1 },
       +        { NULL,          NULL,     "botright",   0,     9,        1,          -1 },
       +};
       +
       +/* 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 */
       +static const int resizehints = 0;    /* 1 means respect size hints in tiled resizals */
       +
       +static const Layout layouts[] = {
       +        /* symbol     arrange function */
       +        { "",       tile },    /* first entry is default */
       +        { "F",      NULL },    /* no layout function means floating behavior */
       +        { "M",      monocle },
       +};
       +
       +/* key definitions */
       +#define MODKEY Mod1Mask
       +#define MODALTKEY Mod4Mask
       +#define TAGKEYS(KEY,TAG) \
       +        { MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
       +        { MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
       +        { MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
       +        { MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
       +
       +
       +static char dmenumon[2] = "0";
       +
       +#define HOME "/home/ad"
       +#define TERMINAL "st"
       +#define EDITOR "vi"
       +#define BROWSER "firefox.sh"
       +
       +/* helper for spawning shell commands in the pre dwm-5.0 fashion */
       +#define TERMCMD(...)   {TERMINAL, "-e", __VA_ARGS__, NULL}
       +#define DUPLEXCMD(cmd) {TERMINAL, "-e", "tmux", "new-session", cmd, NULL}
       +#define DUPLEXATTACHCMD(name, cmd) {TERMINAL, "-e", "tmux", "new-session", "-A", "-s", name, cmd, NULL}
       +
       +/* commands */
       +static const char *termcmd[]           = TERMCMD("ksh", "-l");
       +static const char *termplexcmd[]       = TERMCMD("tmux");
       +
       +static const char *dmenucmd[]          = {"dmenu_run", NULL};
       +static const char *searchcmd[]         = {"search", NULL};
       +static const char *articlesearchcmd[]  = {"articlesearch", NULL};
       +static const char *jabbrevcmd[]        = {"jabbrev", "-c", NULL};
       +static const char *unicodecmd[]        = {"unicodepick", NULL};
       +static const char *definecmd[]         = {"define", "--gui", NULL};
       +static const char *passcmd[]           = {"passmenu", "-t", "-n", NULL};
       +static const char *passemailcmd[]      = {"passmenu", "-t", "-u", "anders@adamsgaard.dk\t", "-n", NULL};
       +static const char *displaycmd[]        = {"displayselect", NULL};
       +static const char *torrentcmd[]        = {"t-daemon-toggle", NULL};
       +static const char *mountcmd[]          = {"dmenumount", NULL};
       +static const char *umountcmd[]         = {"dmenuumount", NULL};
       +static const char *contactscmd[]       = {"contactmenu", NULL};
       +static const char *textcmd[]           = {"text.sh", "-i", NULL};
       +static const char *videocmd[]          = {"videotoggle", NULL};
       +static const char *screenrecordcmd[]   = {"screenrecord", NULL};
       +
       +static const char *plumbcmd[]          = {"clipplumb", NULL};
       +static const char *plumb2cmd[]         = {"clipplumb", "-c", NULL};
       +static const char *showclipcmd[]       = {"showclip", NULL};
       +static const char *xlockcmd[]          = {"slock", NULL};
       +static const char *printscreencmd[]    = {"maimfull", NULL};
       +static const char *printscreenicmd[]   = {"maimpick", NULL};
       +static const char *keyboardlayoutcmd[] = {"keyboard-layout-switch.sh", NULL};
       +
       +static const char *fuzzylaunchcmd[]    = TERMCMD("fuzzylaunch");
       +static const char *journalcmd[]        = TERMCMD("tmux-journal.sh");
       +static const char *browsercmd[]        = {BROWSER, NULL};
       +static const char *torbrowsercmd[]     = {"tor-browser", NULL};
       +static const char *todocmd[]           = DUPLEXATTACHCMD("todo", EDITOR " " HOME "/doc/todo/todo.md");
       +static const char *calendarcmd[]       = DUPLEXATTACHCMD("calendar", "calendar.sh");
       +/* static const char *filecmd[]           = TERMCMD("sh", "-c", "cd ~/tmp; ls -p; $SHELL -l"); */
       +static const char *mailcmd[]           = DUPLEXCMD("mutt");
       +static const char *irccmd[]            = DUPLEXATTACHCMD("irc", "ssh -t irc@adamsgaard.dk 'tmux -u new-session -A -D -s irc irssi'");
       +static const char *topcmd[]            = TERMCMD("top", "-C");
       +
       +static const char *mixercmd[]          = TERMCMD("audiomixer");
       +static const char *musiccmd[]          = TERMCMD("ncmpc");
       +static const char *mpdtogglecmd[]      = {"mpc", "toggle", NULL};
       +static const char *mpdnextcmd[]        = {"mpc", "next", NULL};
       +static const char *mpdprevcmd[]        = {"mpc", "prev", NULL};
       +static const char *mpdstopcmd[]        = {"mpc", "stop", NULL};
       +
       +static const char *audioextvolupcmd[]       = {"sndioctl", "output.level=+0.05", NULL};
       +static const char *audioextvoldncmd[]       = {"sndioctl", "output.level=-0.05", NULL};
       +static const char *audioextmutecmd[]        = {"sndioctl", "output.mute=!", NULL};
       +
       +/* see key names in /usr/include/X11/keysymdef.h */
       +static Key keys[] = {
       +        /* modifier                     key        function        argument */
       +        { MODKEY|ShiftMask,             XK_Return, spawn,          {.v = termcmd } },
       +        { MODKEY,                       XK_Return, spawn,          {.v = termplexcmd } },
       +
       +        { MODKEY|ShiftMask,             XK_space,  spawn,          {.v = dmenucmd } },
       +        { MODKEY,                       XK_space,  spawn,          {.v = searchcmd } },
       +        { MODKEY,                       XK_a,      spawn,          {.v = articlesearchcmd } },
       +        { MODKEY|ShiftMask,             XK_a,      spawn,          {.v = jabbrevcmd } },
       +        { MODKEY,                       XK_o,      spawn,          {.v = fuzzylaunchcmd } },
       +        { MODKEY,                       XK_grave,  spawn,          {.v = unicodecmd } },
       +        { MODKEY,                       XK_slash,  spawn,          {.v = definecmd } },
       +        { MODKEY,                       XK_p,      spawn,          {.v = passcmd } },
       +        { MODKEY|ShiftMask,             XK_p,      spawn,          {.v = passemailcmd } },
       +        { MODKEY,                       XK_F7,     spawn,          {.v = displaycmd } },
       +        { MODKEY,                       XK_F8,     spawn,          {.v = torrentcmd } },
       +        { MODKEY,                       XK_F9,     spawn,          {.v = mountcmd } },
       +        { MODKEY,                       XK_F10,    spawn,          {.v = umountcmd } },
       +        { MODKEY,                       XK_F11,    spawn,          {.v = contactscmd } },
       +
       +        { MODKEY,                       XK_u,      spawn,          {.v = plumbcmd } },
       +        { MODKEY|ShiftMask,             XK_u,      spawn,          {.v = plumb2cmd } },
       +        { MODKEY,                       XK_x,      spawn,          {.v = xlockcmd } },
       +        { 0,                            XK_Print,  spawn,          {.v = printscreencmd } },
       +        { ShiftMask,                    XK_Print,  spawn,          {.v = printscreenicmd } },
       +        { MODKEY|ShiftMask,             XK_c,      spawn,          {.v = showclipcmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_l,      spawn,          {.v = keyboardlayoutcmd } },
       +        
       +        { MODKEY,                       XK_v,      spawn,          {.v = videocmd } },
       +        { MODKEY,                       XK_r,      spawn,          {.v = screenrecordcmd } },
       +        { MODKEY,                       XK_c,      spawn,          {.v = calendarcmd } },
       +        { MODKEY,                       XK_d,      spawn,          {.v = todocmd } },
       +        { MODKEY|ShiftMask,             XK_d,      spawn,          {.v = journalcmd } },
       +        { MODKEY,                       XK_w,      spawn,          {.v = browsercmd } },
       +        { MODKEY|ShiftMask,             XK_w,      spawn,          {.v = torbrowsercmd } },
       +        { MODKEY,                       XK_t,      spawn,          {.v = textcmd } },
       +        { MODKEY,                       XK_m,      spawn,          {.v = mailcmd } },
       +        { MODKEY,                       XK_i,      spawn,          {.v = irccmd } },
       +        { MODKEY|ShiftMask,             XK_o,      spawn,          {.v = topcmd } },
       +
       +        { MODKEY|ControlMask|ShiftMask, XK_a,      spawn,          {.v = mixercmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_m,      spawn,          {.v = musiccmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_p,      spawn,          {.v = mpdtogglecmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_n,      spawn,          {.v = mpdnextcmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_b,      spawn,          {.v = mpdprevcmd } },
       +        { MODKEY|ControlMask|ShiftMask, XK_s,      spawn,          {.v = mpdstopcmd } },
       +        { ShiftMask,      XF86XK_AudioRaiseVolume, spawn,          {.v = audioextvolupcmd } },
       +        { ShiftMask,      XF86XK_AudioLowerVolume, spawn,          {.v = audioextvoldncmd } },
       +        { ShiftMask,      XF86XK_AudioMute,        spawn,          {.v = audioextmutecmd } },
       +
       +        { MODKEY|MODALTKEY,             XK_b,      togglebar,      {0} },
       +        { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
       +        { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
       +        { MODKEY|ShiftMask,             XK_j,      incnmaster,     {.i = +1 } },
       +        { MODKEY|ShiftMask,             XK_k,      incnmaster,     {.i = -1 } },
       +        { MODKEY,                       XK_h,      setmfact,       {.f = -0.05} },
       +        { MODKEY,                       XK_l,      setmfact,       {.f = +0.05} },
       +        { MODKEY,                       XK_Tab,    view,           {0} },
       +        { MODKEY,                       XK_q,      killclient,     {0} },
       +        { MODKEY|ShiftMask,             XK_t,      setlayout,      {.v = &layouts[0]} },
       +        { MODKEY|ShiftMask,             XK_l,      setlayout,      {.v = &layouts[1]} },
       +        { MODKEY|ShiftMask,             XK_m,      setlayout,      {.v = &layouts[2]} },
       +        { MODKEY|ShiftMask,             XK_f,      togglefloating, {0} },
       +        { MODKEY,                       XK_f,      zoom,           {0} },
       +        { MODKEY,                       XK_0,      view,           {.ui = ~0 } },
       +        { MODKEY|ShiftMask,             XK_0,      tag,            {.ui = ~0 } },
       +        { MODKEY,                       XK_comma,  focusmon,       {.i = -1 } },
       +        { MODKEY,                       XK_period, focusmon,       {.i = +1 } },
       +        { MODKEY|ShiftMask,             XK_comma,  tagmon,         {.i = -1 } },
       +        { MODKEY|ShiftMask,             XK_period, tagmon,         {.i = +1 } },
       +        { MODKEY,                       XK_minus,  setgaps,        {.i = -1 } },
       +        { MODKEY|ShiftMask,             XK_equal,  setgaps,        {.i = +1 } },
       +        { MODKEY|MODALTKEY,             XK_equal,  setgaps,        {.i = 0  } },
       +        { MODKEY,                       XK_equal,  setgaps,        {.i = gappx } },
       +        TAGKEYS(                        XK_1,                      0)
       +        TAGKEYS(                        XK_2,                      1)
       +        TAGKEYS(                        XK_3,                      2)
       +        TAGKEYS(                        XK_4,                      3)
       +        TAGKEYS(                        XK_5,                      4)
       +        TAGKEYS(                        XK_6,                      5)
       +        TAGKEYS(                        XK_7,                      6)
       +        TAGKEYS(                        XK_8,                      7)
       +        TAGKEYS(                        XK_9,                      8)
       +        { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
       +};
       +
       +/* button definitions */
       +/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
       +static Button buttons[] = {
       +        /* click                event mask      button          function        argument */
       +        { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
       +        { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
       +        { ClkWinTitle,          0,              Button2,        zoom,           {0} },
       +        { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
       +        { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
       +        { ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
       +        { ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
       +        { ClkTagBar,            0,              Button1,        view,           {0} },
       +        { ClkTagBar,            0,              Button3,        toggleview,     {0} },
       +        { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
       +        { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
       +};
       +
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -18,7 +18,7 @@ XINERAMAFLAGS = -DXINERAMA
        FREETYPELIBS = -lfontconfig -lXft
        FREETYPEINC = /usr/include/freetype2
        # OpenBSD (uncomment)
       -#FREETYPEINC = ${X11INC}/freetype2
       +FREETYPEINC = ${X11INC}/freetype2
        
        # includes and libs
        INCS = -I${X11INC} -I${FREETYPEINC}
 (DIR) diff --git a/dwm.c b/dwm.c
       t@@ -41,6 +41,9 @@
        #endif /* XINERAMA */
        #include <X11/Xft/Xft.h>
        
       +/* for multimedia keys */
       +#include <X11/XF86keysym.h>
       +
        #include "drw.h"
        #include "util.h"
        
       t@@ -92,7 +95,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, floatpos, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
                Client *next;
                Client *snext;
                Monitor *mon;
       t@@ -111,6 +114,7 @@ typedef struct {
                void (*arrange)(Monitor *);
        } Layout;
        
       +typedef struct Pertag Pertag;
        struct Monitor {
                char ltsymbol[16];
                float mfact;
       t@@ -119,6 +123,7 @@ struct Monitor {
                int by;               /* bar geometry */
                int mx, my, mw, mh;   /* screen size */
                int wx, wy, ww, wh;   /* window area  */
       +        int gappx;            /* gaps between windows */
                unsigned int seltags;
                unsigned int sellt;
                unsigned int tagset[2];
       t@@ -130,6 +135,7 @@ struct Monitor {
                Monitor *next;
                Window barwin;
                const Layout *lt[2];
       +        Pertag *pertag;
        };
        
        typedef struct {
       t@@ -137,6 +143,7 @@ typedef struct {
                const char *instance;
                const char *title;
                unsigned int tags;
       +        int floatpos;
                int isfloating;
                int monitor;
        } Rule;
       t@@ -169,7 +176,6 @@ static void focus(Client *c);
        static void focusin(XEvent *e);
        static void focusmon(const Arg *arg);
        static void focusstack(const Arg *arg);
       -static Atom getatomprop(Client *c, Atom prop);
        static int getrootptr(int *x, int *y);
        static long getstate(Window w);
        static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
       t@@ -200,6 +206,7 @@ static void sendmon(Client *c, Monitor *m);
        static void setclientstate(Client *c, long state);
        static void setfocus(Client *c);
        static void setfullscreen(Client *c, int fullscreen);
       +static void setgaps(const Arg *arg);
        static void setlayout(const Arg *arg);
        static void setmfact(const Arg *arg);
        static void setup(void);
       t@@ -272,6 +279,15 @@ static Window root, wmcheckwin;
        /* 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  */
       +        int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
       +};
       +
        /* compile-time check if all tags fit into an unsigned int bit array. */
        struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
        
       t@@ -286,6 +302,7 @@ applyrules(Client *c)
                XClassHint ch = { NULL, NULL };
        
                /* rule matching */
       +        c->floatpos = 0;
                c->isfloating = 0;
                c->tags = 0;
                XGetClassHint(dpy, c->win, &ch);
       t@@ -299,6 +316,7 @@ applyrules(Client *c)
                        && (!r->instance || strstr(instance, r->instance)))
                        {
                                c->isfloating = r->isfloating;
       +                        c->floatpos = r->floatpos;
                                c->tags |= r->tags;
                                for (m = mons; m && m->num != r->monitor; m = m->next);
                                if (m)
       t@@ -417,7 +435,7 @@ attachstack(Client *c)
        void
        buttonpress(XEvent *e)
        {
       -        unsigned int i, x, click;
       +        unsigned int i, x, click, occ = 0;
                Arg arg = {0};
                Client *c;
                Monitor *m;
       t@@ -432,9 +450,14 @@ buttonpress(XEvent *e)
                }
                if (ev->window == selmon->barwin) {
                        i = x = 0;
       -                do
       +                for (c = m->clients; c; c = c->next)
       +                        occ |= c->tags == 255 ? 0 : 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]);
       -                while (ev->x >= x && ++i < LENGTH(tags));
       +                } while (ev->x >= x && ++i < LENGTH(tags));
                        if (i < LENGTH(tags)) {
                                click = ClkTagBar;
                                arg.ui = 1 << i;
       t@@ -632,6 +655,7 @@ Monitor *
        createmon(void)
        {
                Monitor *m;
       +        unsigned int i;
        
                m = ecalloc(1, sizeof(Monitor));
                m->tagset[0] = m->tagset[1] = 1;
       t@@ -639,9 +663,24 @@ createmon(void)
                m->nmaster = nmaster;
                m->showbar = showbar;
                m->topbar = topbar;
       +        m->gappx = gappx;
                m->lt[0] = &layouts[0];
                m->lt[1] = &layouts[1 % LENGTH(layouts)];
                strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
       +        m->pertag = ecalloc(1, sizeof(Pertag));
       +        m->pertag->curtag = m->pertag->prevtag = 1;
       +
       +        for (i = 0; i <= LENGTH(tags); i++) {
       +                m->pertag->nmasters[i] = m->nmaster;
       +                m->pertag->mfacts[i] = m->mfact;
       +
       +                m->pertag->ltidxs[i][0] = m->lt[0];
       +                m->pertag->ltidxs[i][1] = m->lt[1];
       +                m->pertag->sellts[i] = m->sellt;
       +
       +                m->pertag->showbars[i] = m->showbar;
       +        }
       +
                return m;
        }
        
       t@@ -696,7 +735,7 @@ dirtomon(int dir)
        void
        drawbar(Monitor *m)
        {
       -        int x, w, tw = 0;
       +        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;
       t@@ -705,33 +744,33 @@ drawbar(Monitor *m)
                /* 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);
       +                sw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
       +                drw_text(drw, m->ww - sw, 0, sw, bh, 0, stext, 0);
                }
        
                for (c = m->clients; c; c = c->next) {
       -                occ |= c->tags;
       +                occ |= c->tags == 255 ? 0 : c->tags;
                        if (c->isurgent)
                                urg |= c->tags;
                }
                x = 0;
                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;
                }
                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 ((w = m->ww - sw - x) > bh) {
                        if (m->sel) {
       -                        drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
       +                        /*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);
       t@@ -967,7 +1006,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);
        }
        
       t@@ -1050,6 +1089,30 @@ manage(Window w, XWindowAttributes *wa)
                        && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
                c->bw = borderpx;
        
       +        switch (c->floatpos) {
       +                case 1: case 4: case 7:
       +                        c->x = 0;
       +                        break;
       +                case 3: case 6: case 9:
       +                        c->x = c->mon->mw - WIDTH(c);
       +                        break;
       +                case 2: case 5: case 8: default:
       +                        c->x = (c->mon->mw - WIDTH(c)) / 2;
       +                        break;
       +        }
       +
       +        switch (c->floatpos) {
       +                case 1: case 2: case 3:
       +                        c->y = 0;
       +                        break;
       +                case 7: case 8: case 9:
       +                        c->y = c->mon->mh - HEIGHT(c);
       +                        break;
       +                case 4: case 5: case 6: default:
       +                        c->y = (c->mon->mh - HEIGHT(c)) / 2;
       +                        break;
       +        }
       +
                wc.border_width = c->bw;
                XConfigureWindow(dpy, w, CWBorderWidth, &wc);
                XSetWindowBorder(dpy, w, scheme[SchemeNorm][ColBorder].pixel);
       t@@ -1499,12 +1562,22 @@ setfullscreen(Client *c, int fullscreen)
        }
        
        void
       +setgaps(const Arg *arg)
       +{
       +        if ((arg->i == 0) || (selmon->gappx + arg->i < 0))
       +                selmon->gappx = 0;
       +        else
       +                selmon->gappx += arg->i;
       +        arrange(selmon);
       +}
       +
       +void
        setlayout(const Arg *arg)
        {
                if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
       -                selmon->sellt ^= 1;
       +                selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
                if (arg && arg->v)
       -                selmon->lt[selmon->sellt] = (Layout *)arg->v;
       +                selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
                strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
                if (selmon->sel)
                        arrange(selmon);
       t@@ -1521,9 +1594,9 @@ setmfact(const Arg *arg)
                if (!arg || !selmon->lt[selmon->sellt]->arrange)
                        return;
                f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
       -        if (f < 0.05 || f > 0.95)
       +        if (f < 0.1 || f > 0.9)
                        return;
       -        selmon->mfact = f;
       +        selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
                arrange(selmon);
        }
        
       t@@ -1684,25 +1757,23 @@ tile(Monitor *m)
                if (n > m->nmaster)
                        mw = m->nmaster ? m->ww * m->mfact : 0;
                else
       -                mw = m->ww;
       -        for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
       +                mw = m->ww - m->gappx;
       +        for (i = 0, my = ty = m->gappx, 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);
       -                        if (my + HEIGHT(c) < m->wh)
       -                                my += HEIGHT(c);
       +                        h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gappx;
       +                        resize(c, m->wx + m->gappx, m->wy + my, mw - (2*c->bw) - m->gappx, h - (2*c->bw), 0);
       +                        my += HEIGHT(c) + m->gappx;
                        } 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);
       -                        if (ty + HEIGHT(c) < m->wh)
       -                                ty += HEIGHT(c);
       +                        h = (m->wh - ty) / (n - i) - m->gappx;
       +                        resize(c, m->wx + mw + m->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gappx, h - (2*c->bw), 0);
       +                        ty += HEIGHT(c) + m->gappx;
                        }
        }
        
        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);
       t@@ -1741,9 +1812,33 @@ void
        toggleview(const Arg *arg)
        {
                unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
       +        int i;
        
                if (newtagset) {
                        selmon->tagset[selmon->seltags] = 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;
       +                }
       +
       +                /* 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);
                }
       t@@ -2038,11 +2133,37 @@ updatewmhints(Client *c)
        void
        view(const Arg *arg)
        {
       +        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->tagset[selmon->seltags] = arg->ui & TAGMASK;
       +                selmon->pertag->prevtag = selmon->pertag->curtag;
       +
       +                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);
        }