|
@ -118,11 +118,17 @@ typedef struct { |
|
|
const Arg arg; |
|
|
const Arg arg; |
|
|
} Key; |
|
|
} Key; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
|
|
const char * sig; |
|
|
|
|
|
void (*func)(const Arg *); |
|
|
|
|
|
} Signal; |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
typedef struct { |
|
|
const char *symbol; |
|
|
const char *symbol; |
|
|
void (*arrange)(Monitor *); |
|
|
void (*arrange)(Monitor *); |
|
|
} Layout; |
|
|
} Layout; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct Pertag Pertag; |
|
|
struct Monitor { |
|
|
struct Monitor { |
|
|
char ltsymbol[16]; |
|
|
char ltsymbol[16]; |
|
|
float mfact; |
|
|
float mfact; |
|
@ -147,6 +153,7 @@ struct Monitor { |
|
|
Monitor *next; |
|
|
Monitor *next; |
|
|
Window barwin; |
|
|
Window barwin; |
|
|
const Layout *lt[2]; |
|
|
const Layout *lt[2]; |
|
|
|
|
|
Pertag *pertag; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
typedef struct { |
|
|
typedef struct { |
|
@ -169,6 +176,7 @@ static void arrangemon(Monitor *m); |
|
|
static void attach(Client *c); |
|
|
static void attach(Client *c); |
|
|
static void attachaside(Client *c); |
|
|
static void attachaside(Client *c); |
|
|
static void attachstack(Client *c); |
|
|
static void attachstack(Client *c); |
|
|
|
|
|
static int fake_signal(void); |
|
|
static void buttonpress(XEvent *e); |
|
|
static void buttonpress(XEvent *e); |
|
|
static void checkotherwm(void); |
|
|
static void checkotherwm(void); |
|
|
static void cleanup(void); |
|
|
static void cleanup(void); |
|
@ -326,6 +334,15 @@ static xcb_connection_t *xcon; |
|
|
#include "keybinds.h" |
|
|
#include "keybinds.h" |
|
|
#include "rules.h" |
|
|
#include "rules.h" |
|
|
|
|
|
|
|
|
|
|
|
struct Pertag { |
|
|
|
|
|
unsigned int curtag, prevtag; /* current and previous tag */ |
|
|
|
|
|
int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ |
|
|
|
|
|
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ |
|
|
|
|
|
unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */ |
|
|
|
|
|
const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */ |
|
|
|
|
|
int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */ |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
/* compile-time check if all tags fit into an unsigned int bit array. */ |
|
|
/* compile-time check if all tags fit into an unsigned int bit array. */ |
|
|
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; |
|
|
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; |
|
|
|
|
|
|
|
@ -555,15 +572,16 @@ buttonpress(XEvent *e) |
|
|
unsigned int xc; |
|
|
unsigned int xc; |
|
|
int padding = - sp * 3; /* I don't know why 3 works better than two, but it does */ |
|
|
int padding = - sp * 3; /* I don't know why 3 works better than two, but it does */ |
|
|
Arg arg = {0}; |
|
|
Arg arg = {0}; |
|
|
Client *c; |
|
|
|
|
|
|
|
|
Client *c, *sel; |
|
|
Monitor *m; |
|
|
Monitor *m; |
|
|
XButtonPressedEvent *ev = &e->xbutton; |
|
|
XButtonPressedEvent *ev = &e->xbutton; |
|
|
|
|
|
|
|
|
click = ClkRootWin; |
|
|
click = ClkRootWin; |
|
|
/* focus monitor if necessary */ |
|
|
/* focus monitor if necessary */ |
|
|
if ((m = wintomon(ev->window)) && m != selmon) { |
|
|
if ((m = wintomon(ev->window)) && m != selmon) { |
|
|
unfocus(selmon->sel, 1); |
|
|
|
|
|
|
|
|
sel = selmon->sel; |
|
|
selmon = m; |
|
|
selmon = m; |
|
|
|
|
|
unfocus(sel, 1); |
|
|
focus(NULL); |
|
|
focus(NULL); |
|
|
} |
|
|
} |
|
|
if (ev->window == selmon->barwin) { |
|
|
if (ev->window == selmon->barwin) { |
|
@ -842,6 +860,7 @@ Monitor * |
|
|
createmon(void) |
|
|
createmon(void) |
|
|
{ |
|
|
{ |
|
|
Monitor *m; |
|
|
Monitor *m; |
|
|
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
|
m = ecalloc(1, sizeof(Monitor)); |
|
|
m = ecalloc(1, sizeof(Monitor)); |
|
|
m->tagset[0] = m->tagset[1] = 1; |
|
|
m->tagset[0] = m->tagset[1] = 1; |
|
@ -856,6 +875,20 @@ createmon(void) |
|
|
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); |
|
|
|
|
|
m->pertag = ecalloc(1, sizeof(Pertag)); |
|
|
|
|
|
m->pertag->curtag = m->pertag->prevtag = 1; |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i <= LENGTH(tags); i++) { |
|
|
|
|
|
m->pertag->nmasters[i] = m->nmaster; |
|
|
|
|
|
m->pertag->mfacts[i] = m->mfact; |
|
|
|
|
|
|
|
|
|
|
|
m->pertag->ltidxs[i][0] = m->lt[0]; |
|
|
|
|
|
m->pertag->ltidxs[i][1] = m->lt[1]; |
|
|
|
|
|
m->pertag->sellts[i] = m->sellt; |
|
|
|
|
|
|
|
|
|
|
|
m->pertag->showbars[i] = m->showbar; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return m; |
|
|
return m; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1164,7 +1197,7 @@ floatpos(const Arg *arg) |
|
|
void |
|
|
void |
|
|
enternotify(XEvent *e) |
|
|
enternotify(XEvent *e) |
|
|
{ |
|
|
{ |
|
|
Client *c; |
|
|
|
|
|
|
|
|
Client *c, *sel; |
|
|
Monitor *m; |
|
|
Monitor *m; |
|
|
XCrossingEvent *ev = &e->xcrossing; |
|
|
XCrossingEvent *ev = &e->xcrossing; |
|
|
|
|
|
|
|
@ -1173,8 +1206,9 @@ enternotify(XEvent *e) |
|
|
c = wintoclient(ev->window); |
|
|
c = wintoclient(ev->window); |
|
|
m = c ? c->mon : wintomon(ev->window); |
|
|
m = c ? c->mon : wintomon(ev->window); |
|
|
if (m != selmon) { |
|
|
if (m != selmon) { |
|
|
unfocus(selmon->sel, 1); |
|
|
|
|
|
|
|
|
sel = selmon->sel; |
|
|
selmon = m; |
|
|
selmon = m; |
|
|
|
|
|
unfocus(sel, 1); |
|
|
} else if (!c || c == selmon->sel) |
|
|
} else if (!c || c == selmon->sel) |
|
|
return; |
|
|
return; |
|
|
focus(c); |
|
|
focus(c); |
|
@ -1229,13 +1263,15 @@ void |
|
|
focusmon(const Arg *arg) |
|
|
focusmon(const Arg *arg) |
|
|
{ |
|
|
{ |
|
|
Monitor *m; |
|
|
Monitor *m; |
|
|
|
|
|
Client *sel; |
|
|
|
|
|
|
|
|
if (!mons->next) |
|
|
if (!mons->next) |
|
|
return; |
|
|
return; |
|
|
if ((m = dirtomon(arg->i)) == selmon) |
|
|
if ((m = dirtomon(arg->i)) == selmon) |
|
|
return; |
|
|
return; |
|
|
unfocus(selmon->sel, 0); |
|
|
|
|
|
|
|
|
sel = selmon->sel; |
|
|
selmon = m; |
|
|
selmon = m; |
|
|
|
|
|
unfocus(sel, 0); |
|
|
focus(NULL); |
|
|
focus(NULL); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1504,7 +1540,7 @@ grabkeys(void) |
|
|
void |
|
|
void |
|
|
incnmaster(const Arg *arg) |
|
|
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); |
|
|
arrange(selmon); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1536,6 +1572,49 @@ keypress(XEvent *e) |
|
|
keys[i].func(&(keys[i].arg)); |
|
|
keys[i].func(&(keys[i].arg)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int |
|
|
|
|
|
fake_signal(void) |
|
|
|
|
|
{ |
|
|
|
|
|
char fsignal[256]; |
|
|
|
|
|
char indicator[9] = "fsignal:"; |
|
|
|
|
|
char str_sig[50]; |
|
|
|
|
|
char param[16]; |
|
|
|
|
|
int i, len_str_sig, n, paramn; |
|
|
|
|
|
size_t len_fsignal, len_indicator = strlen(indicator); |
|
|
|
|
|
Arg arg; |
|
|
|
|
|
|
|
|
|
|
|
// Get root name property |
|
|
|
|
|
if (gettextprop(root, XA_WM_NAME, fsignal, sizeof(fsignal))) { |
|
|
|
|
|
len_fsignal = strlen(fsignal); |
|
|
|
|
|
|
|
|
|
|
|
// Check if this is indeed a fake signal |
|
|
|
|
|
if (len_indicator > len_fsignal ? 0 : strncmp(indicator, fsignal, len_indicator) == 0) { |
|
|
|
|
|
paramn = sscanf(fsignal+len_indicator, "%s%n%s%n", str_sig, &len_str_sig, param, &n); |
|
|
|
|
|
|
|
|
|
|
|
if (paramn == 1) arg = (Arg) {0}; |
|
|
|
|
|
else if (paramn > 2) return 1; |
|
|
|
|
|
else if (strncmp(param, "i", n - len_str_sig) == 0) |
|
|
|
|
|
sscanf(fsignal + len_indicator + n, "%i", &(arg.i)); |
|
|
|
|
|
else if (strncmp(param, "ui", n - len_str_sig) == 0) |
|
|
|
|
|
sscanf(fsignal + len_indicator + n, "%u", &(arg.ui)); |
|
|
|
|
|
else if (strncmp(param, "f", n - len_str_sig) == 0) |
|
|
|
|
|
sscanf(fsignal + len_indicator + n, "%f", &(arg.f)); |
|
|
|
|
|
else return 1; |
|
|
|
|
|
|
|
|
|
|
|
// Check if a signal was found, and if so handle it |
|
|
|
|
|
for (i = 0; i < LENGTH(signals); i++) |
|
|
|
|
|
if (strncmp(str_sig, signals[i].sig, len_str_sig) == 0 && signals[i].func) |
|
|
|
|
|
signals[i].func(&(arg)); |
|
|
|
|
|
|
|
|
|
|
|
// A fake signal was sent |
|
|
|
|
|
return 1; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// No fake signal was sent, so proceed with update |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void |
|
|
void |
|
|
killclient(const Arg *arg) |
|
|
killclient(const Arg *arg) |
|
|
{ |
|
|
{ |
|
@ -1666,13 +1745,15 @@ motionnotify(XEvent *e) |
|
|
{ |
|
|
{ |
|
|
static Monitor *mon = NULL; |
|
|
static Monitor *mon = NULL; |
|
|
Monitor *m; |
|
|
Monitor *m; |
|
|
|
|
|
Client *sel; |
|
|
XMotionEvent *ev = &e->xmotion; |
|
|
XMotionEvent *ev = &e->xmotion; |
|
|
|
|
|
|
|
|
if (ev->window != root) |
|
|
if (ev->window != root) |
|
|
return; |
|
|
return; |
|
|
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { |
|
|
if ((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) { |
|
|
unfocus(selmon->sel, 1); |
|
|
|
|
|
|
|
|
sel = selmon->sel; |
|
|
selmon = m; |
|
|
selmon = m; |
|
|
|
|
|
unfocus(sel, 1); |
|
|
focus(NULL); |
|
|
focus(NULL); |
|
|
} |
|
|
} |
|
|
mon = m; |
|
|
mon = m; |
|
@ -1771,8 +1852,10 @@ propertynotify(XEvent *e) |
|
|
Window trans; |
|
|
Window trans; |
|
|
XPropertyEvent *ev = &e->xproperty; |
|
|
XPropertyEvent *ev = &e->xproperty; |
|
|
|
|
|
|
|
|
if ((ev->window == root) && (ev->atom == XA_WM_NAME)) |
|
|
|
|
|
updatestatus(); |
|
|
|
|
|
|
|
|
if ((ev->window == root) && (ev->atom == XA_WM_NAME)) { |
|
|
|
|
|
if (!fake_signal()) |
|
|
|
|
|
updatestatus(); |
|
|
|
|
|
} |
|
|
else if (ev->state == PropertyDelete) |
|
|
else if (ev->state == PropertyDelete) |
|
|
return; /* ignore */ |
|
|
return; /* ignore */ |
|
|
else if ((c = wintoclient(ev->window))) { |
|
|
else if ((c = wintoclient(ev->window))) { |
|
@ -2101,9 +2184,9 @@ void |
|
|
setlayout(const Arg *arg) |
|
|
setlayout(const Arg *arg) |
|
|
{ |
|
|
{ |
|
|
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
|
|
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]) |
|
|
selmon->sellt ^= 1; |
|
|
|
|
|
|
|
|
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1; |
|
|
if (arg && arg->v) |
|
|
if (arg && arg->v) |
|
|
selmon->lt[selmon->sellt] = (Layout *)arg->v; |
|
|
|
|
|
|
|
|
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v; |
|
|
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); |
|
|
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol); |
|
|
if (selmon->sel) |
|
|
if (selmon->sel) |
|
|
arrange(selmon); |
|
|
arrange(selmon); |
|
@ -2122,7 +2205,7 @@ setmfact(const Arg *arg) |
|
|
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; |
|
|
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0; |
|
|
if (f < 0.05 || f > 0.95) |
|
|
if (f < 0.05 || f > 0.95) |
|
|
return; |
|
|
return; |
|
|
selmon->mfact = f; |
|
|
|
|
|
|
|
|
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f; |
|
|
arrange(selmon); |
|
|
arrange(selmon); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -2319,7 +2402,7 @@ tagmon(const Arg *arg) |
|
|
void |
|
|
void |
|
|
togglebar(const Arg *arg) |
|
|
togglebar(const Arg *arg) |
|
|
{ |
|
|
{ |
|
|
selmon->showbar = !selmon->showbar; |
|
|
|
|
|
|
|
|
selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar; |
|
|
updatebarpos(selmon); |
|
|
updatebarpos(selmon); |
|
|
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh); |
|
|
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx + sp, selmon->by + vp, selmon->ww - 2 * sp, bh); |
|
|
arrange(selmon); |
|
|
arrange(selmon); |
|
@ -2384,9 +2467,33 @@ void |
|
|
toggleview(const Arg *arg) |
|
|
toggleview(const Arg *arg) |
|
|
{ |
|
|
{ |
|
|
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); |
|
|
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK); |
|
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
if (newtagset) { |
|
|
if (newtagset) { |
|
|
selmon->tagset[selmon->seltags] = newtagset; |
|
|
selmon->tagset[selmon->seltags] = newtagset; |
|
|
|
|
|
|
|
|
|
|
|
if (newtagset == ~0) { |
|
|
|
|
|
selmon->pertag->prevtag = selmon->pertag->curtag; |
|
|
|
|
|
selmon->pertag->curtag = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* test if the user did not select the same tag */ |
|
|
|
|
|
if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) { |
|
|
|
|
|
selmon->pertag->prevtag = selmon->pertag->curtag; |
|
|
|
|
|
for (i = 0; !(newtagset & 1 << i); i++) ; |
|
|
|
|
|
selmon->pertag->curtag = i + 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* apply settings for this view */ |
|
|
|
|
|
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; |
|
|
|
|
|
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; |
|
|
|
|
|
|
|
|
|
|
|
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) |
|
|
|
|
|
togglebar(NULL); |
|
|
|
|
|
|
|
|
focus(NULL); |
|
|
focus(NULL); |
|
|
arrange(selmon); |
|
|
arrange(selmon); |
|
|
} |
|
|
} |
|
@ -2397,6 +2504,8 @@ unfocus(Client *c, int setfocus) |
|
|
{ |
|
|
{ |
|
|
if (!c) |
|
|
if (!c) |
|
|
return; |
|
|
return; |
|
|
|
|
|
if (c->isfullscreen && ISVISIBLE(c) && c->mon == selmon) |
|
|
|
|
|
setfullscreen(c, 0); |
|
|
grabbuttons(c, 0); |
|
|
grabbuttons(c, 0); |
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); |
|
|
XSetWindowBorder(dpy, c->win, scheme[SchemeNorm][ColBorder].pixel); |
|
|
if (setfocus) { |
|
|
if (setfocus) { |
|
@ -2700,11 +2809,37 @@ updatewmhints(Client *c) |
|
|
void |
|
|
void |
|
|
view(const Arg *arg) |
|
|
view(const Arg *arg) |
|
|
{ |
|
|
{ |
|
|
|
|
|
int i; |
|
|
|
|
|
unsigned int tmptag; |
|
|
|
|
|
|
|
|
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) |
|
|
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) |
|
|
return; |
|
|
return; |
|
|
selmon->seltags ^= 1; /* toggle sel tagset */ |
|
|
selmon->seltags ^= 1; /* toggle sel tagset */ |
|
|
if (arg->ui & TAGMASK) |
|
|
|
|
|
|
|
|
if (arg->ui & TAGMASK) { |
|
|
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
|
|
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
|
|
|
|
|
selmon->pertag->prevtag = selmon->pertag->curtag; |
|
|
|
|
|
|
|
|
|
|
|
if (arg->ui == ~0) |
|
|
|
|
|
selmon->pertag->curtag = 0; |
|
|
|
|
|
else { |
|
|
|
|
|
for (i = 0; !(arg->ui & 1 << i); i++) ; |
|
|
|
|
|
selmon->pertag->curtag = i + 1; |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
tmptag = selmon->pertag->prevtag; |
|
|
|
|
|
selmon->pertag->prevtag = selmon->pertag->curtag; |
|
|
|
|
|
selmon->pertag->curtag = tmptag; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag]; |
|
|
|
|
|
selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt]; |
|
|
|
|
|
selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1]; |
|
|
|
|
|
|
|
|
|
|
|
if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag]) |
|
|
|
|
|
togglebar(NULL); |
|
|
|
|
|
|
|
|
focus(NULL); |
|
|
focus(NULL); |
|
|
arrange(selmon); |
|
|
arrange(selmon); |
|
|
} |
|
|
} |
|
|