|
|
@@ -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; |
|
|
|