Browse Source

minor updates

master
RinRi 3 years ago
parent
commit
8cc69be156
14 changed files with 4389 additions and 72 deletions
  1. +25
    -12
      config.def.h
  2. +160
    -0
      config.def.h.orig
  3. +33
    -0
      config.def.h.rej
  4. +25
    -12
      config.h
  5. +0
    -0
      drw.o
  6. BIN
      dwm
  7. +808
    -0
      dwm-tab-v2b-pertab-56a31dc.diff
  8. +24
    -9
      dwm.1
  9. +176
    -0
      dwm.1.orig
  10. +309
    -39
      dwm.c
  11. +2596
    -0
      dwm.c.orig
  12. +233
    -0
      dwm.c.rej
  13. BIN
      dwm.o
  14. +0
    -0
      util.o

+ 25
- 12
config.def.h View File

@@ -7,6 +7,14 @@ static const unsigned int snap = 32; /* snap pixel */
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */

/* Display modes of the tab bar: never shown, always shown, shown only in */
/* monocle mode in presence of several windows. */
/* Modes after showtab_nmodes are disabled */
enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
static const int showtab = showtab_auto; /* Default tab bar show mode */
static const Bool toptab = False; /* False means bottom tab bar */

static const char *fonts[] = { "fontawesome:size=15", "DejaVuSansMono Nerd Font Mono:size=13"} ;
static const char dmenufont[] = "monospace:size=13";
static const char col_gray1[] = "#222222";
@@ -22,27 +30,30 @@ static const char *colors[][3] = {

static const char *const autostart[] = {
"sh", "-c", "sh ~/scripts/xinit.sh", NULL,
"dunst", NULL,
"slstatus", NULL,
NULL /* terminate */
};

/* tagging */
static const char *tags[] = { "", "", "", "", "", "", "", "", "" };

/* default layout per tags */
/* The first element is for all-tag view, following i-th element corresponds to */
/* tags[i]. Layout is referred using the layouts array index.*/
static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 2, 0, 2, 2};


static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask iscentered isfloating monitor */
{ "Gimp", NULL, NULL, 0, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
/* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 0,0, 1, 0, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8,0, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0,0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0,0, 0, 0, 1, -1 }, /* xev */

/* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 1 << 7, 0, 1, 0, 0, -1 },
{ "LibreWolf", NULL, NULL, 1 << 0, 0, 0, 0, -1, -1 },
{ "firefox", NULL, NULL, 1 << 0, 0, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0, 0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0, 0, 0, 0, 1, -1 }, /* xev */
};

/* layout(s) */
@@ -82,8 +93,8 @@ static Key keys[] = {
{ 0, XK_Print, spawn, SHCMD("~/scripts/screenshot.sh") },
{ 0, XF86XK_PowerOff, spawn, SHCMD("~/scripts/poweroff.sh") },
{ 0, XF86XK_AudioMute, spawn, SHCMD("pulsemixer --toggle-mute") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("pulsemixer --change-volume +1") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("pulsemixer --change-volume -1") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("amixer -c 1 sset Master 1+") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("amixer -c 1 sset Master 1-") },
{ 0, XF86XK_AudioPrev, spawn, SHCMD("cmus-remote --prev") },
{ 0, XF86XK_AudioNext, spawn, SHCMD("cmus-remote --next") },
{ 0, XF86XK_AudioPause, spawn, SHCMD("cmus-remote --pause") },
@@ -104,6 +115,7 @@ static Key keys[] = {
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_w, tabmode, {-1} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
@@ -156,5 +168,6 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTabBar, 0, Button1, focuswin, {0} },
};


+ 160
- 0
config.def.h.orig View File

@@ -0,0 +1,160 @@
/* See LICENSE file for copyright and license details. */

/* appearance */
static const unsigned int borderpx = 2; /* border pixel of windows */
static const unsigned int gappx = 15;
static const unsigned int snap = 32; /* snap pixel */
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
static const char *fonts[] = { "fontawesome:size=15", "DejaVuSansMono Nerd Font Mono:size=13"} ;
static const char dmenufont[] = "monospace:size=13";
static const char col_gray1[] = "#222222";
static const char col_gray2[] = "#444444";
static const char col_gray3[] = "#bbbbbb";
static const char col_gray4[] = "#eeeeee";
static const char col_cyan[] = "#41008c";
static const char *colors[][3] = {
/* fg bg border */
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};

static const char *const autostart[] = {
"sh", "-c", "sh ~/scripts/xinit.sh", NULL,
"dunst", NULL,
"slstatus", NULL,
NULL /* terminate */
};

/* tagging */
static const char *tags[] = { "", "", "", "", "", "", "", "", "" };

static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask iscentered isfloating monitor */
{ "Gimp", NULL, NULL, 0, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
/* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 0,0, 1, 0, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8,0, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0,0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0,0, 0, 0, 1, -1 }, /* xev */
};

/* 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", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "st", NULL };

#include <X11/XF86keysym.h>

static Key keys[] = {
/* modifier key function argument */
{ 0, XK_Print, spawn, SHCMD("~/scripts/screenshot.sh") },
{ 0, XF86XK_PowerOff, spawn, SHCMD("~/scripts/poweroff.sh") },
{ 0, XF86XK_AudioMute, spawn, SHCMD("pulsemixer --toggle-mute") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("amixer -c 1 sset Master 1+") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("amixer -c 1 sset Master 1-") },
{ 0, XF86XK_AudioPrev, spawn, SHCMD("cmus-remote --prev") },
{ 0, XF86XK_AudioNext, spawn, SHCMD("cmus-remote --next") },
{ 0, XF86XK_AudioPause, spawn, SHCMD("cmus-remote --pause") },
{ 0, XF86XK_AudioPlay, spawn, SHCMD("cmus-remote --pause") },
{ 0, XF86XK_AudioStop, spawn, SHCMD("cmus-remote --stop") },
{ 0, XF86XK_AudioRewind, spawn, SHCMD("cmus-remote --seek -10") },
{ 0, XF86XK_AudioForward, spawn, SHCMD("cmus-remote --seek +10") },
{ 0, XF86XK_MonBrightnessUp, spawn, SHCMD("brightnessctl s +5%")},
{ 0, XF86XK_MonBrightnessDown, spawn, SHCMD("brightnessctl s 5%-")},
{ MODKEY|ShiftMask, XK_space, togglealwaysontop, {0} },
{ MODKEY, XK_w, spawn, SHCMD("firefox") },
{ MODKEY|ShiftMask, XK_l, spawn, SHCMD("slock") },
{ MODKEY|ShiftMask, XK_m, spawn, SHCMD("st ~/scripts/autostart.sh") },
{ MODKEY|ShiftMask, XK_j, spawn, SHCMD("joplin-desktop") },
{ MODKEY|ShiftMask, XK_s, spawn, SHCMD("~/scripts/screenshot.sh 1") },
{ MODKEY|ShiftMask, XK_n, spawn, SHCMD("connman-gtk") },
{ MODKEY|ShiftMask, XK_x, spawn, SHCMD("mixer.sh") },
{ 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_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, XK_minus, setgaps, {.i = -5 } },
{ MODKEY, XK_equal, setgaps, {.i = +5 } },
{ MODKEY|ShiftMask, XK_equal, setgaps, {.i = 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 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} },
};


