mirror of
https://git.suckless.org/dwm
synced 2024-12-27 03:16:32 +00:00
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:
parent
f1719ac2de
commit
7bc272a4e4
2 changed files with 93 additions and 54 deletions
|
@ -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
145
dwm.c
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue