unsigned int border, oldborder;
Bool isbanned, isfixed, isfloating, isurgent;
Bool *tags;
- View *view;
Client *next;
Client *prev;
Client *snext;
};
/* function declarations */
-void addtag(Client *c, const char *t);
void applyrules(Client *c);
void arrange(void);
void attach(Client *c);
void configure(Client *c);
void configurenotify(XEvent *e);
void configurerequest(XEvent *e);
+Bool conflicts(Client *c, unsigned int tidx);
void destroynotify(XEvent *e);
void detach(Client *c);
void detachstack(Client *c);
void enternotify(XEvent *e);
void eprint(const char *errstr, ...);
void expose(XEvent *e);
+unsigned int firstag(View *v);
void floating(View *v); /* default floating layout */
void focus(Client *c);
void focusin(XEvent *e);
void focusprev(const char *arg);
Client *getclient(Window w);
unsigned long getcolor(const char *colstr);
+View *getview(Client *c);
View *getviewbar(Window barwin);
long getstate(Window w);
Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
[UnmapNotify] = unmapnotify
};
Atom wmatom[WMLast], netatom[NetLast];
-Bool isxinerama = False;
Bool domwfact = True;
Bool dozoom = True;
Bool otherwm, readin;
/* configuration, allows nested code to access above variables */
#include "config.h"
+#define TAGSZ (LENGTH(tags) * sizeof(Bool))
/* function implementations */
-void
-addtag(Client *c, const char *t) {
- unsigned int i, tidx = idxoftag(t);
-
- for(i = 0; i < LENGTH(tags); i++)
- if(c->tags[i] && vtags[i] != vtags[tidx])
- return; /* conflict */
- c->tags[tidx] = True;
- c->view = &views[vtags[tidx]];
-}
void
applyrules(Client *c) {
- unsigned int i;
+ unsigned int i, idx;
Bool matched = False;
Rule *r;
XClassHint ch = { 0 };
|| (ch.res_name && strstr(ch.res_name, r->prop)))
{
c->isfloating = r->isfloating;
- if(r->tag) {
- addtag(c, r->tag);
+ if(r->tag && !conflicts(c, (idx = idxoftag(r->tag)))) {
+ c->tags[idx] = True;
matched = True;
}
}
if(ch.res_name)
XFree(ch.res_name);
if(!matched) {
- memcpy(c->tags, seltags, sizeof initags);
- c->view = selview;
+ for(i = 0; i < LENGTH(tags); i++)
+ if(seltags[i] && vtags[i] == selview->id)
+ c->tags[i] = True;
}
}
ban(Client *c) {
if(c->isbanned)
return;
- XMoveWindow(dpy, c->win, c->x + 3 * c->view->w, c->y);
+ XMoveWindow(dpy, c->win, c->x + 3 * getview(c)->w, c->y);
c->isbanned = True;
}
if(CLEANMASK(ev->state) != MODKEY)
return;
if(ev->button == Button1) {
- restack(c->view);
+ restack(getview(c));
movemouse(c);
}
else if(ev->button == Button2) {
- if((floating != c->view->layout->arrange) && c->isfloating)
+ if((floating != getview(c)->layout->arrange) && c->isfloating)
togglefloating(NULL);
else
zoom(NULL);
}
else if(ev->button == Button3 && !c->isfixed) {
- restack(c->view);
+ restack(getview(c));
resizemouse(c);
}
}
XWindowChanges wc;
if((c = getclient(ev->window))) {
- View *v = c->view;
+ View *v = getview(c);
if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width;
if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) {
XSync(dpy, False);
}
+Bool
+conflicts(Client *c, unsigned int tidx) {
+ unsigned int i;
+
+ for(i = 0; i < LENGTH(tags); i++)
+ if(c->tags[i] && vtags[i] != vtags[tidx])
+ return True; /* conflict */
+ return False;
+}
+
void
destroynotify(XEvent *e) {
Client *c;
Client *c;
dc.x = 0;
- for(c = stack; c && (!isvisible(c) || c->view != v); c = c->snext);
+ for(c = stack; c && (!isvisible(c) || getview(c) != v); c = c->snext);
for(i = 0; i < LENGTH(tags); i++) {
if(&views[vtags[i]] != v)
continue;
Client *c;
XCrossingEvent *ev = &e->xcrossing;
- if(ev->mode != NotifyNormal || ev->detail == NotifyInferior) {
- if(!isxinerama || ev->window != root)
- return;
- }
+ if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
+ return;
if((c = getclient(ev->window)))
focus(c);
else
drawbar(v);
}
+unsigned int
+firstag(View *v) {
+ unsigned int i;
+
+ for(i = 0; i < LENGTH(tags); i++)
+ if(vtags[i] == v->id)
+ return i;
+ return 0; /* safe fallback */
+}
+
void
floating(View *v) { /* default floating layout */
Client *c;
focus(Client *c) {
View *v = selview;
if(c)
- selview = c->view;
- else
- selview = viewat();
+ selview = getview(c);
if(selview != v)
drawbar(v);
if(!c || (c && !isvisible(c)))
- for(c = stack; c && (!isvisible(c) || c->view != selview); c = c->snext);
+ /* TODO: isvisible might take getview(c) as constraint? */
+ for(c = stack; c && (!isvisible(c) || getview(c) != selview); c = c->snext);
if(sel && sel != c) {
grabbuttons(sel, False);
XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
if(c) {
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
- selview = c->view;
+ selview = getview(c);
}
else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
for(c = clients; c && !isvisible(c); c = c->next);
if(c) {
focus(c);
- restack(c->view);
+ restack(getview(c));
}
}
}
if(c) {
focus(c);
- restack(c->view);
+ restack(getview(c));
}
}
return color.pixel;
}
+View *
+getview(Client *c) {
+ unsigned int i;
+
+ for(i = 0; i < LENGTH(tags); i++)
+ if(c->tags[i])
+ return &views[vtags[i]];
+ return NULL;
+}
+
View *
getviewbar(Window barwin) {
unsigned int i;
unsigned int i;
for(i = 0; (i < LENGTH(tags)) && (tags[i] != t); i++);
- return (i < LENGTH(tags)) ? i : 0;
+ return (i < LENGTH(tags)) ? i : firstag(selview);
}
void
XWindowChanges wc;
c = emallocz(sizeof(Client));
- c->tags = emallocz(sizeof initags);
+ c->tags = emallocz(TAGSZ);
c->win = w;
applyrules(c);
- v = c->view;
+ v = getview(c);
c->x = wa->x + v->x;
c->y = wa->y + v->y;
if((rettrans = XGetTransientForHint(dpy, w, &trans) == Success))
for(t = clients; t && t->win != trans; t = t->next);
if(t)
- memcpy(c->tags, t->tags, sizeof initags);
+ memcpy(c->tags, t->tags, TAGSZ);
if(!c->isfloating)
c->isfloating = (rettrans == Success) || c->isfixed;
attach(c);
ocx = nx = c->x;
ocy = ny = c->y;
- v = c->view;
+ v = getview(c);
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess)
return;
Client *
nexttiled(Client *c, View *v) {
- for(; c && (c->isfloating || c->view != v || !isvisible(c)); c = c->next);
+ for(; c && (c->isfloating || getview(c) != v || !isvisible(c)); c = c->next);
return c;
}
break;
case XA_WM_HINTS:
updatewmhints(c);
- drawbar(c->view);
+ drawbar(getview(c));
break;
}
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
View *v;
XWindowChanges wc;
- v = c->view;
+ v = getview(c);
if(sizehints) {
/* set minimum possible */
if (w < 1)
ocx = c->x;
ocy = c->y;
- v = c->view;
+ v = getview(c);
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess)
return;
void
setup(void) {
- unsigned int i;
+ unsigned int i, j;
View *v;
XSetWindowAttributes wa;
XineramaScreenInfo *info = NULL;
cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
- if((isxinerama = XineramaIsActive(dpy)))
+ if(XineramaIsActive(dpy))
info = XineramaQueryScreens(dpy, &nviews);
+
#if defined(AIM_XINERAMA)
-isxinerama = True;
nviews = 2; /* aim Xinerama */
#endif
views = emallocz(nviews * sizeof(View));
blw = i;
}
- seltags = emallocz(sizeof initags);
- prevtags = emallocz(sizeof initags);
- memcpy(seltags, initags, sizeof initags);
- memcpy(prevtags, initags, sizeof initags);
+ seltags = emallocz(TAGSZ);
+ prevtags = emallocz(TAGSZ);
+
+ /* check, if vtags need assistance, because there is only 1 view */
+ if(nviews == 1)
+ for(i = 0; i < LENGTH(tags); i++)
+ vtags[i] = 0;
for(i = 0; i < nviews; i++) {
/* init geometry */
v = &views[i];
+ v->id = i;
+
+ /* select first tag of view */
+ j = firstag(v);
+ seltags[j] = prevtags[j] = True;
- if(nviews != 1 && isxinerama) {
+ if(info) {
#if defined(AIM_XINERAMA)
v->w = DisplayWidth(dpy, screen) / 2;
if(!sel)
return;
for(i = 0; i < LENGTH(tags); i++)
- sel->tags[i] = (NULL == arg);
- sel->tags[idxoftag(arg)] = True;
+ sel->tags[i] = (NULL == arg) && (vtags[i] == getview(sel)->id);
+ i = idxoftag(arg);
+ if(!conflicts(sel, i))
+ sel->tags[idxoftag(arg)] = True;
arrange();
}
for(i = 0, c = mc = nexttiled(clients, v); c; c = nexttiled(c->next, v)) {
if(i == 0) { /* master */
- nx = v->wax;
- ny = v->way;
nw = mw - 2 * c->border;
nh = v->wah - 2 * c->border;
}
if(!sel)
return;
i = idxoftag(arg);
+ if(conflicts(sel, i))
+ return;
sel->tags[i] = !sel->tags[i];
for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
if(j == LENGTH(tags))
void
view(const char *arg) {
- unsigned int i;
+ unsigned int i, j;
Bool tmp[LENGTH(tags)];
- for(i = 0; i < LENGTH(tags); i++)
- tmp[i] = (NULL == arg);
- tmp[idxoftag(arg)] = True;
-
- if(memcmp(seltags, tmp, sizeof initags) != 0) {
- memcpy(prevtags, seltags, sizeof initags);
- memcpy(seltags, tmp, sizeof initags);
+ memcpy(tmp, seltags, TAGSZ);
+ if(arg == NULL) {
+ for(i = 0; i < LENGTH(tags); i++)
+ tmp[i] = (vtags[i] == selview->id);
+ }
+ else {
+ i = idxoftag(arg);
+ for(j = 0; j < LENGTH(tags); j++)
+ if(selview->id == vtags[i]) {
+ /* view tag of selview */
+ if(selview->id == vtags[j])
+ tmp[j] = False;
+ }
+ else {
+ /* only touch the view the focus should go */
+ if(vtags[j] == vtags[i])
+ tmp[j] = False;
+ }
+ selview = &views[vtags[i]];
+ tmp[i] = True;
+ }
+ if(memcmp(seltags, tmp, TAGSZ) != 0) {
+ memcpy(prevtags, seltags, TAGSZ);
+ memcpy(seltags, tmp, TAGSZ);
arrange();
}
}
viewprevtag(const char *arg) {
static Bool tmp[LENGTH(tags)];
- memcpy(tmp, seltags, sizeof initags);
- memcpy(seltags, prevtags, sizeof initags);
- memcpy(prevtags, tmp, sizeof initags);
+ memcpy(tmp, seltags, TAGSZ);
+ memcpy(seltags, prevtags, TAGSZ);
+ memcpy(prevtags, tmp, TAGSZ);
arrange();
}
if(!sel || !dozoom || sel->isfloating)
return;
- if(c == nexttiled(clients, c->view))
- if(!(c = nexttiled(c->next, c->view)))
+ if(c == nexttiled(clients, getview(c)))
+ if(!(c = nexttiled(c->next, getview(c))))
return;
detach(c);
attach(c);