+ 33
- 0
config.def.h.rej View File

@@ -0,0 +1,33 @@
--- config.def.h
+++ config.def.h
@@ -5,6 +5,14 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
+
+/* Display modes of the tab bar: never shown, always shown, shown only in */
+/* monocle mode in presence of several windows. */
+/* Modes after showtab_nmodes are disabled */
+enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
+static const int showtab = showtab_auto; /* Default tab bar show mode */
+static const Bool toptab = False; /* False means bottom tab bar */
+
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
@@ -18,9 +26,15 @@ static const char *colors[SchemeLast][3] = {
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};
+
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+/* default layout per tags */
+/* The first element is for all-tag view, following i-th element corresponds to */
+/* tags[i]. Layout is referred using the layouts array index.*/
+static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class

+ 25
- 12
config.h View File

@@ -7,6 +7,14 @@ static const unsigned int snap = 32; /* snap pixel */
static const int swallowfloating = 0; /* 1 means swallow floating windows by default */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */

/* Display modes of the tab bar: never shown, always shown, shown only in */
/* monocle mode in presence of several windows. */
/* Modes after showtab_nmodes are disabled */
enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
static const int showtab = showtab_auto; /* Default tab bar show mode */
static const Bool toptab = False; /* False means bottom tab bar */

static const char *fonts[] = { "fontawesome:size=15", "DejaVuSansMono Nerd Font Mono:size=13"} ;
static const char dmenufont[] = "monospace:size=13";
static const char col_gray1[] = "#222222";
@@ -22,27 +30,30 @@ static const char *colors[][3] = {

static const char *const autostart[] = {
"sh", "-c", "sh ~/scripts/xinit.sh", NULL,
"dunst", NULL,
"slstatus", NULL,
NULL /* terminate */
};

/* tagging */
static const char *tags[] = { "", "", "", "", "", "", "", "", "" };

/* default layout per tags */
/* The first element is for all-tag view, following i-th element corresponds to */
/* tags[i]. Layout is referred using the layouts array index.*/
static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 2, 0, 2, 2};


static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
* WM_NAME(STRING) = title
*/
/* class instance title tags mask iscentered isfloating monitor */
{ "Gimp", NULL, NULL, 0, 0, 1, -1 },
{ "Firefox", NULL, NULL, 1 << 8, 0, 0, -1 },
/* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 0,0, 1, 0, 0, -1 },
{ "Firefox", NULL, NULL, 1 << 8,0, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0,0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0,0, 0, 0, 1, -1 }, /* xev */

/* class instance title tags mask iscentered isfloating isterminal noswallow monitor */
{ "Gimp", NULL, NULL, 1 << 7, 0, 1, 0, 0, -1 },
{ "LibreWolf", NULL, NULL, 1 << 0, 0, 0, 0, -1, -1 },
{ "firefox", NULL, NULL, 1 << 0, 0, 0, 0, -1, -1 },
{ "St", NULL, NULL, 0, 0, 0, 1, 0, -1 },
{ NULL, NULL, "Event Tester", 0, 0, 0, 0, 1, -1 }, /* xev */
};

/* layout(s) */
@@ -82,8 +93,8 @@ static Key keys[] = {
{ 0, XK_Print, spawn, SHCMD("~/scripts/screenshot.sh") },
{ 0, XF86XK_PowerOff, spawn, SHCMD("~/scripts/poweroff.sh") },
{ 0, XF86XK_AudioMute, spawn, SHCMD("pulsemixer --toggle-mute") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("pulsemixer --change-volume +1") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("pulsemixer --change-volume -1") },
{ 0, XF86XK_AudioRaiseVolume, spawn, SHCMD("amixer -c 1 sset Master 1+") },
{ 0, XF86XK_AudioLowerVolume, spawn, SHCMD("amixer -c 1 sset Master 1-") },
{ 0, XF86XK_AudioPrev, spawn, SHCMD("cmus-remote --prev") },
{ 0, XF86XK_AudioNext, spawn, SHCMD("cmus-remote --next") },
{ 0, XF86XK_AudioPause, spawn, SHCMD("cmus-remote --pause") },
@@ -104,6 +115,7 @@ static Key keys[] = {
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_w, tabmode, {-1} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
@@ -156,5 +168,6 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTabBar, 0, Button1, focuswin, {0} },
};


+ 0
- 0
drw.o View File


BIN
dwm View File


+ 808
- 0
dwm-tab-v2b-pertab-56a31dc.diff View File

