@@ -12,6 +12,7 @@ static const char selbordercolor[] = "#005577"; | |||
static const char selbgcolor[] = "#005577"; | |||
static const char selfgcolor[] = "#eeeeee"; | |||
static const unsigned int borderpx = 1; /* border pixel of windows */ | |||
static const Gap default_gap = {.isgap = 1, .realgap = 10, .gappx = 10}; | |||
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 */ | |||
@@ -91,6 +92,11 @@ static Key keys[] = { | |||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, | |||
{ MODKEY, XK_s, show, {0} }, | |||
{ MODKEY, XK_h, hide, {0} }, | |||
{ MODKEY|ShiftMask, XK_b, toggleAttachBelow, {0} }, | |||
{ MODKEY, XK_minus, setgaps, {.i = -5 } }, | |||
{ MODKEY, XK_equal, setgaps, {.i = +5 } }, | |||
{ MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, | |||
{ MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
@@ -12,6 +12,7 @@ static const char selbordercolor[] = "#005577"; | |||
static const char selbgcolor[] = "#005577"; | |||
static const char selfgcolor[] = "#eeeeee"; | |||
static const unsigned int borderpx = 1; /* border pixel of windows */ | |||
static const Gap default_gap = {.isgap = 1, .realgap = 10, .gappx = 10}; | |||
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 */ | |||
@@ -33,6 +34,7 @@ static const Rule rules[] = { | |||
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 = 1; /* 1 means respect size hints in tiled resizals */ | |||
static int attachbelow = 1; /* 1 means attach after the currently active window */ | |||
static const Layout layouts[] = { | |||
/* symbol arrange function */ | |||
@@ -90,6 +92,11 @@ static Key keys[] = { | |||
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, | |||
{ MODKEY|ShiftMask, XK_s, show, {0} }, | |||
{ MODKEY|ShiftMask, XK_h, hide, {0} }, | |||
{ MODKEY|ShiftMask, XK_b, toggleAttachBelow, {0} }, | |||
{ MODKEY, XK_minus, setgaps, {.i = -5 } }, | |||
{ MODKEY, XK_equal, setgaps, {.i = +5 } }, | |||
{ MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, | |||
{ MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
@@ -1,95 +0,0 @@ | |||
diff --git a/config.def.h b/config.def.h | |||
index 1c0b587..38d2f6c 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -2,6 +2,7 @@ | |||
/* appearance */ | |||
static const unsigned int borderpx = 1; /* border pixel of windows */ | |||
+static const unsigned int gappx = 5; /* 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 */ | |||
@@ -84,6 +85,9 @@ static Key keys[] = { | |||
{ 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, XK_equal, setgaps, {.i = +1 } }, | |||
+ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = 0 } }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
diff --git a/dwm.c b/dwm.c | |||
index 4465af1..4363627 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -119,6 +119,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]; | |||
@@ -199,6 +200,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); | |||
@@ -638,6 +640,7 @@ 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); | |||
@@ -1497,6 +1500,16 @@ 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) | |||
{ | |||
@@ -1683,16 +1696,16 @@ 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); | |||
- 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); | |||
- 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; | |||
} | |||
} | |||
2.20.1 | |||
@@ -0,0 +1,148 @@ | |||
diff --git a/config.def.h b/config.def.h | |||
index 1c0b587..b172f63 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -2,6 +2,7 @@ | |||
/* appearance */ | |||
static const unsigned int borderpx = 1; /* border pixel of windows */ | |||
+static const Gap default_gap = {.isgap = 1, .realgap = 10, .gappx = 10}; | |||
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 */ | |||
@@ -84,6 +85,10 @@ static Key keys[] = { | |||
{ 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 = -5 } }, | |||
+ { MODKEY, XK_equal, setgaps, {.i = +5 } }, | |||
+ { MODKEY|ShiftMask, XK_minus, setgaps, {.i = GAP_RESET } }, | |||
+ { MODKEY|ShiftMask, XK_equal, setgaps, {.i = GAP_TOGGLE} }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
diff --git a/dwm.c b/dwm.c | |||
index 664c527..25bc9b7 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -57,6 +57,9 @@ | |||
#define TAGMASK ((1 << LENGTH(tags)) - 1) | |||
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad) | |||
+#define GAP_TOGGLE 100 | |||
+#define GAP_RESET 0 | |||
+ | |||
/* enums */ | |||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |||
enum { SchemeNorm, SchemeSel }; /* color schemes */ | |||
@@ -111,6 +114,12 @@ typedef struct { | |||
void (*arrange)(Monitor *); | |||
} Layout; | |||
+typedef struct { | |||
+ int isgap; | |||
+ int realgap; | |||
+ int gappx; | |||
+} Gap; | |||
+ | |||
struct Monitor { | |||
char ltsymbol[16]; | |||
float mfact; | |||
@@ -119,6 +128,7 @@ struct Monitor { | |||
int by; /* bar geometry */ | |||
int mx, my, mw, mh; /* screen size */ | |||
int wx, wy, ww, wh; /* window area */ | |||
+ Gap *gap; | |||
unsigned int seltags; | |||
unsigned int sellt; | |||
unsigned int tagset[2]; | |||
@@ -169,6 +179,7 @@ static void focus(Client *c); | |||
static void focusin(XEvent *e); | |||
static void focusmon(const Arg *arg); | |||
static void focusstack(const Arg *arg); | |||
+static void gap_copy(Gap *to, const Gap *from); | |||
static Atom getatomprop(Client *c, Atom prop); | |||
static int getrootptr(int *x, int *y); | |||
static long getstate(Window w); | |||
@@ -200,6 +211,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); | |||
@@ -639,6 +651,8 @@ createmon(void) | |||
m->nmaster = nmaster; | |||
m->showbar = showbar; | |||
m->topbar = topbar; | |||
+ m->gap = malloc(sizeof(Gap)); | |||
+ gap_copy(m->gap, &default_gap); | |||
m->lt[0] = &layouts[0]; | |||
m->lt[1] = &layouts[1 % LENGTH(layouts)]; | |||
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); | |||
@@ -1498,6 +1512,35 @@ setfullscreen(Client *c, int fullscreen) | |||
} | |||
} | |||
+void | |||
+gap_copy(Gap *to, const Gap *from) | |||
+{ | |||
+ to->isgap = from->isgap; | |||
+ to->realgap = from->realgap; | |||
+ to->gappx = from->gappx; | |||
+} | |||
+ | |||
+void | |||
+setgaps(const Arg *arg) | |||
+{ | |||
+ Gap *p = selmon->gap; | |||
+ switch(arg->i) | |||
+ { | |||
+ case GAP_TOGGLE: | |||
+ p->isgap = 1 - p->isgap; | |||
+ break; | |||
+ case GAP_RESET: | |||
+ gap_copy(p, &default_gap); | |||
+ break; | |||
+ default: | |||
+ p->realgap += arg->i; | |||
+ p->isgap = 1; | |||
+ } | |||
+ p->realgap = MAX(p->realgap, 0); | |||
+ p->gappx = p->realgap * p->isgap; | |||
+ arrange(selmon); | |||
+} | |||
+ | |||
void | |||
setlayout(const Arg *arg) | |||
{ | |||
@@ -1684,18 +1727,18 @@ 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->gap->gappx; | |||
+ for (i = 0, my = ty = m->gap->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->gap->gappx; | |||
+ resize(c, m->wx + m->gap->gappx, m->wy + my, mw - (2*c->bw) - m->gap->gappx, h - (2*c->bw), 0); | |||
+ if (my + HEIGHT(c) + m->gap->gappx < m->wh) | |||
+ my += HEIGHT(c) + m->gap->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->gap->gappx; | |||
+ resize(c, m->wx + mw + m->gap->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gap->gappx, h - (2*c->bw), 0); | |||
+ if (ty + HEIGHT(c) + m->gap->gappx < m->wh) | |||
+ ty += HEIGHT(c) + m->gap->gappx; | |||
} | |||
} | |||
@@ -0,0 +1,177 @@ | |||
diff --git a/dwm.c b/dwm.c | |||
index 664c527..ac8e4ec 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -111,6 +111,7 @@ typedef struct { | |||
void (*arrange)(Monitor *); | |||
} Layout; | |||
+typedef struct Pertag Pertag; | |||
struct Monitor { | |||
char ltsymbol[16]; | |||
float mfact; | |||
@@ -130,6 +131,7 @@ struct Monitor { | |||
Monitor *next; | |||
Window barwin; | |||
const Layout *lt[2]; | |||
+ Pertag *pertag; | |||
}; | |||
typedef struct { | |||
@@ -272,6 +274,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]; }; | |||
@@ -632,6 +643,7 @@ Monitor * | |||
createmon(void) | |||
{ | |||
Monitor *m; | |||
+ unsigned int i; | |||
m = ecalloc(1, sizeof(Monitor)); | |||
m->tagset[0] = m->tagset[1] = 1; | |||
@@ -642,6 +654,20 @@ createmon(void) | |||
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; | |||
} | |||
@@ -967,7 +993,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); | |||
} | |||
@@ -1502,9 +1528,9 @@ 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); | |||
@@ -1523,7 +1549,7 @@ setmfact(const Arg *arg) | |||
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; | |||
if (f < 0.05 || f > 0.95) | |||
return; | |||
- selmon->mfact = f; | |||
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; | |||
arrange(selmon); | |||
} | |||
@@ -1702,7 +1728,7 @@ 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); | |||
@@ -1741,9 +1767,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); | |||
} | |||
@@ -2038,11 +2088,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); | |||
} |
@@ -58,6 +58,9 @@ | |||
#define TAGMASK ((1 << LENGTH(tags)) - 1) | |||
#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h) | |||
#define GAP_TOGGLE 100 | |||
#define GAP_RESET 0 | |||
/* enums */ | |||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |||
enum { SchemeNorm, SchemeSel, SchemeHid, SchemeLast }; /* color schemes */ | |||
@@ -112,6 +115,13 @@ typedef struct { | |||
void (*arrange)(Monitor *); | |||
} Layout; | |||
typedef struct { | |||
int isgap; | |||
int realgap; | |||
int gappx; | |||
} Gap; | |||
typedef struct Pertag Pertag; | |||
struct Monitor { | |||
char ltsymbol[16]; | |||
float mfact; | |||
@@ -122,6 +132,7 @@ struct Monitor { | |||
int bt; /* number of tasks */ | |||
int mx, my, mw, mh; /* screen size */ | |||
int wx, wy, ww, wh; /* window area */ | |||
Gap *gap; | |||
unsigned int seltags; | |||
unsigned int sellt; | |||
unsigned int tagset[2]; | |||
@@ -134,6 +145,7 @@ struct Monitor { | |||
Monitor *next; | |||
Window barwin; | |||
const Layout *lt[2]; | |||
Pertag *pertag; | |||
}; | |||
typedef struct { | |||
@@ -145,6 +157,7 @@ typedef struct { | |||
int monitor; | |||
} Rule; | |||
/* function declarations */ | |||
static void applyrules(Client *c); | |||
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact); | |||
@@ -178,6 +191,7 @@ static void focusmon(const Arg *arg); | |||
static void focusstackvis(const Arg *arg); | |||
static void focusstackhid(const Arg *arg); | |||
static void focusstack(int inc, int vis); | |||
static void gap_copy(Gap *to, const Gap *from); | |||
static int getrootptr(int *x, int *y); | |||
static long getstate(Window w); | |||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | |||
@@ -210,6 +224,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); | |||
@@ -285,6 +300,15 @@ 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 */ | |||
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]; }; | |||
@@ -690,6 +714,7 @@ Monitor * | |||
createmon(void) | |||
{ | |||
Monitor *m; | |||
unsigned int i; | |||
m = ecalloc(1, sizeof(Monitor)); | |||
m->tagset[0] = m->tagset[1] = 1; | |||
@@ -697,9 +722,25 @@ createmon(void) | |||
m->nmaster = nmaster; | |||
m->showbar = showbar; | |||
m->topbar = topbar; | |||
m->gap = malloc(sizeof(Gap)); | |||
gap_copy(m->gap, &default_gap); | |||
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; | |||
} | |||
@@ -1121,7 +1162,7 @@ hidewin(Client *c) { | |||
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); | |||
} | |||
@@ -1672,13 +1713,42 @@ setfullscreen(Client *c, int fullscreen) | |||
} | |||
} | |||
void | |||
gap_copy(Gap *to, const Gap *from) | |||
{ | |||
to->isgap = from->isgap; | |||
to->realgap = from->realgap; | |||
to->gappx = from->gappx; | |||
} | |||
void | |||
setgaps(const Arg *arg) | |||
{ | |||
Gap *p = selmon->gap; | |||
switch(arg->i) | |||
{ | |||
case GAP_TOGGLE: | |||
p->isgap = 1 - p->isgap; | |||
break; | |||
case GAP_RESET: | |||
gap_copy(p, &default_gap); | |||
break; | |||
default: | |||
p->realgap += arg->i; | |||
p->isgap = 1; | |||
} | |||
p->realgap = MAX(p->realgap, 0); | |||
p->gappx = p->realgap * p->isgap; | |||
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); | |||
@@ -1697,7 +1767,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); | |||
} | |||
@@ -1853,23 +1923,25 @@ 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->gap->gappx; | |||
for (i = 0, my = ty = m->gap->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); | |||
my += HEIGHT(c); | |||
h = (m->wh - my) / (MIN(n, m->nmaster) - i) - m->gap->gappx; | |||
resize(c, m->wx + m->gap->gappx, m->wy + my, mw - (2*c->bw) - m->gap->gappx, h - (2*c->bw), 0); | |||
if (my + HEIGHT(c) + m->gap->gappx < m->wh) | |||
my += HEIGHT(c) + m->gap->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); | |||
ty += HEIGHT(c); | |||
h = (m->wh - ty) / (n - i) - m->gap->gappx; | |||
resize(c, m->wx + mw + m->gap->gappx, m->wy + ty, m->ww - mw - (2*c->bw) - 2*m->gap->gappx, h - (2*c->bw), 0); | |||
if (ty + HEIGHT(c) + m->gap->gappx < m->wh) | |||
ty += HEIGHT(c) + m->gap->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); | |||
@@ -1908,9 +1980,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); | |||
} | |||
@@ -2229,11 +2325,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); | |||
} | |||