made the basics of the tagging concept working -- if people want dynamic tags, that's even possible with this concept, the vtags[] array needs to be modified during runtime for this -- the new code is quite experimental, ugly and needs polishing

This commit is contained in:
anselm@anselm1 2008-02-28 21:38:53 +00:00
parent f1719ac2de
commit 7bc272a4e4
2 changed files with 93 additions and 54 deletions

View file

@ -17,7 +17,7 @@ LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXinerama
# flags # flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
LDFLAGS = -s ${LIBS} LDFLAGS = -s ${LIBS}
CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" CFLAGS = -g -std=c99 -pedantic -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\" -DAIM_XINERAMA
LDFLAGS = -g ${LIBS} LDFLAGS = -g ${LIBS}
# Solaris # Solaris

145
dwm.c
View file

@ -71,7 +71,6 @@ struct Client {
unsigned int border, oldborder; unsigned int border, oldborder;
Bool isbanned, isfixed, isfloating, isurgent; Bool isbanned, isfixed, isfloating, isurgent;
Bool *tags; Bool *tags;
View *view;
Client *next; Client *next;
Client *prev; Client *prev;
Client *snext; Client *snext;
@ -120,7 +119,6 @@ struct View {
}; };
/* function declarations */ /* function declarations */
void addtag(Client *c, const char *t);
void applyrules(Client *c); void applyrules(Client *c);
void arrange(void); void arrange(void);
void attach(Client *c); void attach(Client *c);
@ -132,6 +130,7 @@ void cleanup(void);
void configure(Client *c); void configure(Client *c);
void configurenotify(XEvent *e); void configurenotify(XEvent *e);
void configurerequest(XEvent *e); void configurerequest(XEvent *e);
Bool conflicts(Client *c, unsigned int tidx);
void destroynotify(XEvent *e); void destroynotify(XEvent *e);
void detach(Client *c); void detach(Client *c);
void detachstack(Client *c); void detachstack(Client *c);
@ -142,6 +141,7 @@ void *emallocz(unsigned int size);
void enternotify(XEvent *e); void enternotify(XEvent *e);
void eprint(const char *errstr, ...); void eprint(const char *errstr, ...);
void expose(XEvent *e); void expose(XEvent *e);
unsigned int firstag(View *v);
void floating(View *v); /* default floating layout */ void floating(View *v); /* default floating layout */
void focus(Client *c); void focus(Client *c);
void focusin(XEvent *e); void focusin(XEvent *e);
@ -149,6 +149,7 @@ void focusnext(const char *arg);
void focusprev(const char *arg); void focusprev(const char *arg);
Client *getclient(Window w); Client *getclient(Window w);
unsigned long getcolor(const char *colstr); unsigned long getcolor(const char *colstr);
View *getview(Client *c);
View *getviewbar(Window barwin); View *getviewbar(Window barwin);
long getstate(Window w); long getstate(Window w);
Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
@ -248,20 +249,10 @@ Window root;
#define TAGSZ (LENGTH(tags) * sizeof(Bool)) #define TAGSZ (LENGTH(tags) * sizeof(Bool))
/* function implementations */ /* 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 void
applyrules(Client *c) { applyrules(Client *c) {
unsigned int i; unsigned int i, idx;
Bool matched = False; Bool matched = False;
Rule *r; Rule *r;
XClassHint ch = { 0 }; XClassHint ch = { 0 };
@ -275,8 +266,8 @@ applyrules(Client *c) {
|| (ch.res_name && strstr(ch.res_name, r->prop))) || (ch.res_name && strstr(ch.res_name, r->prop)))
{ {
c->isfloating = r->isfloating; c->isfloating = r->isfloating;
if(r->tag) { if(r->tag && !conflicts(c, (idx = idxoftag(r->tag)))) {
addtag(c, r->tag); c->tags[idx] = True;
matched = True; matched = True;
} }
} }
@ -286,8 +277,9 @@ applyrules(Client *c) {
if(ch.res_name) if(ch.res_name)
XFree(ch.res_name); XFree(ch.res_name);
if(!matched) { if(!matched) {
memcpy(c->tags, seltags, TAGSZ); for(i = 0; i < LENGTH(tags); i++)
c->view = selview; if(seltags[i] && vtags[i] == selview->id)
c->tags[i] = True;
} }
} }
@ -327,7 +319,7 @@ void
ban(Client *c) { ban(Client *c) {
if(c->isbanned) if(c->isbanned)
return; 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; c->isbanned = True;
} }
@ -367,17 +359,17 @@ buttonpress(XEvent *e) {
if(CLEANMASK(ev->state) != MODKEY) if(CLEANMASK(ev->state) != MODKEY)
return; return;
if(ev->button == Button1) { if(ev->button == Button1) {
restack(c->view); restack(getview(c));
movemouse(c); movemouse(c);
} }
else if(ev->button == Button2) { else if(ev->button == Button2) {
if((floating != c->view->layout->arrange) && c->isfloating) if((floating != getview(c)->layout->arrange) && c->isfloating)
togglefloating(NULL); togglefloating(NULL);
else else
zoom(NULL); zoom(NULL);
} }
else if(ev->button == Button3 && !c->isfixed) { else if(ev->button == Button3 && !c->isfixed) {
restack(c->view); restack(getview(c));
resizemouse(c); resizemouse(c);
} }
} }
@ -466,7 +458,7 @@ configurerequest(XEvent *e) {
XWindowChanges wc; XWindowChanges wc;
if((c = getclient(ev->window))) { if((c = getclient(ev->window))) {
View *v = c->view; View *v = getview(c);
if(ev->value_mask & CWBorderWidth) if(ev->value_mask & CWBorderWidth)
c->border = ev->border_width; c->border = ev->border_width;
if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) { if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) {
@ -504,6 +496,16 @@ configurerequest(XEvent *e) {
XSync(dpy, False); 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 void
destroynotify(XEvent *e) { destroynotify(XEvent *e) {
Client *c; Client *c;
@ -538,7 +540,7 @@ drawbar(View *v) {
Client *c; Client *c;
dc.x = 0; 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++) { for(i = 0; i < LENGTH(tags); i++) {
if(&views[vtags[i]] != v) if(&views[vtags[i]] != v)
continue; continue;
@ -681,6 +683,16 @@ expose(XEvent *e) {
drawbar(v); 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 void
floating(View *v) { /* default floating layout */ floating(View *v) { /* default floating layout */
Client *c; Client *c;
@ -695,13 +707,12 @@ void
focus(Client *c) { focus(Client *c) {
View *v = selview; View *v = selview;
if(c) if(c)
selview = c->view; selview = getview(c);
else
selview = viewat();
if(selview != v) if(selview != v)
drawbar(v); drawbar(v);
if(!c || (c && !isvisible(c))) 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) { if(sel && sel != c) {
grabbuttons(sel, False); grabbuttons(sel, False);
XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
@ -715,7 +726,7 @@ focus(Client *c) {
if(c) { if(c) {
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
selview = c->view; selview = getview(c);
} }
else else
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
@ -741,7 +752,7 @@ focusnext(const char *arg) {
for(c = clients; c && !isvisible(c); c = c->next); for(c = clients; c && !isvisible(c); c = c->next);
if(c) { if(c) {
focus(c); focus(c);
restack(c->view); restack(getview(c));
} }
} }
@ -758,7 +769,7 @@ focusprev(const char *arg) {
} }
if(c) { if(c) {
focus(c); focus(c);
restack(c->view); restack(getview(c));
} }
} }
@ -780,6 +791,16 @@ getcolor(const char *colstr) {
return color.pixel; 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 * View *
getviewbar(Window barwin) { getviewbar(Window barwin) {
unsigned int i; unsigned int i;
@ -905,7 +926,7 @@ idxoftag(const char *t) {
unsigned int i; unsigned int i;
for(i = 0; (i < LENGTH(tags)) && (tags[i] != t); 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 void
@ -1045,7 +1066,7 @@ manage(Window w, XWindowAttributes *wa) {
applyrules(c); applyrules(c);
v = c->view; v = getview(c);
c->x = wa->x + v->x; c->x = wa->x + v->x;
c->y = wa->y + v->y; c->y = wa->y + v->y;
@ -1124,7 +1145,7 @@ movemouse(Client *c) {
ocx = nx = c->x; ocx = nx = c->x;
ocy = ny = c->y; ocy = ny = c->y;
v = c->view; v = getview(c);
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurMove], CurrentTime) != GrabSuccess) None, cursor[CurMove], CurrentTime) != GrabSuccess)
return; return;
@ -1163,7 +1184,7 @@ movemouse(Client *c) {
Client * Client *
nexttiled(Client *c, View *v) { 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; return c;
} }
@ -1188,7 +1209,7 @@ propertynotify(XEvent *e) {
break; break;
case XA_WM_HINTS: case XA_WM_HINTS:
updatewmhints(c); updatewmhints(c);
drawbar(c->view); drawbar(getview(c));
break; break;
} }
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
@ -1221,7 +1242,7 @@ resize(Client *c, int x, int y, int w, int h, Bool sizehints) {
View *v; View *v;
XWindowChanges wc; XWindowChanges wc;
v = c->view; v = getview(c);
if(sizehints) { if(sizehints) {
/* set minimum possible */ /* set minimum possible */
if (w < 1) if (w < 1)
@ -1292,7 +1313,7 @@ resizemouse(Client *c) {
ocx = c->x; ocx = c->x;
ocy = c->y; ocy = c->y;
v = c->view; v = getview(c);
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
None, cursor[CurResize], CurrentTime) != GrabSuccess) None, cursor[CurResize], CurrentTime) != GrabSuccess)
return; return;
@ -1560,14 +1581,11 @@ nviews = 2; /* aim Xinerama */
for(i = 0; i < nviews; i++) { for(i = 0; i < nviews; i++) {
/* init geometry */ /* init geometry */
v = &views[i]; v = &views[i];
v->id = i;
/* select first tag in each view */ /* select first tag of view */
for(j = 0; j < LENGTH(tags); j++) j = firstag(v);
if(vtags[j] == i) { seltags[j] = prevtags[j] = True;
seltags[j] = prevtags[j] = True;
break;
}
if(info) { if(info) {
@ -1661,8 +1679,10 @@ tag(const char *arg) {
if(!sel) if(!sel)
return; return;
for(i = 0; i < LENGTH(tags); i++) for(i = 0; i < LENGTH(tags); i++)
sel->tags[i] = (NULL == arg); sel->tags[i] = (NULL == arg) && (vtags[i] == getview(sel)->id);
sel->tags[idxoftag(arg)] = True; i = idxoftag(arg);
if(!conflicts(sel, i))
sel->tags[idxoftag(arg)] = True;
arrange(); arrange();
} }
@ -1753,6 +1773,8 @@ toggletag(const char *arg) {
if(!sel) if(!sel)
return; return;
i = idxoftag(arg); i = idxoftag(arg);
if(conflicts(sel, i))
return;
sel->tags[i] = !sel->tags[i]; sel->tags[i] = !sel->tags[i];
for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++); for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++);
if(j == LENGTH(tags)) if(j == LENGTH(tags))
@ -1908,13 +1930,30 @@ updatewmhints(Client *c) {
void void
view(const char *arg) { view(const char *arg) {
unsigned int i; unsigned int i, j;
Bool tmp[LENGTH(tags)]; Bool tmp[LENGTH(tags)];
for(i = 0; i < LENGTH(tags); i++) memcpy(tmp, seltags, TAGSZ);
tmp[i] = (NULL == arg); if(arg == NULL) {
tmp[idxoftag(arg)] = True; 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) { if(memcmp(seltags, tmp, TAGSZ) != 0) {
memcpy(prevtags, seltags, TAGSZ); memcpy(prevtags, seltags, TAGSZ);
memcpy(seltags, tmp, TAGSZ); memcpy(seltags, tmp, TAGSZ);
@ -1985,8 +2024,8 @@ zoom(const char *arg) {
if(!sel || !dozoom || sel->isfloating) if(!sel || !dozoom || sel->isfloating)
return; return;
if(c == nexttiled(clients, c->view)) if(c == nexttiled(clients, getview(c)))
if(!(c = nexttiled(c->next, c->view))) if(!(c = nexttiled(c->next, getview(c))))
return; return;
detach(c); detach(c);
attach(c); attach(c);