@@ -0,0 +1,808 @@
diff --git a/config.def.h b/config.def.h
index fd77a07..8cc91c0 100644
--- a/config.def.h
+++ b/config.def.h
@@ -5,6 +5,14 @@ static const unsigned int borderpx = 1; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom bar */
+
+/* Display modes of the tab bar: never shown, always shown, shown only in */
+/* monocle mode in presence of several windows. */
+/* Modes after showtab_nmodes are disabled */
+enum showtab_modes { showtab_never, showtab_auto, showtab_nmodes, showtab_always};
+static const int showtab = showtab_auto; /* Default tab bar show mode */
+static const Bool toptab = False; /* False means bottom tab bar */
+
static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222";
@@ -18,9 +26,15 @@ static const char *colors[SchemeLast][3] = {
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
};
+
/* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+/* default layout per tags */
+/* The first element is for all-tag view, following i-th element corresponds to */
+/* tags[i]. Layout is referred using the layouts array index.*/
+static int def_layouts[1 + LENGTH(tags)] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
static const Rule rules[] = {
/* xprop(1):
* WM_CLASS(STRING) = instance, class
@@ -64,6 +78,7 @@ static Key keys[] = {
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_w, tabmode, {-1} },
{ MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
@@ -111,5 +126,6 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
+ { ClkTabBar, 0, Button1, focuswin, {0} },
};
diff --git a/dwm.1 b/dwm.1
index 6687011..077d92b 100644
--- a/dwm.1
+++ b/dwm.1
@@ -19,14 +19,22 @@ layout applied.
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
.P
-Each screen contains a small status bar which displays all available tags, the
-layout, the title of the focused window, and the text read from the root window
-name property, if the screen is focused. A floating window is indicated with an
-empty square and a maximised floating window is indicated with a filled square
-before the windows title. The selected tags are indicated with a different
-color. The tags of the focused window are indicated with a filled square in the
-top left corner. The tags which are applied to one or more windows are
-indicated with an empty square in the top left corner.
+Each screen contains two small status bars.
+.P
+One bar displays all available tags, the layout, the title of the focused
+window, and the text read from the root window name property, if the screen is
+focused. A floating window is indicated with an empty square and a maximised
+floating window is indicated with a filled square before the windows title. The
+selected tags are indicated with a different color. The tags of the focused
+window are indicated with a filled square in the top left corner. The tags
+which are applied to one or more windows are indicated with an empty square in
+the top left corner.
+.P
+Another bar contains a tab for each window of the current view and allows
+navigation between windows, especially in the monocle mode. The different
+display modes of this bar are described under the Mod1\-w Keybord command
+section. When a single tag is selected, that tag is indicated in the left corner
+of the tab bar.
.P
dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS
@@ -43,7 +51,8 @@ command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
-label toggles between tiled and floating layout.
+label toggles between tiled and floating layout, click on a window name in the
+tab bar brings focus to that window.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
@@ -104,6 +113,12 @@ Increase master area size.
.B Mod1\-h
Decrease master area size.
.TP
+.B Mod1\-w
+Cycle over the tab bar display modes: never displayed, always displayed,
+displayed only in monocle mode when the view contains than one window (auto
+mode). Some display modes can be disabled in the configuration, config.h. In
+the default configuration only "never" and "auto" display modes are enabled.
+.TP
.B Mod1\-Return
Zooms/cycles focused window to/from master area (tiled layouts only).
.TP
diff --git a/dwm.c b/dwm.c
index b2bc9bd..0c34020 100644
--- a/dwm.c
+++ b/dwm.c
@@ -65,7 +65,7 @@ enum { NetSupported, NetWMName, NetWMState,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
-enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
typedef union {
@@ -112,25 +112,35 @@ typedef struct {
void (*arrange)(Monitor *);
} Layout;
+#define MAXTABS 50
+
+typedef struct Pertag Pertag;
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
+ int ty; /* tab bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
+ int showtab;
int topbar;
+ int toptab;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
+ Window tabwin;
+ int ntabs;
+ int tab_widths[MAXTABS];
const Layout *lt[2];
+ Pertag *pertag;
};
typedef struct {
@@ -165,12 +175,15 @@ static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
+static void drawtab(Monitor *m);
+static void drawtabs(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
+static void focuswin(const Arg* arg);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
@@ -207,6 +220,7 @@ static void setup(void);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
+static void tabmode(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
@@ -241,6 +255,7 @@ static char stext[256];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
+static int th = 0; /* tab bar geometry */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
@@ -272,6 +287,16 @@ static Window root;
/* configuration, allows nested code to access above variables */
#include "config.h"
+struct Pertag {
+ unsigned int curtag, prevtag; /* current and previous tag */
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
+ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
+};
+
/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
@@ -395,6 +420,8 @@ arrange(Monitor *m)
void
arrangemon(Monitor *m)
{
+ updatebarpos(m);
+ XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
@@ -444,14 +471,33 @@ buttonpress(XEvent *e)
click = ClkStatusText;
else
click = ClkWinTitle;
- } else if ((c = wintoclient(ev->window))) {
+ }
+ if(ev->window == selmon->tabwin) {
+ i = 0; x = 0;
+ for(c = selmon->clients; c; c = c->next){
+ if(!ISVISIBLE(c)) continue;
+ x += selmon->tab_widths[i];
+ if (ev->x > x)
+ ++i;
+ else
+ break;
+ if(i >= m->ntabs) break;
+ }
+ if(c) {
+ click = ClkTabBar;
+ arg.ui = i;
+ }
+ }
+ else if((c = wintoclient(ev->window))) {
focus(c);
click = ClkClientWin;
}
- for (i = 0; i < LENGTH(buttons); i++)
- if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+ for(i = 0; i < LENGTH(buttons); i++)
+ if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
+ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
+ buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
+ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
+ }
}
void
@@ -476,8 +522,8 @@ cleanup(void)
view(&a);
selmon->lt[selmon->sellt] = &foo;
for (m = mons; m; m = m->next)
- while (m->stack)
- unmanage(m->stack, 0);
+ while(m->stack)
+ unmanage(m->stack, False);
XUngrabKey(dpy, AnyKey, AnyModifier, root);
while (mons)
cleanupmon(mons);
@@ -504,6 +550,8 @@ cleanupmon(Monitor *mon)
}
XUnmapWindow(dpy, mon->barwin);
XDestroyWindow(dpy, mon->barwin);
+ XUnmapWindow(dpy, mon->tabwin);
+ XDestroyWindow(dpy, mon->tabwin);
free(mon);
}
@@ -525,6 +573,7 @@ clientmessage(XEvent *e)
{
XClientMessageEvent *cme = &e->xclient;
Client *c = wintoclient(cme->window);
+ int i;
if (!c)
return;
@@ -536,6 +585,8 @@ clientmessage(XEvent *e)
if (!ISVISIBLE(c)) {
c->mon->seltags ^= 1;
c->mon->tagset[c->mon->seltags] = c->tags;
+ for(i=0; !(c->tags & 1 << i); i++);
+ view(&(Arg){.ui = 1 << i});
}
pop(c);
}
@@ -564,11 +615,10 @@ void
configurenotify(XEvent *e)
{
Monitor *m;
- Client *c;
XConfigureEvent *ev = &e->xconfigure;
int dirty;
- /* TODO: updategeom handling sucks, needs to be simplified */
+ // TODO: updategeom handling sucks, needs to be simplified
if (ev->window == root) {
dirty = (sw != ev->width || sh != ev->height);
sw = ev->width;
@@ -576,10 +626,9 @@ configurenotify(XEvent *e)
if (updategeom() || dirty) {
drw_resize(drw, sw, bh);
updatebars();
- for (m = mons; m; m = m->next) {
- for (c = m->clients; c; c = c->next)
- if (c->isfullscreen)
- resizeclient(c, m->mx, m->my, m->mw, m->mh);
+ //refreshing display of status bar. The tab bar is handled by the arrange()
+ //method, which is called below
+ for (m = mons; m; m = m->next){
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
}
focus(NULL);
@@ -644,16 +693,41 @@ Monitor *
createmon(void)
{
Monitor *m;
+ int i;
m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
m->mfact = mfact;
m->nmaster = nmaster;
m->showbar = showbar;
+ m->showtab = showtab;
m->topbar = topbar;
- m->lt[0] = &layouts[0];
+ m->toptab = toptab;
+ m->ntabs = 0;
+ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+ m->pertag->curtag = m->pertag->prevtag = 1;
+ for(i=0; i <= LENGTH(tags); i++) {
+ /* init nmaster */
+ m->pertag->nmasters[i] = m->nmaster;
+
+ /* init mfacts */
+ m->pertag->mfacts[i] = m->mfact;
+
+ /* init layouts */
+ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)];
+ m->pertag->ltidxs[i][1] = m->lt[1];
+ m->pertag->sellts[i] = m->sellt;
+
+ /* init showbar */
+ m->pertag->showbars[i] = m->showbar;
+
+ /* swap focus and zoomswap*/
+ m->pertag->prevzooms[i] = NULL;
+ }
return m;
}
@@ -765,6 +839,104 @@ drawbars(void)
}
void
+drawtabs(void) {
+ Monitor *m;
+
+ for(m = mons; m; m = m->next)
+ drawtab(m);
+}
+
+static int
+cmpint(const void *p1, const void *p2) {
+ /* The actual arguments to this function are "pointers to
+ pointers to char", but strcmp(3) arguments are "pointers
+ to char", hence the following cast plus dereference */
+ return *((int*) p1) > * (int*) p2;
+}
+
+
+void
+drawtab(Monitor *m) {
+ Client *c;
+ int i;
+ int itag = -1;
+ char view_info[50];
+ int view_info_w = 0;
+ int sorted_label_widths[MAXTABS];
+ int tot_width;
+ int maxsize = bh;
+ int x = 0;
+ int w = 0;
+
+ //view_info: indicate the tag which is displayed in the view
+ for(i = 0; i < LENGTH(tags); ++i){
+ if((selmon->tagset[selmon->seltags] >> i) & 1) {
+ if(itag >=0){ //more than one tag selected
+ itag = -1;
+ break;
+ }
+ itag = i;
+ }
+ }
+ if(0 <= itag && itag < LENGTH(tags)){
+ snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
+ } else {
+ strncpy(view_info, "[...]", sizeof view_info);
+ }
+ view_info[sizeof(view_info) - 1 ] = 0;
+ view_info_w = TEXTW(view_info);
+ tot_width = view_info_w;
+
+ /* Calculates number of labels and their width */
+ m->ntabs = 0;
+ for(c = m->clients; c; c = c->next){
+ if(!ISVISIBLE(c)) continue;
+ m->tab_widths[m->ntabs] = TEXTW(c->name);
+ tot_width += m->tab_widths[m->ntabs];
+ ++m->ntabs;
+ if(m->ntabs >= MAXTABS) break;
+ }
+
+ if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
+ memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
+ qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
+ tot_width = view_info_w;
+ for(i = 0; i < m->ntabs; ++i){
+ if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
+ break;
+ tot_width += sorted_label_widths[i];
+ }
+ maxsize = (m->ww - tot_width) / (m->ntabs - i);
+ } else{
+ maxsize = m->ww;
+ }
+ i = 0;
+ for(c = m->clients; c; c = c->next){
+ if(!ISVISIBLE(c)) continue;
+ if(i >= m->ntabs) break;
+ if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize;
+ w = m->tab_widths[i];
+ drw_setscheme(drw, (c == m->sel) ? scheme[SchemeSel] : scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, th, lrpad / 2, c->name, 0);
+ x += w;
+ ++i;
+ }
+
+ drw_setscheme(drw, scheme[SchemeNorm]);
+
+ /* cleans interspace between window names and current viewed tag label */
+ w = m->ww - view_info_w - x;
+ drw_text(drw, x, 0, w, th, lrpad / 2, "", 0);
+
+ /* view info */
+ x += w;
+ w = view_info_w;
+ drw_text(drw, x, 0, w, th, lrpad / 2, view_info, 0);
+
+ drw_map(drw, m->tabwin, 0, 0, m->ww, th);
+}
+
+void
enternotify(XEvent *e)
{
Client *c;
@@ -789,8 +961,10 @@ expose(XEvent *e)
Monitor *m;
XExposeEvent *ev = &e->xexpose;
- if (ev->count == 0 && (m = wintomon(ev->window)))
+ if (ev->count == 0 && (m = wintomon(ev->window))){
drawbar(m);
+ drawtab(m);
+ }
}
void
@@ -817,6 +991,7 @@ focus(Client *c)
}
selmon->sel = c;
drawbars();
+ drawtabs();
}
/* there are some broken focus acquiring clients */
@@ -870,6 +1045,19 @@ focusstack(const Arg *arg)
}
}
+void
+focuswin(const Arg* arg){
+ int iwin = arg->i;
+ Client* c = NULL;
+ for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
+ if(ISVISIBLE(c)) --iwin;
+ };
+ if(c) {
+ focus(c);
+ restack(selmon);
+ }
+}
+
Atom
getatomprop(Client *c, Atom prop)
{
@@ -983,7 +1171,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);
}
@@ -1142,7 +1330,7 @@ motionnotify(XEvent *e)
if (ev->window != root)
return;
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
- unfocus(selmon->sel, 1);
+ unfocus(selmon->sel, True);
selmon = m;
focus(NULL);
}
@@ -1162,11 +1350,13 @@ movemouse(const Arg *arg)
return;
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
return;
+ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
return;
if (!getrootptr(&x, &y))
return;
@@ -1253,12 +1443,14 @@ propertynotify(XEvent *e)
case XA_WM_HINTS:
updatewmhints(c);
drawbars();
+ drawtabs();
break;
}
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c);
if (c == c->mon->sel)
drawbar(c->mon);
+ drawtab(c->mon);
}
if (ev->atom == netatom[NetWMWindowType])
updatewindowtype(c);
@@ -1320,11 +1512,13 @@ resizemouse(const Arg *arg)
return;
if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
return;
+ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
do {
@@ -1372,6 +1566,7 @@ restack(Monitor *m)
XWindowChanges wc;
drawbar(m);
+ drawtab(m);
if (!m->sel)
return;
if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
@@ -1480,11 +1675,11 @@ sendevent(Client *c, Atom proto)
void
setfocus(Client *c)
{
- if (!c->neverfocus) {
+ if(!c->neverfocus) {
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XChangeProperty(dpy, root, netatom[NetActiveWindow],
- XA_WINDOW, 32, PropModeReplace,
- (unsigned char *) &(c->win), 1);
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(c->win), 1);
}
sendevent(c, wmatom[WMTakeFocus]);
}
@@ -1520,10 +1715,13 @@ setfullscreen(Client *c, int fullscreen)
void
setlayout(const Arg *arg)
{
- if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
- selmon->sellt ^= 1;
- if (arg && arg->v)
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ }
+ if(arg && arg->v)
+ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
if (selmon->sel)
arrange(selmon);
@@ -1542,7 +1740,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);
}
@@ -1564,6 +1762,7 @@ setup(void)
die("no fonts could be loaded.\n");
lrpad = drw->fonts->h;
bh = drw->fonts->h + 2;
+ th = bh;
updategeom();
/* init atoms */
wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
@@ -1631,10 +1830,10 @@ sigchld(int unused)
void
spawn(const Arg *arg)
{
- if (arg->v == dmenucmd)
+ if(arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
- if (fork() == 0) {
- if (dpy)
+ if(fork() == 0) {
+ if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
@@ -1691,18 +1890,29 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
- selmon->showbar = !selmon->showbar;
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
arrange(selmon);
}
void
+tabmode(const Arg *arg)
+{
+ if(arg && arg->i >= 0)
+ selmon->showtab = arg->ui % showtab_nmodes;
+ else
+ selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
+ arrange(selmon);
+}
+
+
+void
togglefloating(const Arg *arg)
{
- if (!selmon->sel)
+ if(!selmon->sel)
return;
- if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
return;
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
if (selmon->sel->isfloating)
@@ -1730,9 +1940,29 @@ void
toggleview(const Arg *arg)
{
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+ int i;
if (newtagset) {
+ if(newtagset == ~0) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = 0;
+ }
+ /* test if the user did not select the same tag */
+ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ for (i=0; !(newtagset & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
selmon->tagset[selmon->seltags] = newtagset;
+
+ /* apply settings for this view */
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@@ -1808,20 +2038,44 @@ updatebars(void)
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin);
+ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->tabwin);
}
}
void
updatebarpos(Monitor *m)
{
+ Client *c;
+ int nvis = 0;
+
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
- m->wy = m->topbar ? m->wy + bh : m->wy;
- } else
+ if ( m->topbar )
+ m->wy += bh;
+ } else {
m->by = -bh;
+ }
+
+ for(c = m->clients; c; c = c->next){
+ if(ISVISIBLE(c)) ++nvis;
+ }
+
+ if(m->showtab == showtab_always
+ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){
+ m->wh -= th;
+ m->ty = m->toptab ? m->wy : m->wy + m->wh;
+ if ( m->toptab )
+ m->wy += th;
+ } else {
+ m->ty = -th;
+ }
}
void
@@ -2003,9 +2257,9 @@ updatewindowtype(Client *c)
Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
if (state == netatom[NetWMFullscreen])
- setfullscreen(c, 1);
+ setfullscreen(c, True);
if (wtype == netatom[NetWMWindowTypeDialog])
- c->isfloating = 1;
+ c->isfloating = True;
}
void
@@ -2030,11 +2284,33 @@ updatewmhints(Client *c)
void
view(const Arg *arg)
{
- if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ int i;
+ unsigned int tmptag;
+
+ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
selmon->seltags ^= 1; /* toggle sel tagset */
- if (arg->ui & TAGMASK)
+ if(arg->ui & TAGMASK) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ if(arg->ui == ~0)
+ selmon->pertag->curtag = 0;
+ else {
+ for (i=0; !(arg->ui & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+ } else {
+ tmptag = selmon->pertag->prevtag;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = tmptag;
+ }
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@@ -2062,7 +2338,7 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next)
- if (w == m->barwin)
+ if(w == m->barwin || w == m->tabwin)
return m;
if ((c = wintoclient(w)))
return c->mon;

+ 24
- 9
dwm.1 View File

@@ -20,14 +20,22 @@ layout applied.
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
.P
Each screen contains a small status bar which displays all available tags, the
layout, the title of the focused window, and the text read from the root window
name property, if the screen is focused. A floating window is indicated with an
empty square and a maximised floating window is indicated with a filled square
before the windows title. The selected tags are indicated with a different
color. The tags of the focused window are indicated with a filled square in the
top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner.
Each screen contains two small status bars.
.P
One bar displays all available tags, the layout, the title of the focused
window, and the text read from the root window name property, if the screen is
focused. A floating window is indicated with an empty square and a maximised
floating window is indicated with a filled square before the windows title. The
selected tags are indicated with a different color. The tags of the focused
window are indicated with a filled square in the top left corner. The tags
which are applied to one or more windows are indicated with an empty square in
the top left corner.
.P
Another bar contains a tab for each window of the current view and allows
navigation between windows, especially in the monocle mode. The different
display modes of this bar are described under the Mod1\-w Keybord command
section. When a single tag is selected, that tag is indicated in the left corner
of the tab bar.
.P
dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS
@@ -44,7 +52,8 @@ command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
label toggles between tiled and floating layout.
label toggles between tiled and floating layout, click on a window name in the
tab bar brings focus to that window.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
@@ -110,6 +119,12 @@ Increase master area size.
.B Mod1\-h
Decrease master area size.
.TP
.B Mod1\-w
Cycle over the tab bar display modes: never displayed, always displayed,
displayed only in monocle mode when the view contains than one window (auto
mode). Some display modes can be disabled in the configuration, config.h. In
the default configuration only "never" and "auto" display modes are enabled.
.TP
.B Mod1\-Return
Zooms/cycles focused window to/from master area (tiled layouts only).
.TP


+ 176
- 0
dwm.1.orig View File

@@ -0,0 +1,176 @@
.TH DWM 1 dwm\-VERSION
.SH NAME
dwm \- dynamic window manager
.SH SYNOPSIS
.B dwm
.RB [ \-v ]
.SH DESCRIPTION
dwm is a dynamic window manager for X. It manages windows in tiled, monocle
and floating layouts. Either layout can be applied dynamically, optimising the
environment for the application in use and the task performed.
.P
In tiled layouts windows are managed in a master and stacking area. The master
area on the left contains one window by default, and the stacking area on the
right contains all other windows. The number of master area windows can be
adjusted from zero to an arbitrary number. In monocle layout all windows are
maximised to the screen size. In floating layout windows can be resized and
moved freely. Dialog windows are always managed floating, regardless of the
layout applied.
.P
Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags.
.P
Each screen contains a small status bar which displays all available tags, the
layout, the title of the focused window, and the text read from the root window
name property, if the screen is focused. A floating window is indicated with an
empty square and a maximised floating window is indicated with a filled square
before the windows title. The selected tags are indicated with a different
color. The tags of the focused window are indicated with a filled square in the
top left corner. The tags which are applied to one or more windows are
indicated with an empty square in the top left corner.
.P
dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS
.TP
.B \-v
prints version information to standard output, then exits.
.SH USAGE
.SS Status bar
.TP
.B X root window name
is read and displayed in the status text area. It can be set with the
.BR xsetroot (1)
command.
.TP
.B Button1
click on a tag label to display all windows with that tag, click on the layout
label toggles between tiled and floating layout.
.TP
.B Button3
click on a tag label adds/removes all windows with that tag to/from the view.
.TP
.B Mod1\-Button1
click on a tag label applies that tag to the focused window.
.TP
.B Mod1\-Button3
click on a tag label adds/removes that tag to/from the focused window.
.SS Keyboard commands
.TP
.B Mod1\-Shift\-Return
Start
.BR st(1).
.TP
.B Mod1\-p
Spawn
.BR dmenu(1)
for launching other programs.
.TP
.B Mod1\-,
Focus previous screen, if any.
.TP
.B Mod1\-.
Focus next screen, if any.
.TP
.B Mod1\-Shift\-,
Send focused window to previous screen, if any.
.TP
.B Mod1\-Shift\-.
Send focused window to next screen, if any.
.TP
.B Mod1\-b
Toggles bar on and off.
.TP
.B Mod1\-t
Sets tiled layout.
.TP
.B Mod1\-f
Sets floating layout.
.TP
.B Mod1\-m
Sets monocle layout.
.TP
.B Mod1\-space
Toggles between current and previous layout.
.TP
.B Mod1\-j
Focus next window.
.TP
.B Mod1\-k
Focus previous window.
.TP
.B Mod1\-i
Increase number of windows in master area.
.TP
.B Mod1\-d
Decrease number of windows in master area.
.TP
.B Mod1\-l
Increase master area size.
.TP
.B Mod1\-h
Decrease master area size.
.TP
.B Mod1\-Return
Zooms/cycles focused window to/from master area (tiled layouts only).
.TP
.B Mod1\-Shift\-c
Close focused window.
.TP
.B Mod1\-Shift\-space
Toggle focused window between tiled and floating state.
.TP
.B Mod1\-Tab
Toggles to the previously selected tags.
.TP
.B Mod1\-Shift\-[1..n]
Apply nth tag to focused window.
.TP
.B Mod1\-Shift\-0
Apply all tags to focused window.
.TP
.B Mod1\-Control\-Shift\-[1..n]
Add/remove nth tag to/from focused window.
.TP
.B Mod1\-[1..n]
View all windows with nth tag.
.TP
.B Mod1\-0
View all windows with any tag.
.TP
.B Mod1\-Control\-[1..n]
Add/remove all windows with nth tag to/from the view.
.TP
.B Mod1\-Shift\-q
Quit dwm.
.SS Mouse commands
.TP
.B Mod1\-Button1
Move focused window while dragging. Tiled windows will be toggled to the floating state.
.TP
.B Mod1\-Button2
Toggles focused window between floating and tiled state.
.TP
.B Mod1\-Button3
Resize focused window while dragging. Tiled windows will be toggled to the floating state.
.SH CUSTOMIZATION
dwm is customized by creating a custom config.h and (re)compiling the source
code. This keeps it fast, secure and simple.
.SH SEE ALSO
.BR dmenu (1),
.BR st (1)
.SH ISSUES
Java applications which use the XToolkit/XAWT backend may draw grey windows
only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds
are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the
environment variable
.BR AWT_TOOLKIT=MToolkit
(to use the older Motif backend instead) or running
.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D
or
.B wmname LG3D
(to pretend that a non-reparenting window manager is running that the
XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable
.BR _JAVA_AWT_WM_NONREPARENTING=1 .
.SH BUGS
Send all bug reports with a patch to hackers@suckless.org.

+ 309
- 39
dwm.c View File

@@ -70,7 +70,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */

typedef union {
@@ -119,12 +119,16 @@ typedef struct {
void (*arrange)(Monitor *);
} Layout;

#define MAXTABS 50

typedef struct Pertag Pertag;
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int ty; /* tab bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
int gappx; /* gaps between windows */
@@ -132,13 +136,19 @@ struct Monitor {
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int showtab;
int topbar;
int toptab;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
Window tabwin;
int ntabs;
int tab_widths[MAXTABS] ;
const Layout *lt[2];
Pertag *pertag;
};

typedef struct {
@@ -175,12 +185,15 @@ static void detachstack(Client *c);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void drawtab(Monitor *m);
static void drawtabs(void);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
static void focuswin(const Arg* arg);
static int getrootptr(int *x, int *y);
static long getstate(Window w);
static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
@@ -219,6 +232,7 @@ static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void tabmode(const Arg *arg);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
@@ -263,6 +277,7 @@ static char stext[256];
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
static int th = 0; /* tab bar geometry */
static int lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
@@ -296,6 +311,16 @@ static xcb_connection_t *xcon;
/* configuration, allows nested code to access above variables */
#include "config.h"

struct Pertag {
unsigned int curtag, prevtag; /* current and previous tag */
int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
};

/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };

@@ -451,6 +476,8 @@ arrange(Monitor *m)
void
arrangemon(Monitor *m)
{
updatebarpos(m);
XMoveResizeWindow(dpy, m->tabwin, m->wx, m->ty, m->ww, th);
strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
@@ -547,16 +574,35 @@ buttonpress(XEvent *e)
click = ClkStatusText;
else
click = ClkWinTitle;
} else if ((c = wintoclient(ev->window))) {
}
if(ev->window == selmon->tabwin) {
i = 0; x = 0;
for(c = selmon->clients; c; c = c->next){
if(!ISVISIBLE(c)) continue;
x += selmon->tab_widths[i];
if (ev->x > x)
++i;
else
break;
if(i >= m->ntabs) break;
}
if(c) {
click = ClkTabBar;
arg.ui = i;
}
}
else if((c = wintoclient(ev->window))) {
focus(c);
restack(selmon);
XAllowEvents(dpy, ReplayPointer, CurrentTime);
click = ClkClientWin;
}
for (i = 0; i < LENGTH(buttons); i++)
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
for(i = 0; i < LENGTH(buttons); i++)
if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
&& buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
}
}

void
@@ -581,8 +627,8 @@ cleanup(void)
view(&a);
selmon->lt[selmon->sellt] = &foo;
for (m = mons; m; m = m->next)
while (m->stack)
unmanage(m->stack, 0);
while(m->stack)
unmanage(m->stack, False);
XUngrabKey(dpy, AnyKey, AnyModifier, root);
while (mons)
cleanupmon(mons);
@@ -610,6 +656,8 @@ cleanupmon(Monitor *mon)
}
XUnmapWindow(dpy, mon->barwin);
XDestroyWindow(dpy, mon->barwin);
XUnmapWindow(dpy, mon->tabwin);
XDestroyWindow(dpy, mon->tabwin);
free(mon);
}

