saving changes before redoing

This commit is contained in:
Bryson Steck 2022-02-07 11:54:51 -07:00
parent 51eabedba7
commit 3425d4bda4
7 changed files with 286 additions and 63 deletions

2
.gitignore vendored
View file

@ -1,2 +1,2 @@
*.o *.o
/patches

View file

@ -6,6 +6,13 @@ static const unsigned int gappx = 6; /* gaps between windows */
static const unsigned int snap = 32; /* snap pixel */ static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */ static const int showbar = 1; /* 0 means no bar */
static const int topbar = 1; /* 0 means bottom 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 the 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 int toptab = False; /* False means bottom tab bar */
static const char *fonts[] = { "monospace:size=10" }; static const char *fonts[] = { "monospace:size=10" };
static const char dmenufont[] = "monospace:size=10"; static const char dmenufont[] = "monospace:size=10";
static const char col_gray1[] = "#222222"; static const char col_gray1[] = "#222222";
@ -66,6 +73,7 @@ static Key keys[] = {
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_w, tabmode, {-1} },
{ MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } },
@ -113,5 +121,6 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTabBar, 0, Button1, focuswin, {0} },
}; };

View file

@ -1,14 +1,15 @@
/* See LICENSE file for copyright and license details. */ /* See LICENSE file for copyright and license details. */
/* appearance */ /* appearance */
static const unsigned int borderpx = 0; /* border pixel of windows */ static const unsigned int borderpx = 3; /* border pixel of windows */
static const unsigned int snap = 32; /* snap pixel */ static const unsigned int snap = 32; /* snap pixel */
static const int showbar = 1; /* 0 means no bar */ static const int showbar = 1; /* 0 means no bar */
static const int topbar = 0; /* 0 means bottom bar */ static const int topbar = 0; /* 0 means bottom bar */
static const char *fonts[] = { "Roboto:size=14" }; static const char *fonts[] = { "Roboto:size=14", "emoji:size=14" };
static const char dmenufont[] = "Roboto:size=14"; static const char dmenufont[] = "Roboto:size=14";
static const char col_turquoise[] = "#00776C"; static const char col_turquoise[] = "#00776C";
static const char col_black[] = "#000000"; static const char col_black[] = "#000000";
static const char col_black_border[] = "#101010";
static const char col_gray1[] = "#222222"; static const char col_gray1[] = "#222222";
static const char col_gray1_5[] = "#333333"; static const char col_gray1_5[] = "#333333";
static const char col_gray2[] = "#444444"; static const char col_gray2[] = "#444444";
@ -21,19 +22,32 @@ static const char col_nord2[] = "#434c5e";
static const char col_nord3[] = "#4c566a"; static const char col_nord3[] = "#4c566a";
static const char col_nord4[] = "#d8dee9"; static const char col_nord4[] = "#d8dee9";
static const char col_nord10[] = "#5e81ac"; static const char col_nord10[] = "#5e81ac";
static const char col_white1[] = "#DBDBDD";
static const char col_white2[] = "#FFFFFF";
static const char col_purple1[] = "#02060F";
static const char col_purple2[] = "#0D0224";
static const char col_blue[] = "#144982"; static const char col_blue[] = "#144982";
static const char col_blue2[] = "#143968";
static const char col_orange[] = "#F59549";
static const char col_other[] = "#191C21";
static const char col_yellow[] = "#D3AD66"; static const char col_yellow[] = "#D3AD66";
static const char col_warm_white[] = "#DCD6B8"; static const char col_warm_white[] = "#DCD6B8";
static const unsigned int gappx = 6; static const unsigned int gappx = 6;
/* Display modes of the tab bar: never shown, always shown, shown only in */
/* monocle mode in the 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 int toptab = False; /* False means bottom tab bar */
static const char *colors[][3] = { static const char *colors[][3] = {
/* fg bg border */ /* fg bg border */
[SchemeNorm] = { col_nord4, col_black, col_black }, [SchemeNorm] = { col_nord4, col_black, col_black_border },
[SchemeSel] = { col_nord4, col_gray1, col_black }, [SchemeSel] = { col_nord4, col_gray1, col_blue },
}; };
/* tagging */ /* tagging */
static const char *tags[] = { "1", "2", "3", "4", "5" }; static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8" };
static const Rule rules[] = { static const Rule rules[] = {
/* xprop(1): /* xprop(1):
@ -49,6 +63,7 @@ static const Rule rules[] = {
{ "Wiimmfi-RPC v1.7.5",NULL,NULL, 0, 1, -1 }, { "Wiimmfi-RPC v1.7.5",NULL,NULL, 0, 1, -1 },
{ "minecraft-launcher",NULL,NULL, 0, 1, -1 }, { "minecraft-launcher",NULL,NULL, 0, 1, -1 },
{ "nitrogen", NULL, NULL, 0, 1, -1 }, { "nitrogen", NULL, NULL, 0, 1, -1 },
{ "Galculator",NULL, NULL, 0, 1, -1 },
}; };
/* layout(s) */ /* layout(s) */
@ -78,15 +93,22 @@ static const Layout layouts[] = {
/* commands */ /* commands */
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
static const char *dmenucmd[] = { "dmenu_run_history", "-b", "-m", dmenumon, "-fn", dmenufont, "-nb", col_black, "-nf", col_gray3, "-sb", col_blue, "-sf", col_gray4, NULL }; static const char *dmenucmd[] = { "dmenu_run_history", "-b", "-m", dmenumon, "-fn", dmenufont, "-nb", col_black, "-nf", col_gray3, "-sb", col_blue, "-sf", col_gray4, NULL };
static const char *termcmd[] = { "alacritty", NULL }; static const char *termcmd[] = { "spawn-alacritty.sh", NULL };
static const char *brightnessup[] = { "brightness-up", NULL }; static const char *brightnessup[] = { "brightness-up", NULL };
static const char *brightnessdown[] = { "brightness-down", NULL }; static const char *brightnessdown[] = { "brightness-down", NULL };
static const char *screenshooter[] = { "xfce4-screenshooter", NULL };
static const char *volup[] = { "volup.sh", NULL };
static const char *voldown[] = { "voldown.sh", NULL };
static const char *volmute[] = { "volmute.sh", NULL };
static const char *firefox[] = { "firefox", "--new-window", NULL };
static Key keys[] = { static Key keys[] = {
/* modifier key function argument */ /* modifier key function argument */
{ MODKEY, XK_p, spawn, {.v = dmenucmd } }, { MODKEY, XK_p, spawn, {.v = dmenucmd } },
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
{ MODKEY|ShiftMask, XK_f, spawn, {.v = firefox } },
{ MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_b, togglebar, {0} },
{ MODKEY, XK_w, tabmode, {-1} },
{ MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_j, focusstack, {.i = +1 } },
{ MODKEY, XK_k, focusstack, {.i = -1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } },
{ MODKEY, XK_i, incnmaster, {.i = +1 } }, { MODKEY, XK_i, incnmaster, {.i = +1 } },
@ -109,6 +131,10 @@ static Key keys[] = {
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } }, { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
{ MODKEY, XK_F4, spawn, {.v = brightnessup } }, { MODKEY, XK_F4, spawn, {.v = brightnessup } },
{ MODKEY, XK_F3, spawn, {.v = brightnessdown } }, { MODKEY, XK_F3, spawn, {.v = brightnessdown } },
{ MODKEY, XK_Print, spawn, {.v = screenshooter } },
{ MODKEY, XK_F9, spawn, {.v = volmute } },
{ MODKEY, XK_F10, spawn, {.v = voldown } },
{ MODKEY, XK_F11, spawn, {.v = volup } },
TAGKEYS( XK_1, 0) TAGKEYS( XK_1, 0)
TAGKEYS( XK_2, 1) TAGKEYS( XK_2, 1)
TAGKEYS( XK_3, 2) TAGKEYS( XK_3, 2)
@ -118,7 +144,7 @@ static Key keys[] = {
TAGKEYS( XK_7, 6) TAGKEYS( XK_7, 6)
TAGKEYS( XK_8, 7) TAGKEYS( XK_8, 7)
TAGKEYS( XK_9, 8) TAGKEYS( XK_9, 8)
{ MODKEY|ShiftMask, XK_q, quit, {0} }, { MODKEY|ShiftMask, XK_BackSpace, quit, {0} },
}; };
/* button definitions */ /* button definitions */
@ -136,5 +162,6 @@ static Button buttons[] = {
{ ClkTagBar, 0, Button3, toggleview, {0} }, { ClkTagBar, 0, Button3, toggleview, {0} },
{ ClkTagBar, MODKEY, Button1, tag, {0} }, { ClkTagBar, MODKEY, Button1, tag, {0} },
{ ClkTagBar, MODKEY, Button3, toggletag, {0} }, { ClkTagBar, MODKEY, Button3, toggletag, {0} },
{ ClkTabBar, 0, Button1, focuswin, {0} },
}; };

1
drw.c
View file

@ -203,6 +203,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
DefaultColormap(drw->dpy, drw->screen), DefaultColormap(drw->dpy, drw->screen),
clrname, dest)) clrname, dest))
die("error, cannot allocate color '%s'", clrname); die("error, cannot allocate color '%s'", clrname);
dest->pixel |= 0xff << 24;
} }
/* Wrapper to create color schemes. The caller has to call free(3) on the /* Wrapper to create color schemes. The caller has to call free(3) on the

BIN
dwm

Binary file not shown.

33
dwm.1
View file

@ -20,14 +20,22 @@ layout applied.
Windows are grouped by tags. Each window can be tagged with one or multiple Windows are grouped by tags. Each window can be tagged with one or multiple
tags. Selecting certain tags displays all windows with these tags. tags. Selecting certain tags displays all windows with these tags.
.P .P
Each screen contains a small status bar which displays all available tags, the Each screen contains two small status bars.
layout, the title of the focused window, and the text read from the root window .P
name property, if the screen is focused. A floating window is indicated with an One bar displays all available tags, the layout, the title of the focused
empty square and a maximised floating window is indicated with a filled square window, and the text read from the root window name property, if the screen is
before the windows title. The selected tags are indicated with a different focused. A floating window is indicated with an empty square and a maximised
color. The tags of the focused window are indicated with a filled square in the floating window is indicated with a filled square before the windows title. The
top left corner. The tags which are applied to one or more windows are selected tags are indicated with a different color. The tags of the focused
indicated with an empty square in the top left corner. 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, this tag is indicated in the left corner
of the tab bar.
.P .P
dwm draws a small border around windows to indicate the focus state. dwm draws a small border around windows to indicate the focus state.
.SH OPTIONS .SH OPTIONS
@ -44,7 +52,8 @@ command.
.TP .TP
.B Button1 .B Button1
click on a tag label to display all windows with that tag, click on the layout 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 .TP
.B Button3 .B Button3
click on a tag label adds/removes all windows with that tag to/from the view. 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 .B Mod1\-h
Decrease master area size. Decrease master area size.
.TP .TP
.B Mod1\-w
Cycle over the tab bar display modes: never displayed, always displayed,
displayed only in monocle mode when the view contains more 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 .B Mod1\-Return
Zooms/cycles focused window to/from master area (tiled layouts only). Zooms/cycles focused window to/from master area (tiled layouts only).
.TP .TP

263
dwm.c
View file

@ -64,7 +64,7 @@ enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
NetWMFullscreen, NetActiveWindow, NetWMWindowType, NetWMFullscreen, NetActiveWindow, NetWMWindowType,
NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */ enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, enum { ClkTagBar, ClkTabBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
ClkClientWin, ClkRootWin, ClkLast }; /* clicks */ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
typedef union { typedef union {
@ -111,24 +111,32 @@ typedef struct {
void (*arrange)(Monitor *); void (*arrange)(Monitor *);
} Layout; } Layout;
#define MAXTABS 50
struct Monitor { struct Monitor {
char ltsymbol[16]; char ltsymbol[16];
float mfact; float mfact;
int nmaster; int nmaster;
int num; int num;
int by; /* bar geometry */ int by; /* bar geometry */
int ty; /* tab bar geometry */
int mx, my, mw, mh; /* screen size */ int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */ int wx, wy, ww, wh; /* window area */
unsigned int seltags; unsigned int seltags;
unsigned int sellt; unsigned int sellt;
unsigned int tagset[2]; unsigned int tagset[2];
int showbar; int showbar;
int showtab;
int topbar; int topbar;
int toptab;
Client *clients; Client *clients;
Client *sel; Client *sel;
Client *stack; Client *stack;
Monitor *next; Monitor *next;
Window barwin; Window barwin;
Window tabwin;
int ntabs;
int tab_widths[MAXTABS];
const Layout *lt[2]; const Layout *lt[2];
}; };
@ -165,10 +173,13 @@ static void drawbar(Monitor *m);
static void drawbars(void); static void drawbars(void);
static void enternotify(XEvent *e); static void enternotify(XEvent *e);
static void expose(XEvent *e); static void expose(XEvent *e);
static void drawtab(Monitor *m);
static void drawtabs(void);
static void focus(Client *c); static void focus(Client *c);
static void focusin(XEvent *e); static void focusin(XEvent *e);
static void focusmon(const Arg *arg); static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg); static void focusstack(const Arg *arg);
static void focuswin(const Arg* arg);
static Atom getatomprop(Client *c, Atom prop); static Atom getatomprop(Client *c, Atom prop);
static int getrootptr(int *x, int *y); static int getrootptr(int *x, int *y);
static long getstate(Window w); static long getstate(Window w);
@ -207,6 +218,7 @@ static void seturgent(Client *c, int urg);
static void showhide(Client *c); static void showhide(Client *c);
static void sigchld(int unused); static void sigchld(int unused);
static void spawn(const Arg *arg); static void spawn(const Arg *arg);
static void tabmode(const Arg *arg);
static void tag(const Arg *arg); static void tag(const Arg *arg);
static void tagmon(const Arg *arg); static void tagmon(const Arg *arg);
static void tile(Monitor *); static void tile(Monitor *);
@ -241,6 +253,7 @@ static char stext[256];
static int screen; static int screen;
static int sw, sh; /* X display screen geometry width, height */ static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */ 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 lrpad; /* sum of left and right padding for text */
static int (*xerrorxlib)(Display *, XErrorEvent *); static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0; static unsigned int numlockmask = 0;
@ -393,8 +406,9 @@ arrange(Monitor *m)
} }
void void
arrangemon(Monitor *m) 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); strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
if (m->lt[m->sellt]->arrange) if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m); m->lt[m->sellt]->arrange(m);
@ -444,7 +458,24 @@ buttonpress(XEvent *e)
click = ClkStatusText; click = ClkStatusText;
else else
click = ClkWinTitle; 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); focus(c);
restack(selmon); restack(selmon);
XAllowEvents(dpy, ReplayPointer, CurrentTime); XAllowEvents(dpy, ReplayPointer, CurrentTime);
@ -452,8 +483,9 @@ buttonpress(XEvent *e)
} }
for (i = 0; i < LENGTH(buttons); i++) for (i = 0; i < LENGTH(buttons); i++)
if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button if (click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
&& CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state)) && 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 == ClkTabBar) && buttons[i].arg.i == 0) ? &arg : &buttons[i].arg);
}
} }
void void
@ -507,6 +539,8 @@ cleanupmon(Monitor *mon)
} }
XUnmapWindow(dpy, mon->barwin); XUnmapWindow(dpy, mon->barwin);
XDestroyWindow(dpy, mon->barwin); XDestroyWindow(dpy, mon->barwin);
XUnmapWindow(dpy, mon->tabwin);
XDestroyWindow(dpy, mon->tabwin);
free(mon); free(mon);
} }
@ -638,7 +672,10 @@ createmon(void)
m->mfact = mfact; m->mfact = mfact;
m->nmaster = nmaster; m->nmaster = nmaster;
m->showbar = showbar; m->showbar = showbar;
m->showtab = showtab;
m->topbar = topbar; m->topbar = topbar;
m->toptab = toptab;
m->ntabs = 0;
m->lt[0] = &layouts[0]; m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)]; m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
@ -752,6 +789,105 @@ drawbars(void)
drawbar(m); 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, scheme[(c == m->sel) ? SchemeSel : SchemeNorm]);
drw_text(drw, x, 0, w, th, 0, c->name, 0);
x += w;
++i;
}
drw_setscheme(drw, scheme[SchemeNorm]);
/* cleans interspace between window names and current viewed tag label */
w = m->ww - view_info_w - x;
drw_text(drw, x, 0, w, th, 0, "", 0);
/* view info */
x += w;
w = view_info_w;
drw_text(drw, x, 0, w, th, 0, view_info, 0);
drw_map(drw, m->tabwin, 0, 0, m->ww, th);
}
void void
enternotify(XEvent *e) enternotify(XEvent *e)
{ {
@ -777,8 +913,10 @@ expose(XEvent *e)
Monitor *m; Monitor *m;
XExposeEvent *ev = &e->xexpose; XExposeEvent *ev = &e->xexpose;
if (ev->count == 0 && (m = wintomon(ev->window))) if(ev->count == 0 && (m = wintomon(ev->window))){
drawbar(m); drawbar(m);
drawtab(m);
}
} }
void void
@ -804,6 +942,7 @@ focus(Client *c)
} }
selmon->sel = c; selmon->sel = c;
drawbars(); drawbars();
drawtabs();
} }
/* there are some broken focus acquiring clients needing extra handling */ /* there are some broken focus acquiring clients needing extra handling */
@ -828,6 +967,8 @@ focusmon(const Arg *arg)
unfocus(selmon->sel, 0); unfocus(selmon->sel, 0);
selmon = m; selmon = m;
focus(NULL); focus(NULL);
if (selmon->sel)
XWarpPointer(dpy, None, selmon->sel->win, 0, 0, 0, 0, selmon->sel->w/2, selmon->sel->h/2);
} }
void void
@ -853,6 +994,20 @@ focusstack(const Arg *arg)
if (c) { if (c) {
focus(c); focus(c);
restack(selmon); restack(selmon);
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
}
}
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);
} }
} }
@ -1234,12 +1389,14 @@ propertynotify(XEvent *e)
case XA_WM_HINTS: case XA_WM_HINTS:
updatewmhints(c); updatewmhints(c);
drawbars(); drawbars();
drawtabs();
break; break;
} }
if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { if (ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
updatetitle(c); updatetitle(c);
if (c == c->mon->sel) if (c == c->mon->sel)
drawbar(c->mon); drawbar(c->mon);
drawtab(c->mon);
} }
if (ev->atom == netatom[NetWMWindowType]) if (ev->atom == netatom[NetWMWindowType])
updatewindowtype(c); updatewindowtype(c);
@ -1277,36 +1434,13 @@ void
resizeclient(Client *c, int x, int y, int w, int h) resizeclient(Client *c, int x, int y, int w, int h)
{ {
XWindowChanges wc; XWindowChanges wc;
unsigned int n;
unsigned int gapoffset;
unsigned int gapincr;
Client *nbc;
c->oldx = c->x; c->x = wc.x = x;
c->oldy = c->y; c->y = wc.y = y;
c->oldw = c->w; c->w = wc.width = w;
c->oldh = c->h; c->h = wc.height = h;
wc.border_width = c->bw; wc.border_width = c->bw;
/* Get number of clients for the selected monitor */
for (n = 0, nbc = nexttiled(selmon->clients); nbc; nbc = nexttiled(nbc->next), n++);
/* Do nothing if layout is floating */
if (c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) {
gapincr = gapoffset = 0;
} else {
/* Remove border and gap if layout is monocle or only one client */
if (selmon->lt[selmon->sellt]->arrange == monocle || n == 1) {
gapoffset = 0;
gapincr = -2 * borderpx;
wc.border_width = 0;
} else {
gapoffset = gappx;
gapincr = 2 * gappx;
}
}
c->oldx = c->x; c->x = wc.x = x + gapoffset;
c->oldy = c->y; c->y = wc.y = y + gapoffset;
c->oldw = c->w; c->w = wc.width = w - gapincr;
c->oldh = c->h; c->h = wc.height = h - gapincr;
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc); XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
configure(c); configure(c);
XSync(dpy, False); XSync(dpy, False);
@ -1377,6 +1511,7 @@ restack(Monitor *m)
XWindowChanges wc; XWindowChanges wc;
drawbar(m); drawbar(m);
drawtab(m);
if (!m->sel) if (!m->sel)
return; return;
if (m->sel->isfloating || !m->lt[m->sellt]->arrange) if (m->sel->isfloating || !m->lt[m->sellt]->arrange)
@ -1571,6 +1706,7 @@ setup(void)
die("no fonts could be loaded."); die("no fonts could be loaded.");
lrpad = drw->fonts->h; lrpad = drw->fonts->h;
bh = drw->fonts->h + 2; bh = drw->fonts->h + 2;
th = bh;
updategeom(); updategeom();
/* init atoms */ /* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False); utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@ -1698,7 +1834,7 @@ tagmon(const Arg *arg)
void void
tile(Monitor *m) tile(Monitor *m)
{ {
unsigned int i, n, h, mw, my, ty; unsigned int i, n, h, r, g = 0, mw, my, ty;
Client *c; Client *c;
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++); for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
@ -1706,20 +1842,20 @@ tile(Monitor *m)
return; return;
if (n > m->nmaster) if (n > m->nmaster)
mw = m->nmaster ? m->ww * m->mfact : 0; mw = m->nmaster ? (m->ww - (g = gappx)) * m->mfact : 0;
else else
mw = m->ww; mw = m->ww;
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
if (i < m->nmaster) { if (i < m->nmaster) {
h = (m->wh - my) / (MIN(n, m->nmaster) - i); r = MIN(n, m->nmaster) - i;
h = (m->wh - my - gappx * (r - 1)) / r;
resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0); resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
if (my + HEIGHT(c) < m->wh) my += HEIGHT(c) + gappx;
my += HEIGHT(c);
} else { } else {
h = (m->wh - ty) / (n - i); r = n - i;
resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), 0); h = (m->wh - ty - gappx * (r - 1)) / r;
if (ty + HEIGHT(c) < m->wh) resize(c, m->wx + mw + g, m->wy + ty, m->ww - mw - g - (2*c->bw), h - (2*c->bw), False);
ty += HEIGHT(c); ty += HEIGHT(c) + gappx;
} }
} }
@ -1732,6 +1868,17 @@ togglebar(const Arg *arg)
arrange(selmon); 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 void
togglefloating(const Arg *arg) togglefloating(const Arg *arg)
{ {
@ -1843,6 +1990,11 @@ updatebars(void)
CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor); XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
XMapRaised(dpy, m->barwin); 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); XSetClassHint(dpy, m->barwin, &ch);
} }
} }
@ -1850,14 +2002,33 @@ updatebars(void)
void void
updatebarpos(Monitor *m) updatebarpos(Monitor *m)
{ {
Client *c;
int nvis = 0;
m->wy = m->my; m->wy = m->my;
m->wh = m->mh; m->wh = m->mh;
if (m->showbar) { if (m->showbar) {
m->wh -= bh; m->wh -= bh;
m->by = m->topbar ? m->wy : m->wy + m->wh; m->by = m->topbar ? m->wy : m->wy + m->wh;
m->wy = m->topbar ? m->wy + bh : m->wy; if ( m->topbar )
} else m->wy += bh;
} else {
m->by = -bh; 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 void
@ -2094,7 +2265,7 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y)) if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1); return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next) for (m = mons; m; m = m->next)
if (w == m->barwin) if (w == m->barwin || w == m->tabwin)
return m; return m;
if ((c = wintoclient(w))) if ((c = wintoclient(w)))
return c->mon; return c->mon;