@@ -0,0 +1,5 @@ | |||
*.sw[op] | |||
*.o | |||
*.rej | |||
*.orig | |||
ses |
@@ -39,6 +39,8 @@ static const Layout layouts[] = { | |||
{ "[]=", tile }, /* first entry is default */ | |||
{ "><>", NULL }, /* no layout function means floating behavior */ | |||
{ "[M]", monocle }, | |||
{ "|M|", centeredmaster }, | |||
{ ">M>", centeredfloatingmaster }, | |||
}; | |||
/* key definitions */ | |||
@@ -62,8 +64,10 @@ static Key keys[] = { | |||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, | |||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, | |||
{ MODKEY, XK_b, togglebar, {0} }, | |||
{ MODKEY, XK_j, focusstack, {.i = +1 } }, | |||
{ MODKEY, XK_k, focusstack, {.i = -1 } }, | |||
{ MODKEY, XK_j, focusstackvis, {.i = +1 } }, | |||
{ MODKEY, XK_k, focusstackvis, {.i = -1 } }, | |||
{ MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, | |||
{ MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, | |||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, | |||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, | |||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, | |||
@@ -74,6 +78,8 @@ static Key keys[] = { | |||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, | |||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, | |||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, | |||
{ MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, | |||
{ MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, | |||
{ MODKEY, XK_space, setlayout, {0} }, | |||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, | |||
{ MODKEY, XK_0, view, {.ui = ~0 } }, | |||
@@ -82,6 +88,8 @@ 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_s, show, {0} }, | |||
{ MODKEY, XK_h, hide, {0} }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
@@ -100,6 +108,7 @@ static Button buttons[] = { | |||
/* click event mask button function argument */ | |||
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, | |||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, | |||
{ ClkWinTitle, 0, Button1, togglewin, {0} }, | |||
{ ClkWinTitle, 0, Button2, zoom, {0} }, | |||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, | |||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, | |||
@@ -0,0 +1,121 @@ | |||
/* See LICENSE file for copyright and license details. */ | |||
/* appearance */ | |||
static const char *fonts[] = { | |||
"monospace:size=10" | |||
}; | |||
static const char dmenufont[] = "monospace:size=10"; | |||
static const char normbordercolor[] = "#444444"; | |||
static const char normbgcolor[] = "#222222"; | |||
static const char normfgcolor[] = "#bbbbbb"; | |||
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 unsigned int snap = 32; /* snap pixel */ | |||
static const int showbar = 1; /* 0 means no bar */ | |||
static const int topbar = 1; /* 0 means bottom bar */ | |||
/* tagging */ | |||
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; | |||
static const Rule rules[] = { | |||
/* xprop(1): | |||
* WM_CLASS(STRING) = instance, class | |||
* WM_NAME(STRING) = title | |||
*/ | |||
/* class instance title tags mask isfloating monitor */ | |||
{ "Gimp", NULL, NULL, 0, 1, -1 }, | |||
{ "Iceweasel", NULL, NULL, 1 << 8, 0, -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 = 1; /* 1 means respect size hints in tiled resizals */ | |||
static const Layout layouts[] = { | |||
/* symbol arrange function */ | |||
{ "[]=", tile }, /* first entry is default */ | |||
{ "><>", NULL }, /* no layout function means floating behavior */ | |||
{ "[M]", monocle }, | |||
{ "|M|", centeredmaster }, | |||
{ ">M>", centeredfloatingmaster }, | |||
}; | |||
/* key definitions */ | |||
#define MODKEY 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} }, | |||
/* helper for spawning shell commands in the pre dwm-5.0 fashion */ | |||
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } } | |||
/* commands */ | |||
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ | |||
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL }; | |||
static const char *termcmd[] = { "x-terminal-emulator", NULL }; | |||
static Key keys[] = { | |||
/* modifier key function argument */ | |||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, | |||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, | |||
{ MODKEY, XK_b, togglebar, {0} }, | |||
{ MODKEY, XK_j, focusstackvis, {.i = +1 } }, | |||
{ MODKEY, XK_k, focusstackvis, {.i = -1 } }, | |||
{ MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, | |||
{ MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, | |||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, | |||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, | |||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, | |||
{ MODKEY, XK_l, setmfact, {.f = +0.05} }, | |||
{ MODKEY, XK_Return, zoom, {0} }, | |||
{ MODKEY, XK_Tab, view, {0} }, | |||
{ MODKEY|ShiftMask, XK_c, killclient, {0} }, | |||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, | |||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, | |||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, | |||
{ MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, | |||
{ MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, | |||
{ MODKEY, XK_space, setlayout, {0} }, | |||
{ MODKEY|ShiftMask, XK_space, togglefloating, {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|ShiftMask, XK_s, show, {0} }, | |||
{ MODKEY|ShiftMask, XK_h, hide, {0} }, | |||
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 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, Button1, togglewin, {0} }, | |||
{ 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} }, | |||
}; |
@@ -0,0 +1,199 @@ | |||
From ee036687ed9e1bb973b9e34694a57cf5dd67652d Mon Sep 17 00:00:00 2001 | |||
From: Jonathan Hodgson <git@jonathanh.co.uk> | |||
Date: Mon, 6 May 2019 18:34:40 +0100 | |||
Subject: [PATCH 1/4] Adds attach below option | |||
--- | |||
config.def.h | 1 + | |||
dwm.c | 31 ++++++++++++++++++++++++++++--- | |||
2 files changed, 29 insertions(+), 3 deletions(-) | |||
diff --git a/config.def.h b/config.def.h | |||
index 1c0b587..51ad933 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -35,6 +35,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 const int attachbelow = 1; /* 1 means attach at the end */ | |||
static const Layout layouts[] = { | |||
/* symbol arrange function */ | |||
diff --git a/dwm.c b/dwm.c | |||
index 4465af1..bd715a2 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -147,6 +147,7 @@ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interac | |||
static void arrange(Monitor *m); | |||
static void arrangemon(Monitor *m); | |||
static void attach(Client *c); | |||
+static void attachBelow(Client *c); | |||
static void attachstack(Client *c); | |||
static void buttonpress(XEvent *e); | |||
static void checkotherwm(void); | |||
@@ -405,6 +406,21 @@ attach(Client *c) | |||
c->next = c->mon->clients; | |||
c->mon->clients = c; | |||
} | |||
+void | |||
+attachBelow(Client *c) | |||
+{ | |||
+ //If there is nothing on the monitor or the selected client is floating, attach as normal | |||
+ if(c->mon->sel == NULL || c->mon->sel == c || c->mon->sel->isfloating) { | |||
+ attach(c); | |||
+ return; | |||
+ } | |||
+ | |||
+ //Set the new client's next property to the same as the currently selected clients next | |||
+ c->next = c->mon->sel->next; | |||
+ //Set the currently selected clients next property to the new client | |||
+ c->mon->sel->next = c; | |||
+ | |||
+} | |||
void | |||
attachstack(Client *c) | |||
@@ -1062,7 +1078,10 @@ manage(Window w, XWindowAttributes *wa) | |||
c->isfloating = c->oldstate = trans != None || c->isfixed; | |||
if (c->isfloating) | |||
XRaiseWindow(dpy, c->win); | |||
- attach(c); | |||
+ if( attachbelow ) | |||
+ attachBelow(c); | |||
+ else | |||
+ attach(c); | |||
attachstack(c); | |||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, | |||
(unsigned char *) &(c->win), 1); | |||
@@ -1417,7 +1436,10 @@ sendmon(Client *c, Monitor *m) | |||
detachstack(c); | |||
c->mon = m; | |||
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */ | |||
- attach(c); | |||
+ if( attachbelow ) | |||
+ attachBelow(c); | |||
+ else | |||
+ attach(c); | |||
attachstack(c); | |||
focus(NULL); | |||
arrange(NULL); | |||
@@ -1897,7 +1919,10 @@ updategeom(void) | |||
m->clients = c->next; | |||
detachstack(c); | |||
c->mon = mons; | |||
- attach(c); | |||
+ if( attachbelow ) | |||
+ attachBelow(c); | |||
+ else | |||
+ attach(c); | |||
attachstack(c); | |||
} | |||
if (m == selmon) | |||
-- | |||
2.21.0 | |||
From e212c1d8cbdcc56c33c717131dfa7c1689e27e9f Mon Sep 17 00:00:00 2001 | |||
From: Jonathan Hodgson <git@jonathanh.co.uk> | |||
Date: Mon, 6 May 2019 19:27:57 +0100 | |||
Subject: [PATCH 2/4] fixes comment | |||
--- | |||
config.def.h | 2 +- | |||
1 file changed, 1 insertion(+), 1 deletion(-) | |||
diff --git a/config.def.h b/config.def.h | |||
index 51ad933..cb8053a 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -35,7 +35,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 const int attachbelow = 1; /* 1 means attach at the end */ | |||
+static const int attachbelow = 1; /* 1 means attach after the currently active window */ | |||
static const Layout layouts[] = { | |||
/* symbol arrange function */ | |||
-- | |||
2.21.0 | |||
From 7568ea3f8756e7e82b30c4943556ae646a445d1c Mon Sep 17 00:00:00 2001 | |||
From: Jonathan Hodgson <git@jonathanh.co.uk> | |||
Date: Mon, 6 May 2019 20:00:30 +0100 | |||
Subject: [PATCH 3/4] Makes changes to man page to reflect attach below patch | |||
--- | |||
dwm.1 | 3 +++ | |||
1 file changed, 3 insertions(+) | |||
diff --git a/dwm.1 b/dwm.1 | |||
index 13b3729..fb6e76c 100644 | |||
--- a/dwm.1 | |||
+++ b/dwm.1 | |||
@@ -29,6 +29,9 @@ 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 | |||
+The attach below patch makes newly spawned windows attach after the currently | |||
+selected window | |||
+.P | |||
dwm draws a small border around windows to indicate the focus state. | |||
.SH OPTIONS | |||
.TP | |||
-- | |||
2.21.0 | |||
From 362b95a5b9f91673f27f3e3343b5738df3c9d6e9 Mon Sep 17 00:00:00 2001 | |||
From: Jonathan Hodgson <git@jonathanh.co.uk> | |||
Date: Sun, 2 Jun 2019 15:11:57 +0100 | |||
Subject: [PATCH 4/4] Allows attach below to be toggled | |||
--- | |||
config.def.h | 2 +- | |||
dwm.c | 6 ++++++ | |||
2 files changed, 7 insertions(+), 1 deletion(-) | |||
diff --git a/config.def.h b/config.def.h | |||
index cb8053a..b4d35aa 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -35,7 +35,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 const int attachbelow = 1; /* 1 means attach after the currently active window */ | |||
+static int attachbelow = 1; /* 1 means attach after the currently active window */ | |||
static const Layout layouts[] = { | |||
/* symbol arrange function */ | |||
diff --git a/dwm.c b/dwm.c | |||
index bd715a2..5d88653 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -148,6 +148,7 @@ static void arrange(Monitor *m); | |||
static void arrangemon(Monitor *m); | |||
static void attach(Client *c); | |||
static void attachBelow(Client *c); | |||
+static void toggleAttachBelow(); | |||
static void attachstack(Client *c); | |||
static void buttonpress(XEvent *e); | |||
static void checkotherwm(void); | |||
@@ -422,6 +423,11 @@ attachBelow(Client *c) | |||
} | |||
+void toggleAttachBelow() | |||
+{ | |||
+ attachbelow = !attachbelow; | |||
+} | |||
+ | |||
void | |||
attachstack(Client *c) | |||
{ | |||
-- | |||
2.21.0 | |||
@@ -0,0 +1,431 @@ | |||
diff --git a/config.def.h b/config.def.h | |||
index 1c0b587..bb8f3f7 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -16,6 +16,7 @@ static const char *colors[][3] = { | |||
/* fg bg border */ | |||
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 }, | |||
[SchemeSel] = { col_gray4, col_cyan, col_cyan }, | |||
+ [SchemeHid] = { col_cyan, col_gray1, col_cyan }, | |||
}; | |||
/* tagging */ | |||
@@ -64,8 +65,10 @@ static Key keys[] = { | |||
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, | |||
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, | |||
{ MODKEY, XK_b, togglebar, {0} }, | |||
- { MODKEY, XK_j, focusstack, {.i = +1 } }, | |||
- { MODKEY, XK_k, focusstack, {.i = -1 } }, | |||
+ { MODKEY, XK_j, focusstackvis, {.i = +1 } }, | |||
+ { MODKEY, XK_k, focusstackvis, {.i = -1 } }, | |||
+ { MODKEY|ShiftMask, XK_j, focusstackhid, {.i = +1 } }, | |||
+ { MODKEY|ShiftMask, XK_k, focusstackhid, {.i = -1 } }, | |||
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, | |||
{ MODKEY, XK_d, incnmaster, {.i = -1 } }, | |||
{ MODKEY, XK_h, setmfact, {.f = -0.05} }, | |||
@@ -84,6 +87,8 @@ 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_s, show, {0} }, | |||
+ { MODKEY, XK_h, hide, {0} }, | |||
TAGKEYS( XK_1, 0) | |||
TAGKEYS( XK_2, 1) | |||
TAGKEYS( XK_3, 2) | |||
@@ -102,6 +107,7 @@ static Button buttons[] = { | |||
/* click event mask button function argument */ | |||
{ ClkLtSymbol, 0, Button1, setlayout, {0} }, | |||
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} }, | |||
+ { ClkWinTitle, 0, Button1, togglewin, {0} }, | |||
{ ClkWinTitle, 0, Button2, zoom, {0} }, | |||
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } }, | |||
{ ClkClientWin, MODKEY, Button1, movemouse, {0} }, | |||
diff --git a/dwm.c b/dwm.c | |||
index 4465af1..e780189 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -50,6 +50,7 @@ | |||
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ | |||
* 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 HIDDEN(C) ((getstate(C->win) == IconicState)) | |||
#define LENGTH(X) (sizeof X / sizeof X[0]) | |||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask) | |||
#define WIDTH(X) ((X)->w + 2 * (X)->bw) | |||
@@ -59,7 +60,7 @@ | |||
/* enums */ | |||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |||
-enum { SchemeNorm, SchemeSel }; /* color schemes */ | |||
+enum { SchemeNorm, SchemeSel, SchemeHid }; /* color schemes */ | |||
enum { NetSupported, NetWMName, NetWMState, NetWMCheck, | |||
NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |||
@@ -117,6 +118,8 @@ struct Monitor { | |||
int nmaster; | |||
int num; | |||
int by; /* bar geometry */ | |||
+ int btw; /* width of tasks portion of bar */ | |||
+ int bt; /* number of tasks */ | |||
int mx, my, mw, mh; /* screen size */ | |||
int wx, wy, ww, wh; /* window area */ | |||
unsigned int seltags; | |||
@@ -124,6 +127,7 @@ struct Monitor { | |||
unsigned int tagset[2]; | |||
int showbar; | |||
int topbar; | |||
+ int hidsel; | |||
Client *clients; | |||
Client *sel; | |||
Client *stack; | |||
@@ -168,12 +172,16 @@ 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 focusstackvis(const Arg *arg); | |||
+static void focusstackhid(const Arg *arg); | |||
+static void focusstack(int inc, int vis); | |||
static int getrootptr(int *x, int *y); | |||
static long getstate(Window w); | |||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | |||
static void grabbuttons(Client *c, int focused); | |||
static void grabkeys(void); | |||
+static void hide(const Arg *arg); | |||
+static void hidewin(Client *c); | |||
static void incnmaster(const Arg *arg); | |||
static void keypress(XEvent *e); | |||
static void killclient(const Arg *arg); | |||
@@ -203,6 +211,8 @@ static void setlayout(const Arg *arg); | |||
static void setmfact(const Arg *arg); | |||
static void setup(void); | |||
static void seturgent(Client *c, int urg); | |||
+static void show(const Arg *arg); | |||
+static void showwin(Client *c); | |||
static void showhide(Client *c); | |||
static void sigchld(int unused); | |||
static void spawn(const Arg *arg); | |||
@@ -213,6 +223,7 @@ static void togglebar(const Arg *arg); | |||
static void togglefloating(const Arg *arg); | |||
static void toggletag(const Arg *arg); | |||
static void toggleview(const Arg *arg); | |||
+static void togglewin(const Arg *arg); | |||
static void unfocus(Client *c, int setfocus); | |||
static void unmanage(Client *c, int destroyed); | |||
static void unmapnotify(XEvent *e); | |||
@@ -439,10 +450,25 @@ buttonpress(XEvent *e) | |||
arg.ui = 1 << i; | |||
} else if (ev->x < x + blw) | |||
click = ClkLtSymbol; | |||
- else if (ev->x > selmon->ww - TEXTW(stext)) | |||
+ /* 2px right padding */ | |||
+ else if (ev->x > selmon->ww - TEXTW(stext) + lrpad - 2) | |||
click = ClkStatusText; | |||
- else | |||
- click = ClkWinTitle; | |||
+ else { | |||
+ x += blw; | |||
+ c = m->clients; | |||
+ | |||
+ if (c) { | |||
+ do { | |||
+ if (!ISVISIBLE(c)) | |||
+ continue; | |||
+ else | |||
+ x += (1.0 / (double)m->bt) * m->btw; | |||
+ } while (ev->x > x && (c = c->next)); | |||
+ | |||
+ click = ClkWinTitle; | |||
+ arg.v = c; | |||
+ } | |||
+ } | |||
} else if ((c = wintoclient(ev->window))) { | |||
focus(c); | |||
restack(selmon); | |||
@@ -452,7 +478,7 @@ buttonpress(XEvent *e) | |||
for (i = 0; i < LENGTH(buttons); i++) | |||
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button | |||
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) | |||
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); | |||
+ buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); | |||
} | |||
void | |||
@@ -695,7 +721,7 @@ dirtomon(int dir) | |||
void | |||
drawbar(Monitor *m) | |||
{ | |||
- int x, w, sw = 0; | |||
+ int x, w, sw = 0, n = 0, scm; | |||
int boxs = drw->fonts->h / 9; | |||
int boxw = drw->fonts->h / 6 + 2; | |||
unsigned int i, occ = 0, urg = 0; | |||
@@ -709,6 +735,8 @@ drawbar(Monitor *m) | |||
} | |||
for (c = m->clients; c; c = c->next) { | |||
+ if (ISVISIBLE(c)) | |||
+ n++; | |||
occ |= c->tags; | |||
if (c->isurgent) | |||
urg |= c->tags; | |||
@@ -729,16 +757,37 @@ drawbar(Monitor *m) | |||
x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0); | |||
if ((w = m->ww - sw - x) > bh) { | |||
- if (m->sel) { | |||
- 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); | |||
+ if (n > 0) { | |||
+ int remainder = w % n; | |||
+ int tabw = (1.0 / (double)n) * w + 1; | |||
+ for (c = m->clients; c; c = c->next) { | |||
+ if (!ISVISIBLE(c)) | |||
+ continue; | |||
+ if (m->sel == c) | |||
+ scm = SchemeSel; | |||
+ else if (HIDDEN(c)) | |||
+ scm = SchemeHid; | |||
+ else | |||
+ scm = SchemeNorm; | |||
+ drw_setscheme(drw, scheme[scm]); | |||
+ | |||
+ if (remainder >= 0) { | |||
+ if (remainder == 0) { | |||
+ tabw--; | |||
+ } | |||
+ remainder--; | |||
+ } | |||
+ drw_text(drw, x, 0, tabw, bh, lrpad / 2, c->name, 0); | |||
+ x += tabw; | |||
+ } | |||
} else { | |||
drw_setscheme(drw, scheme[SchemeNorm]); | |||
drw_rect(drw, x, 0, w, bh, 1, 1); | |||
} | |||
} | |||
+ | |||
+ m->bt = n; | |||
+ m->btw = w; | |||
drw_map(drw, m->barwin, 0, 0, m->ww, bh); | |||
} | |||
@@ -784,9 +833,17 @@ void | |||
focus(Client *c) | |||
{ | |||
if (!c || !ISVISIBLE(c)) | |||
- for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); | |||
- if (selmon->sel && selmon->sel != c) | |||
+ for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); | |||
+ if (selmon->sel && selmon->sel != c) { | |||
unfocus(selmon->sel, 0); | |||
+ | |||
+ if (selmon->hidsel) { | |||
+ hidewin(selmon->sel); | |||
+ if (c) | |||
+ arrange(c->mon); | |||
+ selmon->hidsel = 0; | |||
+ } | |||
+ } | |||
if (c) { | |||
if (c->mon != selmon) | |||
selmon = c->mon; | |||
@@ -830,28 +887,57 @@ focusmon(const Arg *arg) | |||
} | |||
void | |||
-focusstack(const Arg *arg) | |||
+focusstackvis(const Arg *arg) | |||
+{ | |||
+ focusstack(arg->i, 0); | |||
+} | |||
+ | |||
+void | |||
+focusstackhid(const Arg *arg) | |||
+{ | |||
+ focusstack(arg->i, 1); | |||
+} | |||
+ | |||
+void | |||
+focusstack(int inc, int hid) | |||
{ | |||
Client *c = NULL, *i; | |||
- if (!selmon->sel) | |||
+ if (!selmon->sel && !hid) | |||
return; | |||
- if (arg->i > 0) { | |||
- for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); | |||
+ if (!selmon->clients) | |||
+ return; | |||
+ | |||
+ if (inc > 0) { | |||
+ if (selmon->sel) | |||
+ for (c = selmon->sel->next; | |||
+ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); | |||
+ c = c->next); | |||
if (!c) | |||
- for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); | |||
+ for (c = selmon->clients; | |||
+ c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); | |||
+ c = c->next); | |||
} else { | |||
- for (i = selmon->clients; i != selmon->sel; i = i->next) | |||
- if (ISVISIBLE(i)) | |||
- c = i; | |||
+ if (selmon->sel) { | |||
+ for (i = selmon->clients; i != selmon->sel; i = i->next) | |||
+ if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) | |||
+ c = i; | |||
+ } else | |||
+ c = selmon->clients; | |||
if (!c) | |||
for (; i; i = i->next) | |||
- if (ISVISIBLE(i)) | |||
+ if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) | |||
c = i; | |||
} | |||
+ | |||
if (c) { | |||
focus(c); | |||
restack(selmon); | |||
+ | |||
+ if (HIDDEN(c)) { | |||
+ showwin(c); | |||
+ c->mon->hidsel = 1; | |||
+ } | |||
} | |||
} | |||
@@ -963,6 +1049,36 @@ grabkeys(void) | |||
} | |||
} | |||
+void | |||
+hide(const Arg *arg) | |||
+{ | |||
+ hidewin(selmon->sel); | |||
+ focus(NULL); | |||
+ arrange(selmon); | |||
+} | |||
+ | |||
+void | |||
+hidewin(Client *c) { | |||
+ if (!c || HIDDEN(c)) | |||
+ return; | |||
+ | |||
+ Window w = c->win; | |||
+ static XWindowAttributes ra, ca; | |||
+ | |||
+ // more or less taken directly from blackbox's hide() function | |||
+ XGrabServer(dpy); | |||
+ XGetWindowAttributes(dpy, root, &ra); | |||
+ XGetWindowAttributes(dpy, w, &ca); | |||
+ // prevent UnmapNotify events | |||
+ XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); | |||
+ XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); | |||
+ XUnmapWindow(dpy, w); | |||
+ setclientstate(c, IconicState); | |||
+ XSelectInput(dpy, root, ra.your_event_mask); | |||
+ XSelectInput(dpy, w, ca.your_event_mask); | |||
+ XUngrabServer(dpy); | |||
+} | |||
+ | |||
void | |||
incnmaster(const Arg *arg) | |||
{ | |||
@@ -1067,12 +1183,14 @@ manage(Window w, XWindowAttributes *wa) | |||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, | |||
(unsigned char *) &(c->win), 1); | |||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ | |||
- setclientstate(c, NormalState); | |||
+ if (!HIDDEN(c)) | |||
+ setclientstate(c, NormalState); | |||
if (c->mon == selmon) | |||
unfocus(selmon->sel, 0); | |||
c->mon->sel = c; | |||
arrange(c->mon); | |||
- XMapWindow(dpy, c->win); | |||
+ if (!HIDDEN(c)) | |||
+ XMapWindow(dpy, c->win); | |||
focus(NULL); | |||
} | |||
@@ -1195,7 +1313,7 @@ movemouse(const Arg *arg) | |||
Client * | |||
nexttiled(Client *c) | |||
{ | |||
- for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); | |||
+ for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); | |||
return c; | |||
} | |||
@@ -1248,6 +1366,16 @@ propertynotify(XEvent *e) | |||
void | |||
quit(const Arg *arg) | |||
{ | |||
+ // fix: reloading dwm keeps all the hidden clients hidden | |||
+ Monitor *m; | |||
+ Client *c; | |||
+ for (m = mons; m; m = m->next) { | |||
+ if (m) { | |||
+ for (c = m->stack; c; c = c->next) | |||
+ if (c && HIDDEN(c)) showwin(c); | |||
+ } | |||
+ } | |||
+ | |||
running = 0; | |||
} | |||
@@ -1610,6 +1738,25 @@ seturgent(Client *c, int urg) | |||
XFree(wmh); | |||
} | |||
+void | |||
+show(const Arg *arg) | |||
+{ | |||
+ if (selmon->hidsel) | |||
+ selmon->hidsel = 0; | |||
+ showwin(selmon->sel); | |||
+} | |||
+ | |||
+void | |||
+showwin(Client *c) | |||
+{ | |||
+ if (!c || !HIDDEN(c)) | |||
+ return; | |||
+ | |||
+ XMapWindow(dpy, c->win); | |||
+ setclientstate(c, NormalState); | |||
+ arrange(c->mon); | |||
+} | |||
+ | |||
void | |||
showhide(Client *c) | |||
{ | |||
@@ -1746,6 +1893,23 @@ toggleview(const Arg *arg) | |||
} | |||
} | |||
+void | |||
+togglewin(const Arg *arg) | |||
+{ | |||
+ Client *c = (Client*)arg->v; | |||
+ | |||
+ if (c == selmon->sel) { | |||
+ hidewin(c); | |||
+ focus(NULL); | |||
+ arrange(c->mon); | |||
+ } else { | |||
+ if (HIDDEN(c)) | |||
+ showwin(c); | |||
+ focus(c); | |||
+ restack(selmon); | |||
+ } | |||
+} | |||
+ | |||
void | |||
unfocus(Client *c, int setfocus) | |||
{ |
@@ -0,0 +1,142 @@ | |||
diff --git a/config.def.h b/config.def.h | |||
index 7054c06..527b214 100644 | |||
--- a/config.def.h | |||
+++ b/config.def.h | |||
@@ -39,6 +39,8 @@ static const Layout layouts[] = { | |||
{ "[]=", tile }, /* first entry is default */ | |||
{ "><>", NULL }, /* no layout function means floating behavior */ | |||
{ "[M]", monocle }, | |||
+ { "|M|", centeredmaster }, | |||
+ { ">M>", centeredfloatingmaster }, | |||
}; | |||
/* key definitions */ | |||
@@ -74,6 +76,8 @@ static Key keys[] = { | |||
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} }, | |||
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} }, | |||
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} }, | |||
+ { MODKEY, XK_u, setlayout, {.v = &layouts[3]} }, | |||
+ { MODKEY, XK_o, setlayout, {.v = &layouts[4]} }, | |||
{ MODKEY, XK_space, setlayout, {0} }, | |||
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} }, | |||
{ MODKEY, XK_0, view, {.ui = ~0 } }, | |||
diff --git a/dwm.c b/dwm.c | |||
index 0362114..1e81412 100644 | |||
--- a/dwm.c | |||
+++ b/dwm.c | |||
@@ -233,6 +233,8 @@ static int xerror(Display *dpy, XErrorEvent *ee); | |||
static int xerrordummy(Display *dpy, XErrorEvent *ee); | |||
static int xerrorstart(Display *dpy, XErrorEvent *ee); | |||
static void zoom(const Arg *arg); | |||
+static void centeredmaster(Monitor *m); | |||
+static void centeredfloatingmaster(Monitor *m); | |||
/* variables */ | |||
static const char broken[] = "broken"; | |||
@@ -2139,3 +2141,106 @@ main(int argc, char *argv[]) | |||
XCloseDisplay(dpy); | |||
return EXIT_SUCCESS; | |||
} | |||
+ | |||
+void | |||
+centeredmaster(Monitor *m) | |||
+{ | |||
+ unsigned int i, n, h, mw, mx, my, oty, ety, tw; | |||
+ Client *c; | |||
+ | |||
+ /* count number of clients in the selected monitor */ | |||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |||
+ if (n == 0) | |||
+ return; | |||
+ | |||
+ /* initialize areas */ | |||
+ mw = m->ww; | |||
+ mx = 0; | |||
+ my = 0; | |||
+ tw = mw; | |||
+ | |||
+ if (n > m->nmaster) { | |||
+ /* go mfact box in the center if more than nmaster clients */ | |||
+ mw = m->nmaster ? m->ww * m->mfact : 0; | |||
+ tw = m->ww - mw; | |||
+ | |||
+ if (n - m->nmaster > 1) { | |||
+ /* only one client */ | |||
+ mx = (m->ww - mw) / 2; | |||
+ tw = (m->ww - mw) / 2; | |||
+ } | |||
+ } | |||
+ | |||
+ oty = 0; | |||
+ ety = 0; | |||
+ for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |||
+ if (i < m->nmaster) { | |||
+ /* nmaster clients are stacked vertically, in the center | |||
+ * of the screen */ | |||
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i); | |||
+ resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), | |||
+ h - (2*c->bw), 0); | |||
+ my += HEIGHT(c); | |||
+ } else { | |||
+ /* stack clients are stacked vertically */ | |||
+ if ((i - m->nmaster) % 2 ) { | |||
+ h = (m->wh - ety) / ( (1 + n - i) / 2); | |||
+ resize(c, m->wx, m->wy + ety, tw - (2*c->bw), | |||
+ h - (2*c->bw), 0); | |||
+ ety += HEIGHT(c); | |||
+ } else { | |||
+ h = (m->wh - oty) / ((1 + n - i) / 2); | |||
+ resize(c, m->wx + mx + mw, m->wy + oty, | |||
+ tw - (2*c->bw), h - (2*c->bw), 0); | |||
+ oty += HEIGHT(c); | |||
+ } | |||
+ } | |||
+} | |||
+ | |||
+void | |||
+centeredfloatingmaster(Monitor *m) | |||
+{ | |||
+ unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; | |||
+ Client *c; | |||
+ | |||
+ /* count number of clients in the selected monitor */ | |||
+ for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |||
+ if (n == 0) | |||
+ return; | |||
+ | |||
+ /* initialize nmaster area */ | |||
+ if (n > m->nmaster) { | |||
+ /* go mfact box in the center if more than nmaster clients */ | |||
+ if (m->ww > m->wh) { | |||
+ mw = m->nmaster ? m->ww * m->mfact : 0; | |||
+ mh = m->nmaster ? m->wh * 0.9 : 0; | |||
+ } else { | |||
+ mh = m->nmaster ? m->wh * m->mfact : 0; | |||
+ mw = m->nmaster ? m->ww * 0.9 : 0; | |||
+ } | |||
+ mx = mxo = (m->ww - mw) / 2; | |||
+ my = myo = (m->wh - mh) / 2; | |||
+ } else { | |||
+ /* go fullscreen if all clients are in the master area */ | |||
+ mh = m->wh; | |||
+ mw = m->ww; | |||
+ mx = mxo = 0; | |||
+ my = myo = 0; | |||
+ } | |||
+ | |||
+ for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |||
+ if (i < m->nmaster) { | |||
+ /* nmaster clients are stacked horizontally, in the center | |||
+ * of the screen */ | |||
+ w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); | |||
+ resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), | |||
+ mh - (2*c->bw), 0); | |||
+ mx += WIDTH(c); | |||
+ } else { | |||
+ /* stack clients are stacked horizontally */ | |||
+ w = (m->ww - tx) / (n - i); | |||
+ resize(c, m->wx + tx, m->wy, w - (2*c->bw), | |||
+ m->wh - (2*c->bw), 0); | |||
+ tx += WIDTH(c); | |||
+ } | |||
+} |
@@ -0,0 +1,95 @@ | |||
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 | |||
@@ -50,6 +50,7 @@ | |||
#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \ | |||
* 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 HIDDEN(C) ((getstate(C->win) == IconicState)) | |||
#define LENGTH(X) (sizeof X / sizeof X[0]) | |||
#define MOUSEMASK (BUTTONMASK|PointerMotionMask) | |||
#define WIDTH(X) ((X)->w + 2 * (X)->bw) | |||
@@ -59,7 +60,7 @@ | |||
/* enums */ | |||
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */ | |||
enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */ | |||
enum { SchemeNorm, SchemeSel, SchemeHid, SchemeLast }; /* color schemes */ | |||
enum { NetSupported, NetWMName, NetWMState, | |||
NetWMFullscreen, NetActiveWindow, NetWMWindowType, | |||
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ | |||
@@ -117,6 +118,8 @@ struct Monitor { | |||
int nmaster; | |||
int num; | |||
int by; /* bar geometry */ | |||
int btw; /* width of tasks portion of bar */ | |||
int bt; /* number of tasks */ | |||
int mx, my, mw, mh; /* screen size */ | |||
int wx, wy, ww, wh; /* window area */ | |||
unsigned int seltags; | |||
@@ -124,6 +127,7 @@ struct Monitor { | |||
unsigned int tagset[2]; | |||
int showbar; | |||
int topbar; | |||
int hidsel; | |||
Client *clients; | |||
Client *sel; | |||
Client *stack; | |||
@@ -169,12 +173,16 @@ 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 focusstackvis(const Arg *arg); | |||
static void focusstackhid(const Arg *arg); | |||
static void focusstack(int inc, int vis); | |||
static int getrootptr(int *x, int *y); | |||
static long getstate(Window w); | |||
static int gettextprop(Window w, Atom atom, char *text, unsigned int size); | |||
static void grabbuttons(Client *c, int focused); | |||
static void grabkeys(void); | |||
static void hide(const Arg *arg); | |||
static void hidewin(Client *c); | |||
static void incnmaster(const Arg *arg); | |||
static void keypress(XEvent *e); | |||
static void killclient(const Arg *arg); | |||
@@ -203,6 +211,8 @@ static void setfullscreen(Client *c, int fullscreen); | |||
static void setlayout(const Arg *arg); | |||
static void setmfact(const Arg *arg); | |||
static void setup(void); | |||
static void show(const Arg *arg); | |||
static void showwin(Client *c); | |||
static void showhide(Client *c); | |||
static void sigchld(int unused); | |||
static void spawn(const Arg *arg); | |||
@@ -213,6 +223,7 @@ static void togglebar(const Arg *arg); | |||
static void togglefloating(const Arg *arg); | |||
static void toggletag(const Arg *arg); | |||
static void toggleview(const Arg *arg); | |||
static void togglewin(const Arg *arg); | |||
static void unfocus(Client *c, int setfocus); | |||
static void unmanage(Client *c, int destroyed); | |||
static void unmapnotify(XEvent *e); | |||
@@ -233,6 +244,8 @@ static int xerror(Display *dpy, XErrorEvent *ee); | |||
static int xerrordummy(Display *dpy, XErrorEvent *ee); | |||
static int xerrorstart(Display *dpy, XErrorEvent *ee); | |||
static void zoom(const Arg *arg); | |||
static void centeredmaster(Monitor *m); | |||
static void centeredfloatingmaster(Monitor *m); | |||
/* variables */ | |||
static const char broken[] = "broken"; | |||
@@ -438,10 +451,25 @@ buttonpress(XEvent *e) | |||
arg.ui = 1 << i; | |||
} else if (ev->x < x + blw) | |||
click = ClkLtSymbol; | |||
/* 2px right padding */ | |||
else if (ev->x > selmon->ww - TEXTW(stext)) | |||
click = ClkStatusText; | |||
else | |||
click = ClkWinTitle; | |||
else { | |||
x += blw; | |||
c = m->clients; | |||
if (c) { | |||
do { | |||
if (!ISVISIBLE(c)) | |||
continue; | |||
else | |||
x += (1.0 / (double)m->bt) * m->btw; | |||
} while (ev->x > x && (c = c->next)); | |||
click = ClkWinTitle; | |||
arg.v = c; | |||
} | |||
} | |||
} else if ((c = wintoclient(ev->window))) { | |||
focus(c); | |||
click = ClkClientWin; | |||
@@ -449,7 +477,7 @@ buttonpress(XEvent *e) | |||
for (i = 0; i < LENGTH(buttons); i++) | |||
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button | |||
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) | |||
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); | |||
buttons[i].func((click == ClkTagBar || click == ClkWinTitle) && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg); | |||
} | |||
void | |||
@@ -704,13 +732,15 @@ dirtomon(int dir) | |||
void | |||
drawbar(Monitor *m) | |||
{ | |||
int x, xx, w, dx; | |||
int xx, x, w, sw = 0, n = 0, scm; | |||
unsigned int i, occ = 0, urg = 0; | |||
Client *c; | |||
dx = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; | |||
x = (drw->fonts[0]->ascent + drw->fonts[0]->descent + 2) / 4; | |||
for (c = m->clients; c; c = c->next) { | |||
if (ISVISIBLE(c)) | |||
n++; | |||
occ |= c->tags; | |||
if (c->isurgent) | |||
urg |= c->tags; | |||
@@ -720,7 +750,7 @@ drawbar(Monitor *m) | |||
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_rect(drw, x + 1, 1, dx, dx, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, | |||
drw_rect(drw, x + 1, 1, x, x, m == selmon && selmon->sel && selmon->sel->tags & 1 << i, | |||
occ & 1 << i, urg & 1 << i); | |||
x += w; | |||
} | |||
@@ -741,10 +771,29 @@ drawbar(Monitor *m) | |||
x = m->ww; | |||
if ((w = x - xx) > bh) { | |||
x = xx; | |||
if (m->sel) { | |||
drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]); | |||
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); | |||
if (n > 0) { | |||
int remainder = w % n; | |||
int tabw = (1.0 / (double)n) * w + 1; | |||
for (c = m->clients; c; c = c->next) { | |||
if (!ISVISIBLE(c)) | |||
continue; | |||
if (m->sel == c) | |||
scm = SchemeSel; | |||
else if (HIDDEN(c)) | |||
scm = SchemeHid; | |||
else | |||
scm = SchemeNorm; | |||
drw_setscheme(drw, &scheme[scm]); | |||
if (remainder >= 0) { | |||
if (remainder == 0) { | |||
tabw--; | |||
} | |||
remainder--; | |||
} | |||
drw_text(drw, x, 0, tabw, bh, c->name, 0); | |||
x += tabw; | |||
} | |||
} else { | |||
drw_setscheme(drw, &scheme[SchemeNorm]); | |||
drw_rect(drw, x, 0, w, bh, 1, 0, 1); | |||
@@ -795,10 +844,17 @@ void | |||
focus(Client *c) | |||
{ | |||
if (!c || !ISVISIBLE(c)) | |||
for (c = selmon->stack; c && !ISVISIBLE(c); c = c->snext); | |||
/* was if (selmon->sel) */ | |||
if (selmon->sel && selmon->sel != c) | |||
for (c = selmon->stack; c && (!ISVISIBLE(c) || HIDDEN(c)); c = c->snext); | |||
if (selmon->sel && selmon->sel != c) { | |||
unfocus(selmon->sel, 0); | |||
if (selmon->hidsel) { | |||
hidewin(selmon->sel); | |||
if (c) | |||
arrange(c->mon); | |||
selmon->hidsel = 0; | |||
} | |||
} | |||
if (c) { | |||
if (c->mon != selmon) | |||
selmon = c->mon; | |||
@@ -843,28 +899,57 @@ focusmon(const Arg *arg) | |||
} | |||
void | |||
focusstack(const Arg *arg) | |||
focusstackvis(const Arg *arg) | |||
{ | |||
focusstack(arg->i, 0); | |||
} | |||
void | |||
focusstackhid(const Arg *arg) | |||
{ | |||
focusstack(arg->i, 1); | |||
} | |||
void | |||
focusstack(int inc, int hid) | |||
{ | |||
Client *c = NULL, *i; | |||
if (!selmon->sel) | |||
if (!selmon->sel && !hid) | |||
return; | |||
if (arg->i > 0) { | |||
for (c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next); | |||
if (!selmon->clients) | |||
return; | |||
if (inc > 0) { | |||
if (selmon->sel) | |||
for (c = selmon->sel->next; | |||
c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); | |||
c = c->next); | |||
if (!c) | |||
for (c = selmon->clients; c && !ISVISIBLE(c); c = c->next); | |||
for (c = selmon->clients; | |||
c && (!ISVISIBLE(c) || (!hid && HIDDEN(c))); | |||
c = c->next); | |||
} else { | |||
for (i = selmon->clients; i != selmon->sel; i = i->next) | |||
if (ISVISIBLE(i)) | |||
c = i; | |||
if (selmon->sel) { | |||
for (i = selmon->clients; i != selmon->sel; i = i->next) | |||
if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) | |||
c = i; | |||
} else | |||
c = selmon->clients; | |||
if (!c) | |||
for (; i; i = i->next) | |||
if (ISVISIBLE(i)) | |||
if (ISVISIBLE(i) && !(!hid && HIDDEN(i))) | |||
c = i; | |||
} | |||
if (c) { | |||
focus(c); | |||
restack(selmon); | |||
if (HIDDEN(c)) { | |||
showwin(c); | |||
c->mon->hidsel = 1; | |||
} | |||
} | |||
} | |||
@@ -978,6 +1063,36 @@ grabkeys(void) | |||
} | |||
} | |||
void | |||
hide(const Arg *arg) | |||
{ | |||
hidewin(selmon->sel); | |||
focus(NULL); | |||
arrange(selmon); | |||
} | |||
void | |||
hidewin(Client *c) { | |||
if (!c || HIDDEN(c)) | |||
return; | |||
Window w = c->win; | |||
static XWindowAttributes ra, ca; | |||
// more or less taken directly from blackbox's hide() function | |||
XGrabServer(dpy); | |||
XGetWindowAttributes(dpy, root, &ra); | |||
XGetWindowAttributes(dpy, w, &ca); | |||
// prevent UnmapNotify events | |||
XSelectInput(dpy, root, ra.your_event_mask & ~SubstructureNotifyMask); | |||
XSelectInput(dpy, w, ca.your_event_mask & ~StructureNotifyMask); | |||
XUnmapWindow(dpy, w); | |||
setclientstate(c, IconicState); | |||
XSelectInput(dpy, root, ra.your_event_mask); | |||
XSelectInput(dpy, w, ca.your_event_mask); | |||
XUngrabServer(dpy); | |||
} | |||
void | |||
incnmaster(const Arg *arg) | |||
{ | |||
@@ -1081,12 +1196,14 @@ manage(Window w, XWindowAttributes *wa) | |||
XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend, | |||
(unsigned char *) &(c->win), 1); | |||
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */ | |||
setclientstate(c, NormalState); | |||
if (!HIDDEN(c)) | |||
setclientstate(c, NormalState); | |||
if (c->mon == selmon) | |||
unfocus(selmon->sel, 0); | |||
c->mon->sel = c; | |||
arrange(c->mon); | |||
XMapWindow(dpy, c->win); | |||
if (!HIDDEN(c)) | |||
XMapWindow(dpy, c->win); | |||
focus(NULL); | |||
} | |||
@@ -1212,7 +1329,7 @@ movemouse(const Arg *arg) | |||
Client * | |||
nexttiled(Client *c) | |||
{ | |||
for (; c && (c->isfloating || !ISVISIBLE(c)); c = c->next); | |||
for (; c && (c->isfloating || !ISVISIBLE(c) || HIDDEN(c)); c = c->next); | |||
return c; | |||
} | |||
@@ -1265,6 +1382,16 @@ propertynotify(XEvent *e) | |||
void | |||
quit(const Arg *arg) | |||
{ | |||
// fix: reloading dwm keeps all the hidden clients hidden | |||
Monitor *m; | |||
Client *c; | |||
for (m = mons; m; m = m->next) { | |||
if (m) { | |||
for (c = m->stack; c; c = c->next) | |||
if (c && HIDDEN(c)) showwin(c); | |||
} | |||
} | |||
running = 0; | |||
} | |||
@@ -1603,6 +1730,25 @@ setup(void) | |||
focus(NULL); | |||
} | |||
void | |||
show(const Arg *arg) | |||
{ | |||
if (selmon->hidsel) | |||
selmon->hidsel = 0; | |||
showwin(selmon->sel); | |||
} | |||
void | |||
showwin(Client *c) | |||
{ | |||
if (!c || !HIDDEN(c)) | |||
return; | |||
XMapWindow(dpy, c->win); | |||
setclientstate(c, NormalState); | |||
arrange(c->mon); | |||
} | |||
void | |||
showhide(Client *c) | |||
{ | |||
@@ -1739,6 +1885,23 @@ toggleview(const Arg *arg) | |||
} | |||
} | |||
void | |||
togglewin(const Arg *arg) | |||
{ | |||
Client *c = (Client*)arg->v; | |||
if (c == selmon->sel) { | |||
hidewin(c); | |||
focus(NULL); | |||
arrange(c->mon); | |||
} else { | |||
if (HIDDEN(c)) | |||
showwin(c); | |||
focus(c); | |||
restack(selmon); | |||
} | |||
} | |||
void | |||
unfocus(Client *c, int setfocus) | |||
{ | |||
@@ -2139,3 +2302,106 @@ main(int argc, char *argv[]) | |||
XCloseDisplay(dpy); | |||
return EXIT_SUCCESS; | |||
} | |||
void | |||
centeredmaster(Monitor *m) | |||
{ | |||
unsigned int i, n, h, mw, mx, my, oty, ety, tw; | |||
Client *c; | |||
/* count number of clients in the selected monitor */ | |||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |||
if (n == 0) | |||
return; | |||
/* initialize areas */ | |||
mw = m->ww; | |||
mx = 0; | |||
my = 0; | |||
tw = mw; | |||
if (n > m->nmaster) { | |||
/* go mfact box in the center if more than nmaster clients */ | |||
mw = m->nmaster ? m->ww * m->mfact : 0; | |||
tw = m->ww - mw; | |||
if (n - m->nmaster > 1) { | |||
/* only one client */ | |||
mx = (m->ww - mw) / 2; | |||
tw = (m->ww - mw) / 2; | |||
} | |||
} | |||
oty = 0; | |||
ety = 0; | |||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |||
if (i < m->nmaster) { | |||
/* nmaster clients are stacked vertically, in the center | |||
* of the screen */ | |||
h = (m->wh - my) / (MIN(n, m->nmaster) - i); | |||
resize(c, m->wx + mx, m->wy + my, mw - (2*c->bw), | |||
h - (2*c->bw), 0); | |||
my += HEIGHT(c); | |||
} else { | |||
/* stack clients are stacked vertically */ | |||
if ((i - m->nmaster) % 2 ) { | |||
h = (m->wh - ety) / ( (1 + n - i) / 2); | |||
resize(c, m->wx, m->wy + ety, tw - (2*c->bw), | |||
h - (2*c->bw), 0); | |||
ety += HEIGHT(c); | |||
} else { | |||
h = (m->wh - oty) / ((1 + n - i) / 2); | |||
resize(c, m->wx + mx + mw, m->wy + oty, | |||
tw - (2*c->bw), h - (2*c->bw), 0); | |||
oty += HEIGHT(c); | |||
} | |||
} | |||
} | |||
void | |||
centeredfloatingmaster(Monitor *m) | |||
{ | |||
unsigned int i, n, w, mh, mw, mx, mxo, my, myo, tx; | |||
Client *c; | |||
/* count number of clients in the selected monitor */ | |||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); | |||
if (n == 0) | |||
return; | |||
/* initialize nmaster area */ | |||
if (n > m->nmaster) { | |||
/* go mfact box in the center if more than nmaster clients */ | |||
if (m->ww > m->wh) { | |||
mw = m->nmaster ? m->ww * m->mfact : 0; | |||
mh = m->nmaster ? m->wh * 0.9 : 0; | |||
} else { | |||
mh = m->nmaster ? m->wh * m->mfact : 0; | |||
mw = m->nmaster ? m->ww * 0.9 : 0; | |||
} | |||
mx = mxo = (m->ww - mw) / 2; | |||
my = myo = (m->wh - mh) / 2; | |||
} else { | |||
/* go fullscreen if all clients are in the master area */ | |||
mh = m->wh; | |||
mw = m->ww; | |||
mx = mxo = 0; | |||
my = myo = 0; | |||
} | |||
for(i = tx = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) | |||
if (i < m->nmaster) { | |||
/* nmaster clients are stacked horizontally, in the center | |||
* of the screen */ | |||
w = (mw + mxo - mx) / (MIN(n, m->nmaster) - i); | |||
resize(c, m->wx + mx, m->wy + my, w - (2*c->bw), | |||
mh - (2*c->bw), 0); | |||
mx += WIDTH(c); | |||
} else { | |||
/* stack clients are stacked horizontally */ | |||
w = (m->ww - tx) / (n - i); | |||
resize(c, m->wx + tx, m->wy, w - (2*c->bw), | |||
m->wh - (2*c->bw), 0); | |||
tx += WIDTH(c); | |||
} | |||
} |