@@ -618,6 +666,7 @@ clientmessage(XEvent *e)
{
XClientMessageEvent *cme = &e->xclient;
Client *c = wintoclient(cme->window);
int i;

if (!c)
return;
@@ -655,11 +704,10 @@ void
configurenotify(XEvent *e)
{
Monitor *m;
Client *c;
XConfigureEvent *ev = &e->xconfigure;
int dirty;

/* TODO: updategeom handling sucks, needs to be simplified */
// TODO: updategeom handling sucks, needs to be simplified
if (ev->window == root) {
dirty = (sw != ev->width || sh != ev->height);
sw = ev->width;
@@ -667,10 +715,9 @@ configurenotify(XEvent *e)
if (updategeom() || dirty) {
drw_resize(drw, sw, bh);
updatebars();
for (m = mons; m; m = m->next) {
for (c = m->clients; c; c = c->next)
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
//refreshing display of status bar. The tab bar is handled by the arrange()
//method, which is called below
for (m = mons; m; m = m->next){
XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
}
focus(NULL);
@@ -735,17 +782,42 @@ Monitor *
createmon(void)
{
Monitor *m;
int i ;

m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
m->mfact = mfact;
m->nmaster = nmaster;
m->showbar = showbar;
m->topbar = topbar;
m->showtab = showtab;
m->topbar = topbar;
m->gappx = gappx;
m->lt[0] = &layouts[0];
m->toptab = toptab;
m->ntabs = 0;
m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
m->pertag->curtag = m->pertag->prevtag = 1;
for(i=0; i <= LENGTH(tags); i++) {
/* init nmaster */
m->pertag->nmasters[i] = m->nmaster;

/* init mfacts */
m->pertag->mfacts[i] = m->mfact;

/* init layouts */
m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)];
m->pertag->ltidxs[i][1] = m->lt[1];
m->pertag->sellts[i] = m->sellt;

/* init showbar */
m->pertag->showbars[i] = m->showbar;

/* swap focus and zoomswap*/
m->pertag->prevzooms[i] = NULL;
}
return m;
}

@@ -862,6 +934,104 @@ drawbars(void)
drawbar(m);
}

void
drawtabs(void) {
Monitor *m;

for(m = mons; m; m = m->next)
drawtab(m);
}

static int
cmpint(const void *p1, const void *p2) {
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference */
return *((int*) p1) > * (int*) p2;
}


void
drawtab(Monitor *m) {
Client *c;
int i;
int itag = -1;
char view_info[50];
int view_info_w = 0;
int sorted_label_widths[MAXTABS];
int tot_width;
int maxsize = bh;
int x = 0;
int w = 0;

//view_info: indicate the tag which is displayed in the view
for(i = 0; i < LENGTH(tags); ++i){
if((selmon->tagset[selmon->seltags] >> i) & 1) {
if(itag >=0){ //more than one tag selected
itag = -1;
break;
}
itag = i;
}
}
if(0 <= itag && itag < LENGTH(tags)){
snprintf(view_info, sizeof view_info, "[%s]", tags[itag]);
} else {
strncpy(view_info, "[...]", sizeof view_info);
}
view_info[sizeof(view_info) - 1 ] = 0;
view_info_w = TEXTW(view_info);
tot_width = view_info_w;

/* Calculates number of labels and their width */
m->ntabs = 0;
for(c = m->clients; c; c = c->next){
if(!ISVISIBLE(c)) continue;
m->tab_widths[m->ntabs] = TEXTW(c->name);
tot_width += m->tab_widths[m->ntabs];
++m->ntabs;
if(m->ntabs >= MAXTABS) break;
}

if(tot_width > m->ww){ //not enough space to display the labels, they need to be truncated
memcpy(sorted_label_widths, m->tab_widths, sizeof(int) * m->ntabs);
qsort(sorted_label_widths, m->ntabs, sizeof(int), cmpint);
tot_width = view_info_w;
for(i = 0; i < m->ntabs; ++i){
if(tot_width + (m->ntabs - i) * sorted_label_widths[i] > m->ww)
break;
tot_width += sorted_label_widths[i];
}
maxsize = (m->ww - tot_width) / (m->ntabs - i);
} else{
maxsize = m->ww;
}
i = 0;
for(c = m->clients; c; c = c->next){
if(!ISVISIBLE(c)) continue;
if(i >= m->ntabs) break;
if(m->tab_widths[i] > maxsize) m->tab_widths[i] = maxsize;
w = m->tab_widths[i];
drw_setscheme(drw, (c == m->sel) ? scheme[SchemeSel] : scheme[SchemeNorm]);
drw_text(drw, x, 0, w, th, lrpad / 2, c->name, 0);
x += w;
++i;
}

drw_setscheme(drw, scheme[SchemeNorm]);

/* cleans interspace between window names and current viewed tag label */
w = m->ww - view_info_w - x;
drw_text(drw, x, 0, w, th, lrpad / 2, "", 0);

/* view info */
x += w;
w = view_info_w;
drw_text(drw, x, 0, w, th, lrpad / 2, view_info, 0);

drw_map(drw, m->tabwin, 0, 0, m->ww, th);
}

void
enternotify(XEvent *e)
{
@@ -887,8 +1057,10 @@ expose(XEvent *e)
Monitor *m;
XExposeEvent *ev = &e->xexpose;

if (ev->count == 0 && (m = wintomon(ev->window)))
if (ev->count == 0 && (m = wintomon(ev->window))){
drawbar(m);
drawtab(m);
}
}

void
@@ -914,6 +1086,7 @@ focus(Client *c)
}
selmon->sel = c;
drawbars();
drawtabs();
}

