several simplifications
1ddfc571
2 file(s) · +83 −109
| 1 | 1 | /* See LICENSE file for copyright and license details. */ |
|
| 2 | 2 | ||
| 3 | 3 | /* appearance */ |
|
| 4 | + | #define SHOWBAR True /* False means no bar */ |
|
| 5 | + | #define TOPBAR True /* False means bottom bar */ |
|
| 4 | 6 | static const char font[] = "-*-*-medium-*-*-*-14-*-*-*-*-*-*-*"; |
|
| 5 | 7 | static const char normbordercolor[] = "#cccccc"; |
|
| 6 | 8 | static const char normbgcolor[] = "#cccccc"; |
|
| 10 | 12 | static const char selfgcolor[] = "#ffffff"; |
|
| 11 | 13 | static unsigned int borderpx = 1; /* border pixel of windows */ |
|
| 12 | 14 | static unsigned int snap = 32; /* snap pixel */ |
|
| 13 | - | static Bool showbar = True; /* False means no bar */ |
|
| 14 | - | static Bool topbar = True; /* False means bottom bar */ |
|
| 15 | - | ||
| 16 | 15 | ||
| 17 | 16 | /* tagging */ |
|
| 18 | 17 | static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; |
|
| 1 | - | //#define XINULATOR /* debug, simulates dual head */ |
|
| 2 | 1 | /* See LICENSE file for copyright and license details. |
|
| 3 | 2 | * |
|
| 4 | 3 | * dynamic window manager is designed like any other X client as well. It is |
|
| 174 | 173 | static void focus(Client *c); |
|
| 175 | 174 | static void focusin(XEvent *e); |
|
| 176 | 175 | static void focusstack(const Arg *arg); |
|
| 177 | - | static Client *getclient(Window w); |
|
| 178 | 176 | static unsigned long getcolor(const char *colstr); |
|
| 179 | - | static Monitor *getmon(Window w); |
|
| 180 | - | static Monitor *getmonn(unsigned int n); |
|
| 181 | - | static Monitor *getmonxy(int x, int y); |
|
| 182 | 177 | static Bool getrootpointer(int *x, int *y); |
|
| 183 | 178 | static long getstate(Window w); |
|
| 184 | 179 | static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
|
| 185 | 180 | static void grabbuttons(Client *c, Bool focused); |
|
| 186 | 181 | static void grabkeys(void); |
|
| 182 | + | static Monitor *idxtomon(unsigned int n); |
|
| 187 | 183 | static void initfont(const char *fontstr); |
|
| 188 | 184 | static Bool isprotodel(Client *c); |
|
| 189 | 185 | static void keypress(XEvent *e); |
|
| 194 | 190 | static void monocle(Monitor *m); |
|
| 195 | 191 | static void movemouse(const Arg *arg); |
|
| 196 | 192 | static Client *nexttiled(Client *c); |
|
| 193 | + | static Monitor *pointertomon(int x, int y); |
|
| 197 | 194 | static void propertynotify(XEvent *e); |
|
| 198 | 195 | static void quit(const Arg *arg); |
|
| 199 | 196 | static void resize(Client *c, int x, int y, int w, int h); |
|
| 228 | 225 | static void updatetitle(Client *c); |
|
| 229 | 226 | static void updatewmhints(Client *c); |
|
| 230 | 227 | static void view(const Arg *arg); |
|
| 228 | + | static Client *wintoclient(Window w); |
|
| 229 | + | static Monitor *wintomon(Window w); |
|
| 231 | 230 | static int xerror(Display *dpy, XErrorEvent *ee); |
|
| 232 | 231 | static int xerrordummy(Display *dpy, XErrorEvent *ee); |
|
| 233 | 232 | static int xerrorstart(Display *dpy, XErrorEvent *ee); |
|
| 402 | 401 | ||
| 403 | 402 | click = ClkRootWin; |
|
| 404 | 403 | /* focus monitor if necessary */ |
|
| 405 | - | if((m = getmon(ev->window)) && m != selmon) { |
|
| 404 | + | if((m = wintomon(ev->window)) && m != selmon) { |
|
| 406 | 405 | unfocus(selmon->sel); |
|
| 407 | 406 | selmon = m; |
|
| 408 | 407 | focus(NULL); |
|
| 424 | 423 | else |
|
| 425 | 424 | click = ClkWinTitle; |
|
| 426 | 425 | } |
|
| 427 | - | else if((c = getclient(ev->window))) { |
|
| 426 | + | else if((c = wintoclient(ev->window))) { |
|
| 428 | 427 | focus(c); |
|
| 429 | 428 | click = ClkClientWin; |
|
| 430 | 429 | } |
|
| 457 | 456 | ||
| 458 | 457 | view(&a); |
|
| 459 | 458 | lt[selmon->sellt] = &foo; |
|
| 460 | - | ||
| 461 | - | /* TODO: consider simplifying cleanup code of the stack, perhaps do that in cleanmons() ? */ |
|
| 462 | 459 | for(m = mons; m; m = m->next) |
|
| 463 | 460 | while(m->stack) |
|
| 464 | 461 | unmanage(m->stack); |
|
| 546 | 543 | XConfigureRequestEvent *ev = &e->xconfigurerequest; |
|
| 547 | 544 | XWindowChanges wc; |
|
| 548 | 545 | ||
| 549 | - | if((c = getclient(ev->window))) { |
|
| 546 | + | if((c = wintoclient(ev->window))) { |
|
| 550 | 547 | if(ev->value_mask & CWBorderWidth) |
|
| 551 | 548 | c->bw = ev->border_width; |
|
| 552 | 549 | else if(c->isfloating || !lt[selmon->sellt]->arrange) { |
|
| 589 | 586 | Client *c; |
|
| 590 | 587 | XDestroyWindowEvent *ev = &e->xdestroywindow; |
|
| 591 | 588 | ||
| 592 | - | if((c = getclient(ev->window))) |
|
| 589 | + | if((c = wintoclient(ev->window))) |
|
| 593 | 590 | unmanage(c); |
|
| 594 | 591 | } |
|
| 595 | 592 | ||
| 607 | 604 | ||
| 608 | 605 | for(tc = &c->mon->stack; *tc && *tc != c; tc = &(*tc)->snext); |
|
| 609 | 606 | *tc = c->snext; |
|
| 607 | + | ||
| 608 | + | if(c == c->mon->sel) { |
|
| 609 | + | for(*tc = c->mon->stack; *tc && !ISVISIBLE((*tc)); *tc = (*tc)->snext); |
|
| 610 | + | c->mon->sel = *tc; |
|
| 611 | + | } |
|
| 610 | 612 | } |
|
| 611 | 613 | ||
| 612 | 614 | void |
|
| 750 | 752 | ||
| 751 | 753 | if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root) |
|
| 752 | 754 | return; |
|
| 753 | - | if((m = getmon(ev->window)) && m != selmon) { |
|
| 755 | + | if((m = wintomon(ev->window)) && m != selmon) { |
|
| 754 | 756 | unfocus(selmon->sel); |
|
| 755 | 757 | selmon = m; |
|
| 756 | 758 | } |
|
| 757 | - | if((c = getclient(ev->window))) |
|
| 759 | + | if((c = wintoclient(ev->window))) |
|
| 758 | 760 | focus(c); |
|
| 759 | 761 | else |
|
| 760 | 762 | focus(NULL); |
|
| 765 | 767 | Monitor *m; |
|
| 766 | 768 | XExposeEvent *ev = &e->xexpose; |
|
| 767 | 769 | ||
| 768 | - | if(ev->count == 0 && (m = getmon(ev->window))) |
|
| 770 | + | if(ev->count == 0 && (m = wintomon(ev->window))) |
|
| 769 | 771 | drawbar(m); |
|
| 770 | 772 | } |
|
| 771 | 773 | ||
| 805 | 807 | focusmon(const Arg *arg) { |
|
| 806 | 808 | Monitor *m; |
|
| 807 | 809 | ||
| 808 | - | if(!(m = getmonn(arg->ui)) || m == selmon) |
|
| 810 | + | if(!(m = idxtomon(arg->ui)) || m == selmon) |
|
| 809 | 811 | return; |
|
| 810 | 812 | unfocus(selmon->sel); |
|
| 811 | 813 | selmon = m; |
|
| 839 | 841 | } |
|
| 840 | 842 | } |
|
| 841 | 843 | ||
| 842 | - | Client * |
|
| 843 | - | getclient(Window w) { |
|
| 844 | - | Client *c; |
|
| 845 | - | Monitor *m; |
|
| 846 | - | ||
| 847 | - | for(m = mons; m; m = m->next) |
|
| 848 | - | for(c = m->clients; c; c = c->next) |
|
| 849 | - | if(c->win == w) |
|
| 850 | - | return c; |
|
| 851 | - | return NULL; |
|
| 852 | - | } |
|
| 853 | - | ||
| 854 | 844 | unsigned long |
|
| 855 | 845 | getcolor(const char *colstr) { |
|
| 856 | 846 | Colormap cmap = DefaultColormap(dpy, screen); |
|
| 861 | 851 | return color.pixel; |
|
| 862 | 852 | } |
|
| 863 | 853 | ||
| 864 | - | Monitor * |
|
| 865 | - | getmon(Window w) { |
|
| 866 | - | int x, y; |
|
| 867 | - | Client *c; |
|
| 868 | - | Monitor *m; |
|
| 869 | - | ||
| 870 | - | if(w == root && getrootpointer(&x, &y)) |
|
| 871 | - | return getmonxy(x, y); |
|
| 872 | - | for(m = mons; m; m = m->next) |
|
| 873 | - | if(w == m->barwin) |
|
| 874 | - | return m; |
|
| 875 | - | if((c = getclient(w))) |
|
| 876 | - | return c->mon; |
|
| 877 | - | return mons; |
|
| 878 | - | } |
|
| 879 | - | ||
| 880 | - | Monitor * |
|
| 881 | - | getmonn(unsigned int n) { |
|
| 882 | - | unsigned int i; |
|
| 883 | - | Monitor *m; |
|
| 884 | - | ||
| 885 | - | for(m = mons, i = 0; m && i != n; m = m->next, i++); |
|
| 886 | - | return m; |
|
| 887 | - | } |
|
| 888 | - | ||
| 889 | - | Monitor * |
|
| 890 | - | getmonxy(int x, int y) { |
|
| 891 | - | Monitor *m; |
|
| 892 | - | ||
| 893 | - | for(m = mons; m; m = m->next) |
|
| 894 | - | if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh)) |
|
| 895 | - | return m; |
|
| 896 | - | return mons; |
|
| 897 | - | } |
|
| 898 | - | ||
| 899 | 854 | Bool |
|
| 900 | 855 | getrootpointer(int *x, int *y) { |
|
| 901 | 856 | int di; |
|
| 987 | 942 | } |
|
| 988 | 943 | } |
|
| 989 | 944 | ||
| 945 | + | Monitor * |
|
| 946 | + | idxtomon(unsigned int n) { |
|
| 947 | + | unsigned int i; |
|
| 948 | + | Monitor *m; |
|
| 949 | + | ||
| 950 | + | for(m = mons, i = 0; m && i != n; m = m->next, i++); |
|
| 951 | + | return m; |
|
| 952 | + | } |
|
| 953 | + | ||
| 990 | 954 | void |
|
| 991 | 955 | initfont(const char *fontstr) { |
|
| 992 | 956 | char *def, **missing; |
|
| 1116 | 1080 | grabbuttons(c, False); |
|
| 1117 | 1081 | updatetitle(c); |
|
| 1118 | 1082 | if(XGetTransientForHint(dpy, w, &trans)) |
|
| 1119 | - | t = getclient(trans); |
|
| 1083 | + | t = wintoclient(trans); |
|
| 1120 | 1084 | if(t) |
|
| 1121 | 1085 | c->tags = t->tags; |
|
| 1122 | 1086 | else |
|
| 1151 | 1115 | return; |
|
| 1152 | 1116 | if(wa.override_redirect) |
|
| 1153 | 1117 | return; |
|
| 1154 | - | if(!getclient(ev->window)) |
|
| 1118 | + | if(!wintoclient(ev->window)) |
|
| 1155 | 1119 | manage(ev->window, &wa); |
|
| 1156 | 1120 | } |
|
| 1157 | 1121 | ||
| 1212 | 1176 | } |
|
| 1213 | 1177 | while(ev.type != ButtonRelease); |
|
| 1214 | 1178 | XUngrabPointer(dpy, CurrentTime); |
|
| 1215 | - | if((m = getmonxy(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
|
| 1179 | + | if((m = pointertomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
|
| 1216 | 1180 | sendmon(c, m); |
|
| 1217 | 1181 | selmon = m; |
|
| 1218 | 1182 | focus(NULL); |
|
| 1225 | 1189 | return c; |
|
| 1226 | 1190 | } |
|
| 1227 | 1191 | ||
| 1192 | + | Monitor * |
|
| 1193 | + | pointertomon(int x, int y) { |
|
| 1194 | + | Monitor *m; |
|
| 1195 | + | ||
| 1196 | + | for(m = mons; m; m = m->next) |
|
| 1197 | + | if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh)) |
|
| 1198 | + | return m; |
|
| 1199 | + | return mons; |
|
| 1200 | + | } |
|
| 1201 | + | ||
| 1228 | 1202 | void |
|
| 1229 | 1203 | propertynotify(XEvent *e) { |
|
| 1230 | 1204 | Client *c; |
|
| 1235 | 1209 | updatestatus(); |
|
| 1236 | 1210 | else if(ev->state == PropertyDelete) |
|
| 1237 | 1211 | return; /* ignore */ |
|
| 1238 | - | else if((c = getclient(ev->window))) { |
|
| 1212 | + | else if((c = wintoclient(ev->window))) { |
|
| 1239 | 1213 | switch (ev->atom) { |
|
| 1240 | 1214 | default: break; |
|
| 1241 | 1215 | case XA_WM_TRANSIENT_FOR: |
|
| 1242 | 1216 | XGetTransientForHint(dpy, c->win, &trans); |
|
| 1243 | - | if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) |
|
| 1217 | + | if(!c->isfloating && (c->isfloating = (wintoclient(trans) != NULL))) |
|
| 1244 | 1218 | arrange(); |
|
| 1245 | 1219 | break; |
|
| 1246 | 1220 | case XA_WM_NORMAL_HINTS: |
|
| 1324 | 1298 | XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1); |
|
| 1325 | 1299 | XUngrabPointer(dpy, CurrentTime); |
|
| 1326 | 1300 | while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
|
| 1327 | - | if((m = getmonxy(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
|
| 1301 | + | if((m = pointertomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) { |
|
| 1328 | 1302 | sendmon(c, m); |
|
| 1329 | 1303 | selmon = m; |
|
| 1330 | 1304 | focus(NULL); |
|
| 1557 | 1531 | tagmon(const Arg *arg) { |
|
| 1558 | 1532 | Monitor *m; |
|
| 1559 | 1533 | ||
| 1560 | - | if(!selmon->sel || !(m = getmonn(arg->ui))) |
|
| 1534 | + | if(!selmon->sel || !(m = idxtomon(arg->ui))) |
|
| 1561 | 1535 | return; |
|
| 1562 | 1536 | sendmon(selmon->sel, m); |
|
| 1563 | 1537 | } |
|
| 1670 | 1644 | XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */ |
|
| 1671 | 1645 | detach(c); |
|
| 1672 | 1646 | detachstack(c); |
|
| 1673 | - | if(c->mon->sel == c) { |
|
| 1674 | - | /* TODO: consider separate the next code into a function or into detachstack? */ |
|
| 1675 | - | Client *tc; |
|
| 1676 | - | for(tc = c->mon->stack; tc && !ISVISIBLE(tc); tc = tc->snext); |
|
| 1677 | - | c->mon->sel = tc; |
|
| 1678 | - | focus(NULL); |
|
| 1679 | - | } |
|
| 1680 | 1647 | XUngrabButton(dpy, AnyButton, AnyModifier, c->win); |
|
| 1681 | 1648 | setclientstate(c, WithdrawnState); |
|
| 1682 | 1649 | free(c); |
|
| 1683 | 1650 | XSync(dpy, False); |
|
| 1684 | 1651 | XSetErrorHandler(xerror); |
|
| 1685 | 1652 | XUngrabServer(dpy); |
|
| 1653 | + | focus(NULL); |
|
| 1686 | 1654 | arrange(); |
|
| 1687 | 1655 | } |
|
| 1688 | 1656 | ||
| 1691 | 1659 | Client *c; |
|
| 1692 | 1660 | XUnmapEvent *ev = &e->xunmap; |
|
| 1693 | 1661 | ||
| 1694 | - | if((c = getclient(ev->window))) |
|
| 1662 | + | if((c = wintoclient(ev->window))) |
|
| 1695 | 1663 | unmanage(c); |
|
| 1696 | 1664 | } |
|
| 1697 | 1665 | ||
| 1733 | 1701 | Client *c; |
|
| 1734 | 1702 | Monitor *newmons = NULL, *m, *tm; |
|
| 1735 | 1703 | ||
| 1736 | - | #ifdef XINULATOR |
|
| 1737 | - | n = 2; |
|
| 1738 | - | #elif defined(XINERAMA) |
|
| 1704 | + | #ifdef XINERAMA |
|
| 1739 | 1705 | XineramaScreenInfo *info = NULL; |
|
| 1740 | 1706 | ||
| 1741 | 1707 | if(XineramaIsActive(dpy)) |
|
| 1742 | 1708 | info = XineramaQueryScreens(dpy, &n); |
|
| 1743 | - | #endif |
|
| 1709 | + | #endif /* XINERAMA */ |
|
| 1744 | 1710 | /* allocate monitor(s) for the new geometry setup */ |
|
| 1745 | 1711 | for(i = 0; i < n; i++) { |
|
| 1746 | 1712 | m = (Monitor *)malloc(sizeof(Monitor)); |
|
| 1749 | 1715 | } |
|
| 1750 | 1716 | ||
| 1751 | 1717 | /* initialise monitor(s) */ |
|
| 1752 | - | #ifdef XINULATOR |
|
| 1753 | - | if(1) { |
|
| 1754 | - | m = newmons; |
|
| 1755 | - | m->screen_number = 0; |
|
| 1756 | - | m->wx = sx; |
|
| 1757 | - | m->my = m->wy = sy; |
|
| 1758 | - | m->ww = sw; |
|
| 1759 | - | m->mh = m->wh = sh / 2; |
|
| 1760 | - | m = newmons->next; |
|
| 1761 | - | m->screen_number = 1; |
|
| 1762 | - | m->wx = sx; |
|
| 1763 | - | m->my = m->wy = sy + sh / 2; |
|
| 1764 | - | m->ww = sw; |
|
| 1765 | - | m->mh = m->wh = sh / 2; |
|
| 1766 | - | } |
|
| 1767 | - | else |
|
| 1768 | - | #elif defined(XINERAMA) |
|
| 1718 | + | #ifdef XINERAMA |
|
| 1769 | 1719 | if(XineramaIsActive(dpy)) { |
|
| 1770 | 1720 | for(i = 0, m = newmons; m; m = m->next, i++) { |
|
| 1771 | 1721 | m->screen_number = info[i].screen_number; |
|
| 1777 | 1727 | XFree(info); |
|
| 1778 | 1728 | } |
|
| 1779 | 1729 | else |
|
| 1780 | - | #endif |
|
| 1730 | + | #endif /* XINERAMA */ |
|
| 1781 | 1731 | /* default monitor setup */ |
|
| 1782 | 1732 | { |
|
| 1783 | 1733 | m->screen_number = 0; |
|
| 1789 | 1739 | ||
| 1790 | 1740 | /* bar geometry setup */ |
|
| 1791 | 1741 | for(m = newmons; m; m = m->next) { |
|
| 1792 | - | /* TODO: consider removing the following values from config.h */ |
|
| 1793 | - | m->clients = NULL; |
|
| 1794 | - | m->sel = NULL; |
|
| 1795 | - | m->stack = NULL; |
|
| 1742 | + | m->sel = m->stack = m->clients = NULL; |
|
| 1796 | 1743 | m->seltags = 0; |
|
| 1797 | 1744 | m->sellt = 0; |
|
| 1798 | 1745 | m->tagset[0] = m->tagset[1] = 1; |
|
| 1799 | 1746 | m->mfact = mfact; |
|
| 1800 | - | m->showbar = showbar; |
|
| 1801 | - | m->topbar = topbar; |
|
| 1747 | + | m->showbar = SHOWBAR; |
|
| 1748 | + | m->topbar = TOPBAR; |
|
| 1802 | 1749 | updatebarpos(m); |
|
| 1803 | 1750 | } |
|
| 1804 | 1751 | ||
| 1816 | 1763 | /* select focused monitor */ |
|
| 1817 | 1764 | cleanupmons(); |
|
| 1818 | 1765 | mons = newmons; |
|
| 1819 | - | selmon = getmon(root); |
|
| 1766 | + | selmon = wintomon(root); |
|
| 1820 | 1767 | } |
|
| 1821 | 1768 | ||
| 1822 | 1769 | void |
|
| 1921 | 1868 | if(arg->ui & TAGMASK) |
|
| 1922 | 1869 | selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
|
| 1923 | 1870 | arrange(); |
|
| 1871 | + | } |
|
| 1872 | + | ||
| 1873 | + | Client * |
|
| 1874 | + | wintoclient(Window w) { |
|
| 1875 | + | Client *c; |
|
| 1876 | + | Monitor *m; |
|
| 1877 | + | ||
| 1878 | + | for(m = mons; m; m = m->next) |
|
| 1879 | + | for(c = m->clients; c; c = c->next) |
|
| 1880 | + | if(c->win == w) |
|
| 1881 | + | return c; |
|
| 1882 | + | return NULL; |
|
| 1883 | + | } |
|
| 1884 | + | ||
| 1885 | + | Monitor * |
|
| 1886 | + | wintomon(Window w) { |
|
| 1887 | + | int x, y; |
|
| 1888 | + | Client *c; |
|
| 1889 | + | Monitor *m; |
|
| 1890 | + | ||
| 1891 | + | if(w == root && getrootpointer(&x, &y)) |
|
| 1892 | + | return pointertomon(x, y); |
|
| 1893 | + | for(m = mons; m; m = m->next) |
|
| 1894 | + | if(w == m->barwin) |
|
| 1895 | + | return m; |
|
| 1896 | + | if((c = wintoclient(w))) |
|
| 1897 | + | return c->mon; |
|
| 1898 | + | return mons; |
|
| 1924 | 1899 | } |
|
| 1925 | 1900 | ||
| 1926 | 1901 | /* There's no way to check accesses to destroyed windows, thus those cases are |
|