154 void focus(Client *c); |
153 void focus(Client *c); |
155 void focusin(XEvent *e); |
154 void focusin(XEvent *e); |
156 void focusnext(const char *arg); |
155 void focusnext(const char *arg); |
157 void focusprev(const char *arg); |
156 void focusprev(const char *arg); |
158 Client *getclient(Window w); |
157 Client *getclient(Window w); |
159 unsigned long getcolor(const char *colstr, int screen); |
158 unsigned long getcolor(const char *colstr); |
160 long getstate(Window w); |
159 long getstate(Window w); |
161 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
160 Bool gettextprop(Window w, Atom atom, char *text, unsigned int size); |
162 void grabbuttons(Client *c, Bool focused); |
161 void grabbuttons(Client *c, Bool focused); |
163 void grabkeys(void); |
162 void grabkeys(void); |
164 unsigned int idxoftag(const char *tag); |
163 unsigned int idxoftag(const char *tag); |
165 void initfont(Monitor*, const char *fontstr); |
164 void initfont(const char *fontstr); |
166 Bool isoccupied(unsigned int monitor, unsigned int t); |
165 Bool isoccupied(unsigned int monitor, unsigned int t); |
167 Bool isprotodel(Client *c); |
166 Bool isprotodel(Client *c); |
168 Bool isurgent(unsigned int monitor, unsigned int t); |
167 Bool isurgent(unsigned int monitor, unsigned int t); |
169 Bool isvisible(Client *c, int monitor); |
168 Bool isvisible(Client *c, int monitor); |
170 void keypress(XEvent *e); |
169 void keypress(XEvent *e); |
564 int i, j, x; |
564 int i, j, x; |
565 Client *c; |
565 Client *c; |
566 |
566 |
567 for(i = 0; i < mcount; i++) { |
567 for(i = 0; i < mcount; i++) { |
568 Monitor *m = &monitors[i]; |
568 Monitor *m = &monitors[i]; |
569 m->dc.x = 0; |
569 dc.x = 0; |
570 for(c = stack; c && !isvisible(c, i); c = c->snext); |
570 for(c = stack; c && !isvisible(c, i); c = c->snext); |
571 fprintf(stderr, "m%d %s\n", i, c ? c->name : "NIL"); |
571 fprintf(stderr, "m%d %s\n", i, c ? c->name : "NIL"); |
572 for(j = 0; j < LENGTH(tags); j++) { |
572 for(j = 0; j < LENGTH(tags); j++) { |
573 m->dc.w = textw(m, tags[j]); |
573 dc.w = textw(tags[j]); |
574 if(m->seltags[j]) { |
574 if(m->seltags[j]) { |
575 drawtext(m, tags[j], m->dc.sel, isurgent(i, j)); |
575 drawtext(m, tags[j], dc.sel, isurgent(i, j)); |
576 drawsquare(m, c && c->tags[j] && c->monitor == i, |
576 drawsquare(m, c && c->tags[j] && c->monitor == i, |
577 isoccupied(i, j), isurgent(i, j), m->dc.sel); |
577 isoccupied(i, j), isurgent(i, j), dc.sel); |
578 } |
578 } |
579 else { |
579 else { |
580 drawtext(m, tags[j], m->dc.norm, isurgent(i, j)); |
580 drawtext(m, tags[j], dc.norm, isurgent(i, j)); |
581 drawsquare(m, c && c->tags[j] && c->monitor == i, |
581 drawsquare(m, c && c->tags[j] && c->monitor == i, |
582 isoccupied(i, j), isurgent(i, j), m->dc.norm); |
582 isoccupied(i, j), isurgent(i, j), dc.norm); |
583 } |
583 } |
584 m->dc.x += m->dc.w; |
584 dc.x += dc.w; |
585 } |
585 } |
586 m->dc.w = blw; |
586 dc.w = blw; |
587 drawtext(m, m->layout->symbol, m->dc.norm, False); |
587 drawtext(m, m->layout->symbol, dc.norm, False); |
588 x = m->dc.x + m->dc.w; |
588 x = dc.x + dc.w; |
589 if(i == selmonitor) { |
589 if(i == selmonitor) { |
590 m->dc.w = textw(m, stext); |
590 dc.w = textw(stext); |
591 m->dc.x = m->sw - m->dc.w; |
591 dc.x = m->sw - dc.w; |
592 if(m->dc.x < x) { |
592 if(dc.x < x) { |
593 m->dc.x = x; |
593 dc.x = x; |
594 m->dc.w = m->sw - x; |
594 dc.w = m->sw - x; |
595 } |
595 } |
596 drawtext(m, stext, m->dc.norm, False); |
596 drawtext(m, stext, dc.norm, False); |
597 } |
597 } |
598 else |
598 else |
599 m->dc.x = m->sw; |
599 dc.x = m->sw; |
600 if((m->dc.w = m->dc.x - x) > bh) { |
600 if((dc.w = dc.x - x) > bh) { |
601 m->dc.x = x; |
601 dc.x = x; |
602 if(c) { |
602 if(c) { |
603 drawtext(m, c->name, m->dc.sel, False); |
603 drawtext(m, c->name, dc.sel, False); |
604 drawsquare(m, False, c->isfloating, False, m->dc.sel); |
604 drawsquare(m, False, c->isfloating, False, dc.sel); |
605 } |
605 } |
606 else |
606 else |
607 drawtext(m, NULL, m->dc.norm, False); |
607 drawtext(m, NULL, dc.norm, False); |
608 } |
608 } |
609 XCopyArea(dpy, m->dc.drawable, m->barwin, m->dc.gc, 0, 0, m->sw, bh, 0, 0); |
609 XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->sw, bh, 0, 0); |
610 XSync(dpy, False); |
610 XSync(dpy, False); |
611 } |
611 } |
612 } |
612 } |
613 |
613 |
614 void |
614 void |
615 drawsquare(Monitor *m, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
615 drawsquare(Monitor *m, Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) { |
616 int x; |
616 int x; |
617 XGCValues gcv; |
617 XGCValues gcv; |
618 XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h }; |
618 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
619 |
619 |
620 gcv.foreground = col[invert ? ColBG : ColFG]; |
620 gcv.foreground = col[invert ? ColBG : ColFG]; |
621 XChangeGC(dpy, m->dc.gc, GCForeground, &gcv); |
621 XChangeGC(dpy, dc.gc, GCForeground, &gcv); |
622 x = (m->dc.font.ascent + m->dc.font.descent + 2) / 4; |
622 x = (dc.font.ascent + dc.font.descent + 2) / 4; |
623 r.x = m->dc.x + 1; |
623 r.x = dc.x + 1; |
624 r.y = m->dc.y + 1; |
624 r.y = dc.y + 1; |
625 if(filled) { |
625 if(filled) { |
626 r.width = r.height = x + 1; |
626 r.width = r.height = x + 1; |
627 XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
627 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
628 } |
628 } |
629 else if(empty) { |
629 else if(empty) { |
630 r.width = r.height = x; |
630 r.width = r.height = x; |
631 XDrawRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
631 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
632 } |
632 } |
633 } |
633 } |
634 |
634 |
635 void |
635 void |
636 drawtext(Monitor *m, const char *text, unsigned long col[ColLast], Bool invert) { |
636 drawtext(Monitor *m, const char *text, unsigned long col[ColLast], Bool invert) { |
637 int x, y, w, h; |
637 int x, y, w, h; |
638 static char buf[256]; |
638 static char buf[256]; |
639 unsigned int len, olen; |
639 unsigned int len, olen; |
640 XRectangle r = { m->dc.x, m->dc.y, m->dc.w, m->dc.h }; |
640 XRectangle r = { dc.x, dc.y, dc.w, dc.h }; |
641 |
641 |
642 XSetForeground(dpy, m->dc.gc, col[invert ? ColFG : ColBG]); |
642 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]); |
643 XFillRectangles(dpy, m->dc.drawable, m->dc.gc, &r, 1); |
643 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1); |
644 if(!text) |
644 if(!text) |
645 return; |
645 return; |
646 w = 0; |
646 w = 0; |
647 olen = len = strlen(text); |
647 olen = len = strlen(text); |
648 if(len >= sizeof buf) |
648 if(len >= sizeof buf) |
649 len = sizeof buf - 1; |
649 len = sizeof buf - 1; |
650 memcpy(buf, text, len); |
650 memcpy(buf, text, len); |
651 buf[len] = 0; |
651 buf[len] = 0; |
652 h = m->dc.font.ascent + m->dc.font.descent; |
652 h = dc.font.ascent + dc.font.descent; |
653 y = m->dc.y + (m->dc.h / 2) - (h / 2) + m->dc.font.ascent; |
653 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent; |
654 x = m->dc.x + (h / 2); |
654 x = dc.x + (h / 2); |
655 /* shorten text if necessary */ |
655 /* shorten text if necessary */ |
656 while(len && (w = textnw(m, buf, len)) > m->dc.w - h) |
656 while(len && (w = textnw(buf, len)) > dc.w - h) |
657 buf[--len] = 0; |
657 buf[--len] = 0; |
658 if(len < olen) { |
658 if(len < olen) { |
659 if(len > 1) |
659 if(len > 1) |
660 buf[len - 1] = '.'; |
660 buf[len - 1] = '.'; |
661 if(len > 2) |
661 if(len > 2) |
662 buf[len - 2] = '.'; |
662 buf[len - 2] = '.'; |
663 if(len > 3) |
663 if(len > 3) |
664 buf[len - 3] = '.'; |
664 buf[len - 3] = '.'; |
665 } |
665 } |
666 if(w > m->dc.w) |
666 if(w > dc.w) |
667 return; /* too long */ |
667 return; /* too long */ |
668 XSetForeground(dpy, m->dc.gc, col[invert ? ColBG : ColFG]); |
668 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]); |
669 if(m->dc.font.set) |
669 if(dc.font.set) |
670 XmbDrawString(dpy, m->dc.drawable, m->dc.font.set, m->dc.gc, x, y, buf, len); |
670 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len); |
671 else |
671 else |
672 XDrawString(dpy, m->dc.drawable, m->dc.gc, x, y, buf, len); |
672 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
673 } |
673 } |
674 |
674 |
675 void * |
675 void * |
676 emallocz(unsigned int size) { |
676 emallocz(unsigned int size) { |
677 void *res = calloc(1, size); |
677 void *res = calloc(1, size); |
935 for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++); |
935 for(i = 0; (i < LENGTH(tags)) && (tags[i] != tag); i++); |
936 return (i < LENGTH(tags)) ? i : 0; |
936 return (i < LENGTH(tags)) ? i : 0; |
937 } |
937 } |
938 |
938 |
939 void |
939 void |
940 initfont(Monitor *m, const char *fontstr) { |
940 initfont(const char *fontstr) { |
941 char *def, **missing; |
941 char *def, **missing; |
942 int i, n; |
942 int i, n; |
943 |
943 |
944 missing = NULL; |
944 missing = NULL; |
945 if(m->dc.font.set) |
945 if(dc.font.set) |
946 XFreeFontSet(dpy, m->dc.font.set); |
946 XFreeFontSet(dpy, dc.font.set); |
947 m->dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
947 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def); |
948 if(missing) { |
948 if(missing) { |
949 while(n--) |
949 while(n--) |
950 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
950 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]); |
951 XFreeStringList(missing); |
951 XFreeStringList(missing); |
952 } |
952 } |
953 if(m->dc.font.set) { |
953 if(dc.font.set) { |
954 XFontSetExtents *font_extents; |
954 XFontSetExtents *font_extents; |
955 XFontStruct **xfonts; |
955 XFontStruct **xfonts; |
956 char **font_names; |
956 char **font_names; |
957 m->dc.font.ascent = m->dc.font.descent = 0; |
957 dc.font.ascent = dc.font.descent = 0; |
958 font_extents = XExtentsOfFontSet(m->dc.font.set); |
958 font_extents = XExtentsOfFontSet(dc.font.set); |
959 n = XFontsOfFontSet(m->dc.font.set, &xfonts, &font_names); |
959 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names); |
960 for(i = 0, m->dc.font.ascent = 0, m->dc.font.descent = 0; i < n; i++) { |
960 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) { |
961 if(m->dc.font.ascent < (*xfonts)->ascent) |
961 if(dc.font.ascent < (*xfonts)->ascent) |
962 m->dc.font.ascent = (*xfonts)->ascent; |
962 dc.font.ascent = (*xfonts)->ascent; |
963 if(m->dc.font.descent < (*xfonts)->descent) |
963 if(dc.font.descent < (*xfonts)->descent) |
964 m->dc.font.descent = (*xfonts)->descent; |
964 dc.font.descent = (*xfonts)->descent; |
965 xfonts++; |
965 xfonts++; |
966 } |
966 } |
967 } |
967 } |
968 else { |
968 else { |
969 if(m->dc.font.xfont) |
969 if(dc.font.xfont) |
970 XFreeFont(dpy, m->dc.font.xfont); |
970 XFreeFont(dpy, dc.font.xfont); |
971 m->dc.font.xfont = NULL; |
971 dc.font.xfont = NULL; |
972 if(!(m->dc.font.xfont = XLoadQueryFont(dpy, fontstr)) |
972 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)) |
973 && !(m->dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) |
973 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed"))) |
974 eprint("error, cannot load font: '%s'\n", fontstr); |
974 eprint("error, cannot load font: '%s'\n", fontstr); |
975 m->dc.font.ascent = m->dc.font.xfont->ascent; |
975 dc.font.ascent = dc.font.xfont->ascent; |
976 m->dc.font.descent = m->dc.font.xfont->descent; |
976 dc.font.descent = dc.font.xfont->descent; |
977 } |
977 } |
978 m->dc.font.height = m->dc.font.ascent + m->dc.font.descent; |
978 dc.font.height = dc.font.ascent + dc.font.descent; |
979 } |
979 } |
980 |
980 |
981 Bool |
981 Bool |
982 isoccupied(unsigned int monitor, unsigned int t) { |
982 isoccupied(unsigned int monitor, unsigned int t) { |
983 Client *c; |
983 Client *c; |
1571 mcount = 1; |
1571 mcount = 1; |
1572 if((isxinerama = XineramaIsActive(dpy))) |
1572 if((isxinerama = XineramaIsActive(dpy))) |
1573 info = XineramaQueryScreens(dpy, &mcount); |
1573 info = XineramaQueryScreens(dpy, &mcount); |
1574 monitors = emallocz(mcount * sizeof(Monitor)); |
1574 monitors = emallocz(mcount * sizeof(Monitor)); |
1575 |
1575 |
1576 root = DefaultRootWindow(dpy); |
1576 screen = DefaultScreen(dpy); |
1577 |
1577 root = RootWindow(dpy, screen); |
|
1578 |
|
1579 /* init appearance */ |
|
1580 dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR); |
|
1581 dc.norm[ColBG] = getcolor(NORMBGCOLOR); |
|
1582 dc.norm[ColFG] = getcolor(NORMFGCOLOR); |
|
1583 dc.sel[ColBorder] = getcolor(SELBORDERCOLOR); |
|
1584 dc.sel[ColBG] = getcolor(SELBGCOLOR); |
|
1585 dc.sel[ColFG] = getcolor(SELFGCOLOR); |
|
1586 initfont(FONT); |
|
1587 dc.h = bh = dc.font.height + 2; |
|
1588 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen)); |
|
1589 dc.gc = XCreateGC(dpy, root, 0, 0); |
|
1590 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
|
1591 if(!dc.font.set) |
|
1592 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
|
1593 |
|
1594 for(blw = i = 0; i < LENGTH(layouts); i++) { |
|
1595 i = textw(layouts[i].symbol); |
|
1596 if(i > blw) |
|
1597 blw = i; |
|
1598 } |
1578 for(i = 0; i < mcount; i++) { |
1599 for(i = 0; i < mcount; i++) { |
1579 /* init geometry */ |
1600 /* init geometry */ |
1580 m = &monitors[i]; |
1601 m = &monitors[i]; |
1581 |
1602 |
1582 m->screen = isxinerama ? 0 : i; |
1603 m->monitor = i; |
1583 |
1604 |
1584 if (mcount != 1 && isxinerama) { |
1605 if (mcount != 1 && isxinerama) { |
1585 m->sx = info[i].x_org; |
1606 m->sx = info[i].x_org; |
1586 m->sy = info[i].y_org; |
1607 m->sy = info[i].y_org; |
1587 m->sw = info[i].width; |
1608 m->sw = info[i].width; |
1589 fprintf(stderr, "monitor[%d]: %d,%d,%d,%d\n", i, m->sx, m->sy, m->sw, m->sh); |
1610 fprintf(stderr, "monitor[%d]: %d,%d,%d,%d\n", i, m->sx, m->sy, m->sw, m->sh); |
1590 } |
1611 } |
1591 else { |
1612 else { |
1592 m->sx = 0; |
1613 m->sx = 0; |
1593 m->sy = 0; |
1614 m->sy = 0; |
1594 m->sw = DisplayWidth(dpy, m->screen); |
1615 m->sw = DisplayWidth(dpy, screen); |
1595 m->sh = DisplayHeight(dpy, m->screen); |
1616 m->sh = DisplayHeight(dpy, screen); |
1596 } |
1617 } |
1597 |
1618 |
1598 m->seltags = emallocz(sizeof initags); |
1619 m->seltags = emallocz(sizeof initags); |
1599 m->prevtags = emallocz(sizeof initags); |
1620 m->prevtags = emallocz(sizeof initags); |
1600 |
1621 |
1601 memcpy(m->seltags, initags, sizeof initags); |
1622 memcpy(m->seltags, initags, sizeof initags); |
1602 memcpy(m->prevtags, initags, sizeof initags); |
1623 memcpy(m->prevtags, initags, sizeof initags); |
1603 |
|
1604 /* init appearance */ |
|
1605 m->dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR, m->screen); |
|
1606 m->dc.norm[ColBG] = getcolor(NORMBGCOLOR, m->screen); |
|
1607 m->dc.norm[ColFG] = getcolor(NORMFGCOLOR, m->screen); |
|
1608 m->dc.sel[ColBorder] = getcolor(SELBORDERCOLOR, m->screen); |
|
1609 m->dc.sel[ColBG] = getcolor(SELBGCOLOR, m->screen); |
|
1610 m->dc.sel[ColFG] = getcolor(SELFGCOLOR, m->screen); |
|
1611 initfont(m, FONT); |
|
1612 m->dc.h = bh = m->dc.font.height + 2; |
|
1613 |
1624 |
1614 /* init layouts */ |
1625 /* init layouts */ |
1615 m->mwfact = MWFACT; |
1626 m->mwfact = MWFACT; |
1616 m->layout = &layouts[0]; |
1627 m->layout = &layouts[0]; |
1617 for(blw = k = 0; k < LENGTH(layouts); k++) { |
|
1618 j = textw(m, layouts[k].symbol); |
|
1619 if(j > blw) |
|
1620 blw = j; |
|
1621 } |
|
1622 |
1628 |
1623 // TODO: bpos per screen? |
1629 // TODO: bpos per screen? |
1624 bpos = BARPOS; |
1630 bpos = BARPOS; |
1625 wa.override_redirect = 1; |
1631 wa.override_redirect = 1; |
1626 wa.background_pixmap = ParentRelative; |
1632 wa.background_pixmap = ParentRelative; |
1627 wa.event_mask = ButtonPressMask | ExposureMask; |
1633 wa.event_mask = ButtonPressMask | ExposureMask; |
1628 |
1634 |
1629 /* init bars */ |
1635 /* init bars */ |
1630 m->barwin = XCreateWindow(dpy, root, m->sx, m->sy, m->sw, bh, 0, |
1636 m->barwin = XCreateWindow(dpy, root, m->sx, m->sy, m->sw, bh, 0, |
1631 DefaultDepth(dpy, m->screen), CopyFromParent, DefaultVisual(dpy, m->screen), |
1637 DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), |
1632 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
1638 CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); |
1633 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1639 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
1634 updatebarpos(m); |
1640 updatebarpos(m); |
1635 XMapRaised(dpy, m->barwin); |
1641 XMapRaised(dpy, m->barwin); |
1636 strcpy(stext, "dwm-"VERSION); |
1642 strcpy(stext, "dwm-"VERSION); |
1637 m->dc.drawable = XCreatePixmap(dpy, root, m->sw, bh, DefaultDepth(dpy, m->screen)); |
|
1638 m->dc.gc = XCreateGC(dpy, root, 0, 0); |
|
1639 XSetLineAttributes(dpy, m->dc.gc, 1, LineSolid, CapButt, JoinMiter); |
|
1640 if(!m->dc.font.set) |
|
1641 XSetFont(dpy, m->dc.gc, m->dc.font.xfont->fid); |
|
1642 |
1643 |
1643 /* EWMH support per monitor */ |
1644 /* EWMH support per monitor */ |
1644 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1645 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1645 PropModeReplace, (unsigned char *) netatom, NetLast); |
1646 PropModeReplace, (unsigned char *) netatom, NetLast); |
1646 |
1647 |