/* there are some broken focus acquiring clients needing extra handling */
@@ -966,6 +1139,19 @@ focusstack(const Arg *arg)
}
}

void
focuswin(const Arg* arg){
int iwin = arg->i;
Client* c = NULL;
for(c = selmon->clients; c && (iwin || !ISVISIBLE(c)) ; c = c->next){
if(ISVISIBLE(c)) --iwin;
};
if(c) {
focus(c);
restack(selmon);
}
}

Atom
getatomprop(Client *c, Atom prop)
{
@@ -1077,7 +1263,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);
}

@@ -1244,7 +1430,7 @@ motionnotify(XEvent *e)
if (ev->window != root)
return;
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
unfocus(selmon->sel, 1);
unfocus(selmon->sel, True);
selmon = m;
focus(NULL);
}
@@ -1352,12 +1538,14 @@ propertynotify(XEvent *e)
case XA_WM_HINTS:
updatewmhints(c);
drawbars();
drawtabs();
break;
}
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c);
if (c == c->mon->sel)
drawbar(c->mon);
drawtab(c->mon);
}
if (ev->atom == netatom[NetWMWindowType])
updatewindowtype(c);
@@ -1481,6 +1669,7 @@ restack(Monitor *m)
XWindowChanges wc;

drawbar(m);
drawtab(m);
if (!m->sel)
return;
if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
@@ -1650,10 +1839,13 @@ setgaps(const Arg *arg)
void
setlayout(const Arg *arg)
{
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
selmon->sellt ^= 1;
if (arg && arg->v)
selmon->lt[selmon->sellt] = (Layout *)arg->v;
if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) {
selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
}
if(arg && arg->v)
selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
if (selmon->sel)
arrange(selmon);
@@ -1672,7 +1864,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);
}

