34 #include <X11/keysym.h> |
34 #include <X11/keysym.h> |
35 #include <X11/Xatom.h> |
35 #include <X11/Xatom.h> |
36 #include <X11/Xlib.h> |
36 #include <X11/Xlib.h> |
37 #include <X11/Xproto.h> |
37 #include <X11/Xproto.h> |
38 #include <X11/Xutil.h> |
38 #include <X11/Xutil.h> |
|
39 #include <X11/Xft/Xft.h> |
|
40 #include <pango/pango.h> |
|
41 #include <pango/pangoxft.h> |
|
42 #include <pango/pango-font.h> |
39 #ifdef XINERAMA |
43 #ifdef XINERAMA |
40 #include <X11/extensions/Xinerama.h> |
44 #include <X11/extensions/Xinerama.h> |
41 #endif /* XINERAMA */ |
45 #endif /* XINERAMA */ |
42 |
46 |
43 /* macros */ |
47 /* macros */ |
44 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
48 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
45 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) |
49 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) |
46 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) |
50 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) |
47 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
51 #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags])) |
48 #define LENGTH(X) (sizeof X / sizeof X[0]) |
52 #define LENGTH(X) (sizeof X / sizeof X[0]) |
|
53 #ifndef MAX |
49 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
54 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
|
55 #endif |
|
56 #ifndef MIN |
50 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
57 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
|
58 #endif |
51 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
59 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
52 #define WIDTH(X) ((X)->w + 2 * (X)->bw) |
60 #define WIDTH(X) ((X)->w + 2 * (X)->bw) |
53 #define HEIGHT(X) ((X)->h + 2 * (X)->bw) |
61 #define HEIGHT(X) ((X)->h + 2 * (X)->bw) |
54 #define TAGMASK ((1 << LENGTH(tags)) - 1) |
62 #define TAGMASK ((1 << LENGTH(tags)) - 1) |
55 #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height) |
63 #define TEXTW(X) (textnw(X, strlen(X)) + dc.font.height) |
181 static void expose(XEvent *e); |
175 static void expose(XEvent *e); |
182 static void focus(Client *c); |
176 static void focus(Client *c); |
183 static void focusin(XEvent *e); |
177 static void focusin(XEvent *e); |
184 static void focusmon(const Arg *arg); |
178 static void focusmon(const Arg *arg); |
185 static void focusstack(const Arg *arg); |
179 static void focusstack(const Arg *arg); |
186 static unsigned long getcolor(const char *colstr); |
180 static unsigned long getcolor(const char *colstr, XftColor *color); |
187 static Bool getrootptr(int *x, int *y); |
181 static Bool getrootptr(int *x, int *y); |
188 static long getstate(Window w); |
182 static long getstate(Window w); |
189 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
183 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
190 static void grabbuttons(Client *c, Bool focused); |
184 static void grabbuttons(Client *c, Bool focused); |
191 static void grabkeys(void); |
185 static void grabkeys(void); |
275 static Window root; |
269 static Window root; |
276 |
270 |
277 /* configuration, allows nested code to access above variables */ |
271 /* configuration, allows nested code to access above variables */ |
278 #include "config.h" |
272 #include "config.h" |
279 |
273 |
|
274 struct Monitor { |
|
275 char ltsymbol[16]; |
|
276 float mfact; |
|
277 int num; |
|
278 int by; /* bar geometry */ |
|
279 int mx, my, mw, mh; /* screen size */ |
|
280 int wx, wy, ww, wh; /* window area */ |
|
281 unsigned int seltags; |
|
282 unsigned int sellt; |
|
283 unsigned int tagset[2]; |
|
284 Bool showbar; |
|
285 Bool topbar; |
|
286 Client *clients; |
|
287 Client *sel; |
|
288 Client *stack; |
|
289 Monitor *next; |
|
290 Window barwin; |
|
291 const Layout *lt[2]; |
|
292 int curtag; |
|
293 int prevtag; |
|
294 const Layout *lts[LENGTH(tags) + 1]; |
|
295 double mfacts[LENGTH(tags) + 1]; |
|
296 Bool showbars[LENGTH(tags) + 1]; |
|
297 }; |
|
298 |
280 /* compile-time check if all tags fit into an unsigned int bit array. */ |
299 /* compile-time check if all tags fit into an unsigned int bit array. */ |
281 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; |
300 struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; }; |
282 |
301 |
283 /* function implementations */ |
302 /* function implementations */ |
284 void |
303 void |
474 view(&a); |
493 view(&a); |
475 selmon->lt[selmon->sellt] = &foo; |
494 selmon->lt[selmon->sellt] = &foo; |
476 for(m = mons; m; m = m->next) |
495 for(m = mons; m; m = m->next) |
477 while(m->stack) |
496 while(m->stack) |
478 unmanage(m->stack, False); |
497 unmanage(m->stack, False); |
479 if(dc.font.set) |
|
480 XFreeFontSet(dpy, dc.font.set); |
|
481 else |
|
482 XFreeFont(dpy, dc.font.xfont); |
|
483 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
498 XUngrabKey(dpy, AnyKey, AnyModifier, root); |
484 XFreePixmap(dpy, dc.drawable); |
499 XFreePixmap(dpy, dc.drawable); |
485 XFreeGC(dpy, dc.gc); |
500 XFreeGC(dpy, dc.gc); |
486 XFreeCursor(dpy, cursor[CurNormal]); |
501 XFreeCursor(dpy, cursor[CurNormal]); |
487 XFreeCursor(dpy, cursor[CurResize]); |
502 XFreeCursor(dpy, cursor[CurResize]); |
547 sh = ev->height; |
562 sh = ev->height; |
548 if(updategeom()) { |
563 if(updategeom()) { |
549 if(dc.drawable != 0) |
564 if(dc.drawable != 0) |
550 XFreePixmap(dpy, dc.drawable); |
565 XFreePixmap(dpy, dc.drawable); |
551 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
566 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
|
567 XftDrawChange(dc.xftdrawable, dc.drawable); |
552 updatebars(); |
568 updatebars(); |
553 for(m = mons; m; m = m->next) |
569 for(m = mons; m; m = m->next) |
554 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
570 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
555 arrange(NULL); |
571 arrange(NULL); |
556 } |
572 } |
603 } |
619 } |
604 |
620 |
605 Monitor * |
621 Monitor * |
606 createmon(void) { |
622 createmon(void) { |
607 Monitor *m; |
623 Monitor *m; |
|
624 unsigned int i; |
608 |
625 |
609 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
626 if(!(m = (Monitor *)calloc(1, sizeof(Monitor)))) |
610 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
627 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
611 m->tagset[0] = m->tagset[1] = 1; |
628 m->tagset[0] = m->tagset[1] = 1; |
612 m->mfact = mfact; |
629 m->mfact = mfact; |
613 m->showbar = showbar; |
630 m->showbar = showbar; |
614 m->topbar = topbar; |
631 m->topbar = topbar; |
615 m->lt[0] = &layouts[0]; |
632 m->lt[0] = &layouts[0]; |
616 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
633 m->lt[1] = &layouts[1 % LENGTH(layouts)]; |
617 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
634 strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol); |
|
635 |
|
636 /* pertag init */ |
|
637 m->curtag = m->prevtag = 1; |
|
638 for(i=0; i < LENGTH(tags) + 1 ; i++) { |
|
639 m->mfacts[i] = mfact; |
|
640 m->lts[i] = i ? &layouts[deflayouts[i-1]] : &layouts[0]; |
|
641 m->showbars[i] = m->showbar; |
|
642 } |
|
643 |
618 return m; |
644 return m; |
619 } |
645 } |
620 |
646 |
621 void |
647 void |
622 destroynotify(XEvent *e) { |
648 destroynotify(XEvent *e) { |
764 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
790 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
765 if(!text) |
791 if(!text) |
766 return; |
792 return; |
767 olen = strlen(text); |
793 olen = strlen(text); |
768 h = dc.font.ascent + dc.font.descent; |
794 h = dc.font.ascent + dc.font.descent; |
769 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
795 //y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
|
796 y = dc.y; |
770 x = dc.x + (h / 2); |
797 x = dc.x + (h / 2); |
771 /* shorten text if necessary */ |
798 /* shorten text if necessary */ |
772 for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--); |
799 for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--); |
773 if(!len) |
800 if(!len) |
774 return; |
801 return; |
775 memcpy(buf, text, len); |
802 memcpy(buf, text, len); |
776 if(len < olen) |
803 if(len < olen) |
777 for(i = len; i && i > len - 3; buf[--i] = '.'); |
804 for(i = len; i && i > len - 3; buf[--i] = '.'); |
778 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); |
805 pango_layout_set_text(dc.plo, text, len); |
779 if(dc.font.set) |
806 pango_xft_render_layout(dc.xftdrawable, (col==dc.norm?dc.xftnorm:dc.xftsel)+(invert?ColBG:ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE); |
780 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); |
|
781 else |
|
782 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
|
783 } |
807 } |
784 |
808 |
785 void |
809 void |
786 enternotify(XEvent *e) { |
810 enternotify(XEvent *e) { |
787 Monitor *m; |
811 Monitor *m; |
875 restack(selmon); |
899 restack(selmon); |
876 } |
900 } |
877 } |
901 } |
878 |
902 |
879 unsigned long |
903 unsigned long |
880 getcolor(const char *colstr) { |
904 getcolor(const char *colstr, XftColor *color) { |
881 Colormap cmap = DefaultColormap(dpy, screen); |
905 Colormap cmap = DefaultColormap(dpy, screen); |
882 XColor color; |
906 Visual *vis = DefaultVisual(dpy, screen); |
883 |
907 |
884 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) |
908 if(!XftColorAllocName(dpy,vis,cmap,colstr, color)) |
885 die("error, cannot allocate color '%s'\n", colstr); |
909 die("error, cannot allocate color '%s'\n", colstr); |
886 return color.pixel; |
910 return color->pixel; |
887 } |
911 } |
888 |
912 |
889 Bool |
913 Bool |
890 getrootptr(int *x, int *y) { |
914 getrootptr(int *x, int *y) { |
891 int di; |
915 int di; |
977 } |
1001 } |
978 } |
1002 } |
979 |
1003 |
980 void |
1004 void |
981 initfont(const char *fontstr) { |
1005 initfont(const char *fontstr) { |
982 char *def, **missing; |
1006 PangoFontMetrics *metrics; |
983 int n; |
1007 |
984 |
1008 dc.pgc = pango_xft_get_context(dpy, screen); |
985 missing = NULL; |
1009 dc.pfd = pango_font_description_from_string(fontstr); |
986 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
1010 |
987 if(missing) { |
1011 metrics = pango_context_get_metrics(dc.pgc, dc.pfd, pango_language_from_string(setlocale(LC_CTYPE, ""))); |
988 while(n--) |
1012 dc.font.ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; |
989 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
1013 dc.font.descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE; |
990 XFreeStringList(missing); |
1014 |
991 } |
1015 pango_font_metrics_unref(metrics); |
992 if(dc.font.set) { |
1016 |
993 XFontStruct **xfonts; |
1017 dc.plo = pango_layout_new(dc.pgc); |
994 char **font_names; |
1018 pango_layout_set_font_description(dc.plo, dc.pfd); |
995 |
|
996 dc.font.ascent = dc.font.descent = 0; |
|
997 XExtentsOfFontSet(dc.font.set); |
|
998 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); |
|
999 while(n--) { |
|
1000 dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent); |
|
1001 dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent); |
|
1002 xfonts++; |
|
1003 } |
|
1004 } |
|
1005 else { |
|
1006 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) |
|
1007 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) |
|
1008 die("error, cannot load font: '%s'\n", fontstr); |
|
1009 dc.font.ascent = dc.font.xfont->ascent; |
|
1010 dc.font.descent = dc.font.xfont->descent; |
|
1011 } |
|
1012 dc.font.height = dc.font.ascent + dc.font.descent; |
1019 dc.font.height = dc.font.ascent + dc.font.descent; |
1013 } |
1020 } |
1014 |
1021 |
1015 Bool |
1022 Bool |
1016 isprotodel(Client *c) { |
1023 isprotodel(Client *c) { |
1524 /* init cursors */ |
1531 /* init cursors */ |
1525 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1532 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1526 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1533 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1527 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1534 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1528 /* init appearance */ |
1535 /* init appearance */ |
1529 dc.norm[ColBorder] = getcolor(normbordercolor); |
1536 dc.norm[ColBorder] = getcolor(normbordercolor, dc.xftnorm+ColBorder); |
1530 dc.norm[ColBG] = getcolor(normbgcolor); |
1537 dc.norm[ColBG] = getcolor(normbgcolor, dc.xftnorm+ColBG); |
1531 dc.norm[ColFG] = getcolor(normfgcolor); |
1538 dc.norm[ColFG] = getcolor(normfgcolor, dc.xftnorm+ColFG); |
1532 dc.sel[ColBorder] = getcolor(selbordercolor); |
1539 dc.sel[ColBorder] = getcolor(selbordercolor, dc.xftsel+ColBorder); |
1533 dc.sel[ColBG] = getcolor(selbgcolor); |
1540 dc.sel[ColBG] = getcolor(selbgcolor, dc.xftsel+ColBG); |
1534 dc.sel[ColFG] = getcolor(selfgcolor); |
1541 dc.sel[ColFG] = getcolor(selfgcolor, dc.xftsel+ColFG); |
1535 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); |
1542 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); |
1536 dc.gc = XCreateGC(dpy, root, 0, NULL); |
1543 dc.gc = XCreateGC(dpy, root, 0, NULL); |
1537 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1544 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1538 if(!dc.font.set) |
1545 dc.xftdrawable = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy,screen), DefaultColormap(dpy,screen)); |
1539 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1546 if(!dc.xftdrawable) |
1540 /* init bars */ |
1547 printf("error, cannot create drawable\n"); |
1541 updatebars(); |
1548 updatebars(); |
1542 updatestatus(); |
1549 updatestatus(); |
1543 /* EWMH support per view */ |
1550 /* EWMH support per view */ |
1544 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1551 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1545 PropModeReplace, (unsigned char *) netatom, NetLast); |
1552 PropModeReplace, (unsigned char *) netatom, NetLast); |
1604 sendmon(selmon->sel, dirtomon(arg->i)); |
1611 sendmon(selmon->sel, dirtomon(arg->i)); |
1605 } |
1612 } |
1606 |
1613 |
1607 int |
1614 int |
1608 textnw(const char *text, unsigned int len) { |
1615 textnw(const char *text, unsigned int len) { |
1609 XRectangle r; |
1616 PangoRectangle r; |
1610 |
1617 pango_layout_set_text(dc.plo, text, len); |
1611 if(dc.font.set) { |
1618 pango_layout_get_extents(dc.plo, &r, 0); |
1612 XmbTextExtents(dc.font.set, text, len, NULL, &r); |
1619 return r.width / PANGO_SCALE; |
1613 return r.width; |
|
1614 } |
|
1615 return XTextWidth(dc.font.xfont, text, len); |
|
1616 } |
1620 } |
1617 |
1621 |
1618 void |
1622 void |
1619 tile(Monitor *m) { |
1623 tile(Monitor *m) { |
1620 int x, y, h, w, mw; |
1624 int x, y, h, w, mw; |
1665 } |
1669 } |
1666 |
1670 |
1667 void |
1671 void |
1668 toggletag(const Arg *arg) { |
1672 toggletag(const Arg *arg) { |
1669 unsigned int newtags; |
1673 unsigned int newtags; |
|
1674 unsigned int i; |
1670 |
1675 |
1671 if(!selmon->sel) |
1676 if(!selmon->sel) |
1672 return; |
1677 return; |
1673 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); |
1678 newtags = selmon->sel->tags ^ (arg->ui & TAGMASK); |
1674 if(newtags) { |
1679 if(newtags) { |
1675 selmon->sel->tags = newtags; |
1680 selmon->sel->tags = newtags; |
|
1681 if(newtags == ~0) { |
|
1682 selmon->prevtag = selmon->curtag; |
|
1683 selmon->curtag = 0; |
|
1684 } |
|
1685 if(!(newtags & 1 << (selmon->curtag - 1))) { |
|
1686 selmon->prevtag = selmon->curtag; |
|
1687 for (i=0; !(newtags & 1 << i); i++); |
|
1688 selmon->curtag = i + 1; |
|
1689 } |
|
1690 selmon->sel->tags = newtags; |
|
1691 selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag]; |
|
1692 selmon->mfact = selmon->mfacts[selmon->curtag]; |
|
1693 if (selmon->showbar != selmon->showbars[selmon->curtag]) |
|
1694 togglebar(NULL); |
1676 arrange(selmon); |
1695 arrange(selmon); |
1677 } |
1696 } |
1678 } |
1697 } |
1679 |
1698 |
1680 void |
1699 void |
1937 } |
1956 } |
1938 } |
1957 } |
1939 |
1958 |
1940 void |
1959 void |
1941 view(const Arg *arg) { |
1960 view(const Arg *arg) { |
|
1961 unsigned int i; |
|
1962 |
1942 if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) |
1963 if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags]) |
1943 return; |
1964 return; |
1944 selmon->seltags ^= 1; /* toggle sel tagset */ |
1965 selmon->seltags ^= 1; /* toggle sel tagset */ |
1945 if(arg->ui & TAGMASK) |
1966 if(arg->ui & TAGMASK) { |
1946 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
1967 selmon->tagset[selmon->seltags] = arg->ui & TAGMASK; |
|
1968 selmon->prevtag = selmon->curtag; |
|
1969 if(arg->ui == ~0) |
|
1970 selmon->curtag = 0; |
|
1971 else { |
|
1972 for (i=0; !(arg->ui & 1 << i); i++); |
|
1973 selmon->curtag = i + 1; |
|
1974 } |
|
1975 } else { |
|
1976 selmon->prevtag= selmon->curtag ^ selmon->prevtag; |
|
1977 selmon->curtag^= selmon->prevtag; |
|
1978 selmon->prevtag= selmon->curtag ^ selmon->prevtag; |
|
1979 } |
|
1980 selmon->lt[selmon->sellt]= selmon->lts[selmon->curtag]; |
|
1981 selmon->mfact = selmon->mfacts[selmon->curtag]; |
|
1982 if(selmon->showbar != selmon->showbars[selmon->curtag]) |
|
1983 togglebar(NULL); |
1947 arrange(selmon); |
1984 arrange(selmon); |
1948 } |
1985 } |
1949 |
1986 |
1950 Client * |
1987 Client * |
1951 wintoclient(Window w) { |
1988 wintoclient(Window w) { |