| 71 |
71 |
|
unsigned int border, oldborder; |
| 72 |
72 |
|
Bool isbanned, isfixed, isfloating, isurgent; |
| 73 |
73 |
|
Bool *tags; |
| 74 |
|
- |
View *view; |
| 75 |
74 |
|
Client *next; |
| 76 |
75 |
|
Client *prev; |
| 77 |
76 |
|
Client *snext; |
|
| 120 |
119 |
|
}; |
| 121 |
120 |
|
|
| 122 |
121 |
|
/* function declarations */ |
| 123 |
|
- |
void addtag(Client *c, const char *t); |
| 124 |
122 |
|
void applyrules(Client *c); |
| 125 |
123 |
|
void arrange(void); |
| 126 |
124 |
|
void attach(Client *c); |
|
| 132 |
130 |
|
void configure(Client *c); |
| 133 |
131 |
|
void configurenotify(XEvent *e); |
| 134 |
132 |
|
void configurerequest(XEvent *e); |
|
133 |
+ |
Bool conflicts(Client *c, unsigned int tidx); |
| 135 |
134 |
|
void destroynotify(XEvent *e); |
| 136 |
135 |
|
void detach(Client *c); |
| 137 |
136 |
|
void detachstack(Client *c); |
|
| 142 |
141 |
|
void enternotify(XEvent *e); |
| 143 |
142 |
|
void eprint(const char *errstr, ...); |
| 144 |
143 |
|
void expose(XEvent *e); |
|
144 |
+ |
unsigned int firstag(View *v); |
| 145 |
145 |
|
void floating(View *v); /* default floating layout */ |
| 146 |
146 |
|
void focus(Client *c); |
| 147 |
147 |
|
void focusin(XEvent *e); |
|
| 149 |
149 |
|
void focusprev(const char *arg); |
| 150 |
150 |
|
Client *getclient(Window w); |
| 151 |
151 |
|
unsigned long getcolor(const char *colstr); |
|
152 |
+ |
View *getview(Client *c); |
| 152 |
153 |
|
View *getviewbar(Window barwin); |
| 153 |
154 |
|
long getstate(Window w); |
| 154 |
155 |
|
Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
|
| 248 |
249 |
|
#define TAGSZ (LENGTH(tags) * sizeof(Bool)) |
| 249 |
250 |
|
|
| 250 |
251 |
|
/* function implementations */ |
| 251 |
|
- |
void |
| 252 |
|
- |
addtag(Client *c, const char *t) { |
| 253 |
|
- |
unsigned int i, tidx = idxoftag(t); |
| 254 |
|
- |
|
| 255 |
|
- |
for(i = 0; i < LENGTH(tags); i++) |
| 256 |
|
- |
if(c->tags[i] && vtags[i] != vtags[tidx]) |
| 257 |
|
- |
return; /* conflict */ |
| 258 |
|
- |
c->tags[tidx] = True; |
| 259 |
|
- |
c->view = &views[vtags[tidx]]; |
| 260 |
|
- |
} |
| 261 |
252 |
|
|
| 262 |
253 |
|
void |
| 263 |
254 |
|
applyrules(Client *c) { |
| 264 |
|
- |
unsigned int i; |
|
255 |
+ |
unsigned int i, idx; |
| 265 |
256 |
|
Bool matched = False; |
| 266 |
257 |
|
Rule *r; |
| 267 |
258 |
|
XClassHint ch = { 0 }; |
|
| 275 |
266 |
|
|| (ch.res_name && strstr(ch.res_name, r->prop))) |
| 276 |
267 |
|
{ |
| 277 |
268 |
|
c->isfloating = r->isfloating; |
| 278 |
|
- |
if(r->tag) { |
| 279 |
|
- |
addtag(c, r->tag); |
|
269 |
+ |
if(r->tag && !conflicts(c, (idx = idxoftag(r->tag)))) { |
|
270 |
+ |
c->tags[idx] = True; |
| 280 |
271 |
|
matched = True; |
| 281 |
272 |
|
} |
| 282 |
273 |
|
} |
|
| 286 |
277 |
|
if(ch.res_name) |
| 287 |
278 |
|
XFree(ch.res_name); |
| 288 |
279 |
|
if(!matched) { |
| 289 |
|
- |
memcpy(c->tags, seltags, TAGSZ); |
| 290 |
|
- |
c->view = selview; |
|
280 |
+ |
for(i = 0; i < LENGTH(tags); i++) |
|
281 |
+ |
if(seltags[i] && vtags[i] == selview->id) |
|
282 |
+ |
c->tags[i] = True; |
| 291 |
283 |
|
} |
| 292 |
284 |
|
} |
| 293 |
285 |
|
|
|
| 327 |
319 |
|
ban(Client *c) { |
| 328 |
320 |
|
if(c->isbanned) |
| 329 |
321 |
|
return; |
| 330 |
|
- |
XMoveWindow(dpy, c->win, c->x + 3 * c->view->w, c->y); |
|
322 |
+ |
XMoveWindow(dpy, c->win, c->x + 3 * getview(c)->w, c->y); |
| 331 |
323 |
|
c->isbanned = True; |
| 332 |
324 |
|
} |
| 333 |
325 |
|
|
|
| 367 |
359 |
|
if(CLEANMASK(ev->state) != MODKEY) |
| 368 |
360 |
|
return; |
| 369 |
361 |
|
if(ev->button == Button1) { |
| 370 |
|
- |
restack(c->view); |
|
362 |
+ |
restack(getview(c)); |
| 371 |
363 |
|
movemouse(c); |
| 372 |
364 |
|
} |
| 373 |
365 |
|
else if(ev->button == Button2) { |
| 374 |
|
- |
if((floating != c->view->layout->arrange) && c->isfloating) |
|
366 |
+ |
if((floating != getview(c)->layout->arrange) && c->isfloating) |
| 375 |
367 |
|
togglefloating(NULL); |
| 376 |
368 |
|
else |
| 377 |
369 |
|
zoom(NULL); |
| 378 |
370 |
|
} |
| 379 |
371 |
|
else if(ev->button == Button3 && !c->isfixed) { |
| 380 |
|
- |
restack(c->view); |
|
372 |
+ |
restack(getview(c)); |
| 381 |
373 |
|
resizemouse(c); |
| 382 |
374 |
|
} |
| 383 |
375 |
|
} |
|
| 466 |
458 |
|
XWindowChanges wc; |
| 467 |
459 |
|
|
| 468 |
460 |
|
if((c = getclient(ev->window))) { |
| 469 |
|
- |
View *v = c->view; |
|
461 |
+ |
View *v = getview(c); |
| 470 |
462 |
|
if(ev->value_mask & CWBorderWidth) |
| 471 |
463 |
|
c->border = ev->border_width; |
| 472 |
464 |
|
if(c->isfixed || c->isfloating || (floating == v->layout->arrange)) { |
|
| 504 |
496 |
|
XSync(dpy, False); |
| 505 |
497 |
|
} |
| 506 |
498 |
|
|
|
499 |
+ |
Bool |
|
500 |
+ |
conflicts(Client *c, unsigned int tidx) { |
|
501 |
+ |
unsigned int i; |
|
502 |
+ |
|
|
503 |
+ |
for(i = 0; i < LENGTH(tags); i++) |
|
504 |
+ |
if(c->tags[i] && vtags[i] != vtags[tidx]) |
|
505 |
+ |
return True; /* conflict */ |
|
506 |
+ |
return False; |
|
507 |
+ |
} |
|
508 |
+ |
|
| 507 |
509 |
|
void |
| 508 |
510 |
|
destroynotify(XEvent *e) { |
| 509 |
511 |
|
Client *c; |
|
| 538 |
540 |
|
Client *c; |
| 539 |
541 |
|
|
| 540 |
542 |
|
dc.x = 0; |
| 541 |
|
- |
for(c = stack; c && (!isvisible(c) || c->view != v); c = c->snext); |
|
543 |
+ |
for(c = stack; c && (!isvisible(c) || getview(c) != v); c = c->snext); |
| 542 |
544 |
|
for(i = 0; i < LENGTH(tags); i++) { |
| 543 |
545 |
|
if(&views[vtags[i]] != v) |
| 544 |
546 |
|
continue; |
|
| 681 |
683 |
|
drawbar(v); |
| 682 |
684 |
|
} |
| 683 |
685 |
|
|
|
686 |
+ |
unsigned int |
|
687 |
+ |
firstag(View *v) { |
|
688 |
+ |
unsigned int i; |
|
689 |
+ |
|
|
690 |
+ |
for(i = 0; i < LENGTH(tags); i++) |
|
691 |
+ |
if(vtags[i] == v->id) |
|
692 |
+ |
return i; |
|
693 |
+ |
return 0; /* safe fallback */ |
|
694 |
+ |
} |
|
695 |
+ |
|
| 684 |
696 |
|
void |
| 685 |
697 |
|
floating(View *v) { /* default floating layout */ |
| 686 |
698 |
|
Client *c; |
|
| 695 |
707 |
|
focus(Client *c) { |
| 696 |
708 |
|
View *v = selview; |
| 697 |
709 |
|
if(c) |
| 698 |
|
- |
selview = c->view; |
| 699 |
|
- |
else |
| 700 |
|
- |
selview = viewat(); |
|
710 |
+ |
selview = getview(c); |
| 701 |
711 |
|
if(selview != v) |
| 702 |
712 |
|
drawbar(v); |
| 703 |
713 |
|
if(!c || (c && !isvisible(c))) |
| 704 |
|
- |
for(c = stack; c && (!isvisible(c) || c->view != selview); c = c->snext); |
|
714 |
+ |
/* TODO: isvisible might take getview(c) as constraint? */ |
|
715 |
+ |
for(c = stack; c && (!isvisible(c) || getview(c) != selview); c = c->snext); |
| 705 |
716 |
|
if(sel && sel != c) { |
| 706 |
717 |
|
grabbuttons(sel, False); |
| 707 |
718 |
|
XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]); |
|
| 715 |
726 |
|
if(c) { |
| 716 |
727 |
|
XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]); |
| 717 |
728 |
|
XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
| 718 |
|
- |
selview = c->view; |
|
729 |
+ |
selview = getview(c); |
| 719 |
730 |
|
} |
| 720 |
731 |
|
else |
| 721 |
732 |
|
XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); |
|
| 741 |
752 |
|
for(c = clients; c && !isvisible(c); c = c->next); |
| 742 |
753 |
|
if(c) { |
| 743 |
754 |
|
focus(c); |
| 744 |
|
- |
restack(c->view); |
|
755 |
+ |
restack(getview(c)); |
| 745 |
756 |
|
} |
| 746 |
757 |
|
} |
| 747 |
758 |
|
|
|
| 758 |
769 |
|
} |
| 759 |
770 |
|
if(c) { |
| 760 |
771 |
|
focus(c); |
| 761 |
|
- |
restack(c->view); |
|
772 |
+ |
restack(getview(c)); |
| 762 |
773 |
|
} |
| 763 |
774 |
|
} |
| 764 |
775 |
|
|
|
| 781 |
792 |
|
} |
| 782 |
793 |
|
|
| 783 |
794 |
|
View * |
|
795 |
+ |
getview(Client *c) { |
|
796 |
+ |
unsigned int i; |
|
797 |
+ |
|
|
798 |
+ |
for(i = 0; i < LENGTH(tags); i++) |
|
799 |
+ |
if(c->tags[i]) |
|
800 |
+ |
return &views[vtags[i]]; |
|
801 |
+ |
return NULL; |
|
802 |
+ |
} |
|
803 |
+ |
|
|
804 |
+ |
View * |
| 784 |
805 |
|
getviewbar(Window barwin) { |
| 785 |
806 |
|
unsigned int i; |
| 786 |
807 |
|
|
|
| 905 |
926 |
|
unsigned int i; |
| 906 |
927 |
|
|
| 907 |
928 |
|
for(i = 0; (i < LENGTH(tags)) && (tags[i] != t); i++); |
| 908 |
|
- |
return (i < LENGTH(tags)) ? i : 0; |
|
929 |
+ |
return (i < LENGTH(tags)) ? i : firstag(selview); |
| 909 |
930 |
|
} |
| 910 |
931 |
|
|
| 911 |
932 |
|
void |
|
| 1045 |
1066 |
|
|
| 1046 |
1067 |
|
applyrules(c); |
| 1047 |
1068 |
|
|
| 1048 |
|
- |
v = c->view; |
|
1069 |
+ |
v = getview(c); |
| 1049 |
1070 |
|
|
| 1050 |
1071 |
|
c->x = wa->x + v->x; |
| 1051 |
1072 |
|
c->y = wa->y + v->y; |
|
| 1124 |
1145 |
|
|
| 1125 |
1146 |
|
ocx = nx = c->x; |
| 1126 |
1147 |
|
ocy = ny = c->y; |
| 1127 |
|
- |
v = c->view; |
|
1148 |
+ |
v = getview(c); |
| 1128 |
1149 |
|
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
| 1129 |
1150 |
|
None, cursor[CurMove], CurrentTime) != GrabSuccess) |
| 1130 |
1151 |
|
return; |
|
| 1163 |
1184 |
|
|
| 1164 |
1185 |
|
Client * |
| 1165 |
1186 |
|
nexttiled(Client *c, View *v) { |
| 1166 |
|
- |
for(; c && (c->isfloating || c->view != v || !isvisible(c)); c = c->next); |
|
1187 |
+ |
for(; c && (c->isfloating || getview(c) != v || !isvisible(c)); c = c->next); |
| 1167 |
1188 |
|
return c; |
| 1168 |
1189 |
|
} |
| 1169 |
1190 |
|
|
|
| 1188 |
1209 |
|
break; |
| 1189 |
1210 |
|
case XA_WM_HINTS: |
| 1190 |
1211 |
|
updatewmhints(c); |
| 1191 |
|
- |
drawbar(c->view); |
|
1212 |
+ |
drawbar(getview(c)); |
| 1192 |
1213 |
|
break; |
| 1193 |
1214 |
|
} |
| 1194 |
1215 |
|
if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
|
| 1221 |
1242 |
|
View *v; |
| 1222 |
1243 |
|
XWindowChanges wc; |
| 1223 |
1244 |
|
|
| 1224 |
|
- |
v = c->view; |
|
1245 |
+ |
v = getview(c); |
| 1225 |
1246 |
|
if(sizehints) { |
| 1226 |
1247 |
|
/* set minimum possible */ |
| 1227 |
1248 |
|
if (w < 1) |
|
| 1292 |
1313 |
|
|
| 1293 |
1314 |
|
ocx = c->x; |
| 1294 |
1315 |
|
ocy = c->y; |
| 1295 |
|
- |
v = c->view; |
|
1316 |
+ |
v = getview(c); |
| 1296 |
1317 |
|
if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync, |
| 1297 |
1318 |
|
None, cursor[CurResize], CurrentTime) != GrabSuccess) |
| 1298 |
1319 |
|
return; |
|
| 1560 |
1581 |
|
for(i = 0; i < nviews; i++) { |
| 1561 |
1582 |
|
/* init geometry */ |
| 1562 |
1583 |
|
v = &views[i]; |
|
1584 |
+ |
v->id = i; |
| 1563 |
1585 |
|
|
| 1564 |
|
- |
/* select first tag in each view */ |
| 1565 |
|
- |
for(j = 0; j < LENGTH(tags); j++) |
| 1566 |
|
- |
if(vtags[j] == i) { |
| 1567 |
|
- |
seltags[j] = prevtags[j] = True; |
| 1568 |
|
- |
break; |
| 1569 |
|
- |
} |
| 1570 |
|
- |
|
|
1586 |
+ |
/* select first tag of view */ |
|
1587 |
+ |
j = firstag(v); |
|
1588 |
+ |
seltags[j] = prevtags[j] = True; |
| 1571 |
1589 |
|
|
| 1572 |
1590 |
|
if(info) { |
| 1573 |
1591 |
|
|
|
| 1661 |
1679 |
|
if(!sel) |
| 1662 |
1680 |
|
return; |
| 1663 |
1681 |
|
for(i = 0; i < LENGTH(tags); i++) |
| 1664 |
|
- |
sel->tags[i] = (NULL == arg); |
| 1665 |
|
- |
sel->tags[idxoftag(arg)] = True; |
|
1682 |
+ |
sel->tags[i] = (NULL == arg) && (vtags[i] == getview(sel)->id); |
|
1683 |
+ |
i = idxoftag(arg); |
|
1684 |
+ |
if(!conflicts(sel, i)) |
|
1685 |
+ |
sel->tags[idxoftag(arg)] = True; |
| 1666 |
1686 |
|
arrange(); |
| 1667 |
1687 |
|
} |
| 1668 |
1688 |
|
|
|
| 1753 |
1773 |
|
if(!sel) |
| 1754 |
1774 |
|
return; |
| 1755 |
1775 |
|
i = idxoftag(arg); |
|
1776 |
+ |
if(conflicts(sel, i)) |
|
1777 |
+ |
return; |
| 1756 |
1778 |
|
sel->tags[i] = !sel->tags[i]; |
| 1757 |
1779 |
|
for(j = 0; j < LENGTH(tags) && !sel->tags[j]; j++); |
| 1758 |
1780 |
|
if(j == LENGTH(tags)) |
|
| 1908 |
1930 |
|
|
| 1909 |
1931 |
|
void |
| 1910 |
1932 |
|
view(const char *arg) { |
| 1911 |
|
- |
unsigned int i; |
|
1933 |
+ |
unsigned int i, j; |
| 1912 |
1934 |
|
Bool tmp[LENGTH(tags)]; |
| 1913 |
1935 |
|
|
| 1914 |
|
- |
for(i = 0; i < LENGTH(tags); i++) |
| 1915 |
|
- |
tmp[i] = (NULL == arg); |
| 1916 |
|
- |
tmp[idxoftag(arg)] = True; |
| 1917 |
|
- |
|
|
1936 |
+ |
memcpy(tmp, seltags, TAGSZ); |
|
1937 |
+ |
if(arg == NULL) { |
|
1938 |
+ |
for(i = 0; i < LENGTH(tags); i++) |
|
1939 |
+ |
tmp[i] = (vtags[i] == selview->id); |
|
1940 |
+ |
} |
|
1941 |
+ |
else { |
|
1942 |
+ |
i = idxoftag(arg); |
|
1943 |
+ |
for(j = 0; j < LENGTH(tags); j++) |
|
1944 |
+ |
if(selview->id == vtags[i]) { |
|
1945 |
+ |
/* view tag of selview */ |
|
1946 |
+ |
if(selview->id == vtags[j]) |
|
1947 |
+ |
tmp[j] = False; |
|
1948 |
+ |
} |
|
1949 |
+ |
else { |
|
1950 |
+ |
/* only touch the view the focus should go */ |
|
1951 |
+ |
if(vtags[j] == vtags[i]) |
|
1952 |
+ |
tmp[j] = False; |
|
1953 |
+ |
} |
|
1954 |
+ |
selview = &views[vtags[i]]; |
|
1955 |
+ |
tmp[i] = True; |
|
1956 |
+ |
} |
| 1918 |
1957 |
|
if(memcmp(seltags, tmp, TAGSZ) != 0) { |
| 1919 |
1958 |
|
memcpy(prevtags, seltags, TAGSZ); |
| 1920 |
1959 |
|
memcpy(seltags, tmp, TAGSZ); |
|
| 1985 |
2024 |
|
|
| 1986 |
2025 |
|
if(!sel || !dozoom || sel->isfloating) |
| 1987 |
2026 |
|
return; |
| 1988 |
|
- |
if(c == nexttiled(clients, c->view)) |
| 1989 |
|
- |
if(!(c = nexttiled(c->next, c->view))) |
|
2027 |
+ |
if(c == nexttiled(clients, getview(c))) |
|
2028 |
+ |
if(!(c = nexttiled(c->next, getview(c)))) |
| 1990 |
2029 |
|
return; |
| 1991 |
2030 |
|
detach(c); |
| 1992 |
2031 |
|
attach(c); |