@@ -1696,6 +1888,7 @@ setup(void)
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
bh = drw->fonts->h + 2;
th = bh;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@@ -1805,10 +1998,10 @@ sigchld(int unused)
void
spawn(const Arg *arg)
{
if (arg->v == dmenucmd)
if(arg->v == dmenucmd)
dmenumon[0] = '0' + selmon->num;
if (fork() == 0) {
if (dpy)
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
@@ -1865,18 +2058,29 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
selmon->showbar = !selmon->showbar;
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
updatebarpos(selmon);
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
arrange(selmon);
}

void
tabmode(const Arg *arg)
{
if(arg && arg->i >= 0)
selmon->showtab = arg->ui % showtab_nmodes;
else
selmon->showtab = (selmon->showtab + 1 ) % showtab_nmodes;
arrange(selmon);
}


void
togglefloating(const Arg *arg)
{
if (!selmon->sel)
if(!selmon->sel)
return;
if (selmon->sel->isfullscreen) /* no support for fullscreen windows */
if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
return;
selmon->sel->isfloating = !selmon->sel->isfloating || selmon->sel->isfixed;
if (selmon->sel->isfloating)
@@ -1930,9 +2134,29 @@ void
toggleview(const Arg *arg)
{
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
int i;

if (newtagset) {
if(newtagset == ~0) {
selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->pertag->curtag = 0;
}
/* test if the user did not select the same tag */
if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
selmon->pertag->prevtag = selmon->pertag->curtag;
for (i=0; !(newtagset & 1 << i); i++) ;
selmon->pertag->curtag = i + 1;
}
selmon->tagset[selmon->seltags] = newtagset;

/* apply settings for this view */
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@@ -2025,6 +2249,11 @@ updatebars(void)
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin);
m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->tabwin);
XSetClassHint(dpy, m->barwin, &ch);
}
}
@@ -2032,14 +2261,33 @@ updatebars(void)
void
updatebarpos(Monitor *m)
{
m->wy = m->my;
Client *c;
int nvis = 0;

m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
m->wy = m->topbar ? m->wy + bh : m->wy;
} else
m->by = -bh;
if ( m->topbar )
m->wy += bh;
} else {
m->by = -bh;
}

for(c = m->clients; c; c = c->next){
if(ISVISIBLE(c)) ++nvis;
}

if(m->showtab == showtab_always
|| ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){
m->wh -= th;
m->ty = m->toptab ? m->wy : m->wy + m->wh;
if ( m->toptab )
m->wy += th;
} else {
m->ty = -th;
}
}

void
@@ -2217,10 +2465,10 @@ updatewindowtype(Client *c)
Atom wtype = getatomprop(c, netatom[NetWMWindowType]);

if (state == netatom[NetWMFullscreen])
setfullscreen(c, 1);
setfullscreen(c, True);
if (wtype == netatom[NetWMWindowTypeDialog]) {
c->iscentered = 1;
c->isfloating = 1;
c->isfloating = True;
}
}

@@ -2246,11 +2494,33 @@ updatewmhints(Client *c)
void
view(const Arg *arg)
{
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
int i;
unsigned int tmptag;

if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
return;
selmon->seltags ^= 1; /* toggle sel tagset */
if (arg->ui & TAGMASK)
if(arg->ui & TAGMASK) {
selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
if(arg->ui == ~0)
selmon->pertag->curtag = 0;
else {
for (i=0; !(arg->ui & 1 << i); i++) ;
selmon->pertag->curtag = i + 1;
}
} else {
tmptag = selmon->pertag->prevtag;
selmon->pertag->prevtag = selmon->pertag->curtag;
selmon->pertag->curtag = tmptag;
}
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
togglebar(NULL);
focus(NULL);
arrange(selmon);
}
@@ -2408,7 +2678,7 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next)
if (w == m->barwin)
if(w == m->barwin || w == m->tabwin)
return m;
if ((c = wintoclient(w)))
return c->mon;


+ 2596
- 0
dwm.c.orig
File diff suppressed because it is too large
View File


+ 233
- 0
dwm.c.rej View File

@@ -0,0 +1,233 @@
--- dwm.c
+++ dwm.c
@@ -112,25 +112,35 @@ typedef struct {
void (*arrange)(Monitor *);
} Layout;
+#define MAXTABS 50
+
+typedef struct Pertag Pertag;
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
+ int ty; /* tab bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
+ int showtab;
int topbar;
+ int toptab;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
+ Window tabwin;
+ int ntabs;
+ int tab_widths[MAXTABS];
const Layout *lt[2];
+ Pertag *pertag;
};
typedef struct {
@@ -461,14 +488,33 @@ buttonpress(XEvent *e)
click = ClkStatusText;
else
click = ClkWinTitle;
- } else if ((c = wintoclient(ev->window))) {
+ }
+ if(ev->window == selmon->tabwin) {
+ i = 0; x = 0;
+ for(c = selmon->clients; c; c = c->next){
+ if(!ISVISIBLE(c)) continue;
+ x += selmon->tab_widths[i];
+ if (ev->x > x)
+ ++i;
+ else
+ break;
+ if(i >= m->ntabs) break;
+ }
+ if(c) {
+ click = ClkTabBar;
+ arg.ui = i;
+ }
+ }
+ else if((c = wintoclient(ev->window))) {
focus(c);
click = ClkClientWin;
}
- for (i = 0; i < LENGTH(buttons); i++)
- if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
- && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
- buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
+ for(i = 0; i < LENGTH(buttons); i++)
+ if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
+ && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)){
+ buttons[i].func(((click == ClkTagBar || click == ClkTabBar)
+ && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
+ }
}
void
@@ -556,6 +605,8 @@ clientmessage(XEvent *e)
if (!ISVISIBLE(c)) {
c->mon->seltags ^= 1;
c->mon->tagset[c->mon->seltags] = c->tags;
+ for(i=0; !(c->tags & 1 << i); i++);
+ view(&(Arg){.ui = 1 << i});
}
pop(c);
}
@@ -662,16 +711,41 @@ Monitor *
createmon(void)
{
Monitor *m;
+ int i;
m = ecalloc(1, sizeof(Monitor));
m->tagset[0] = m->tagset[1] = 1;
m->mfact = mfact;
m->nmaster = nmaster;
m->showbar = showbar;
+ m->showtab = showtab;
m->topbar = topbar;
- m->lt[0] = &layouts[0];
+ m->toptab = toptab;
+ m->ntabs = 0;
+ m->lt[0] = &layouts[def_layouts[1] % LENGTH(layouts)];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+ m->pertag->curtag = m->pertag->prevtag = 1;
+ for(i=0; i <= LENGTH(tags); i++) {
+ /* init nmaster */
+ m->pertag->nmasters[i] = m->nmaster;
+
+ /* init mfacts */
+ m->pertag->mfacts[i] = m->mfact;
+
+ /* init layouts */
+ m->pertag->ltidxs[i][0] = &layouts[def_layouts[i % LENGTH(def_layouts)] % LENGTH(layouts)];
+ m->pertag->ltidxs[i][1] = m->lt[1];
+ m->pertag->sellts[i] = m->sellt;
+
+ /* init showbar */
+ m->pertag->showbars[i] = m->showbar;
+
+ /* swap focus and zoomswap*/
+ m->pertag->prevzooms[i] = NULL;
+ }
return m;
}
@@ -1294,11 +1482,13 @@ movemouse(const Arg *arg)
return;
if (c->isfullscreen) /* no support moving fullscreen windows by mouse */
return;
+ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+ None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
return;
if (!getrootptr(&x, &y))
return;
@@ -1454,11 +1646,13 @@ resizemouse(const Arg *arg)
return;
if (c->isfullscreen) /* no support resizing fullscreen windows by mouse */
return;
+ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
restack(selmon);
ocx = c->x;
ocy = c->y;
if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
- None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+ None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
return;
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
do {
@@ -1615,11 +1810,11 @@ sendevent(Client *c, Atom proto)
void
setfocus(Client *c)
{
- if (!c->neverfocus) {
+ if(!c->neverfocus) {
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
XChangeProperty(dpy, root, netatom[NetActiveWindow],
- XA_WINDOW, 32, PropModeReplace,
- (unsigned char *) &(c->win), 1);
+ XA_WINDOW, 32, PropModeReplace,
+ (unsigned char *) &(c->win), 1);
}
sendevent(c, wmatom[WMTakeFocus]);
}
@@ -1978,20 +2208,44 @@ updatebars(void)
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin);
+ m->tabwin = XCreateWindow(dpy, root, m->wx, m->ty, m->ww, th, 0, DefaultDepth(dpy, screen),
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->tabwin, cursor[CurNormal]->cursor);
+ XMapRaised(dpy, m->tabwin);
}
}
void
updatebarpos(Monitor *m)
{
+ Client *c;
+ int nvis = 0;
+
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
- m->wy = m->topbar ? m->wy + bh : m->wy;
- } else
+ if ( m->topbar )
+ m->wy += bh;
+ } else {
m->by = -bh;
+ }
+
+ for(c = m->clients; c; c = c->next){
+ if(ISVISIBLE(c)) ++nvis;
+ }
+
+ if(m->showtab == showtab_always
+ || ((m->showtab == showtab_auto) && (nvis > 1) && (m->lt[m->sellt]->arrange == monocle))){
+ m->wh -= th;
+ m->ty = m->toptab ? m->wy : m->wy + m->wh;
+ if ( m->toptab )
+ m->wy += th;
+ } else {
+ m->ty = -th;
+ }
}
void
@@ -2173,9 +2427,9 @@ updatewindowtype(Client *c)
Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
if (state == netatom[NetWMFullscreen])
- setfullscreen(c, 1);
+ setfullscreen(c, True);
if (wtype == netatom[NetWMWindowTypeDialog])
- c->isfloating = 1;
+ c->isfloating = True;
}
void

BIN
dwm.o View File


+ 0
- 0
util.o View File


Loading…
Cancel
Save