42 |
42 |
43 /* macros */ |
43 /* macros */ |
44 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
44 #define BUTTONMASK (ButtonPressMask|ButtonReleaseMask) |
45 #define CLEANMASK(mask) (mask & ~(numlockmask|LockMask)) |
45 #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)) |
46 #define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH)) |
47 #define ISVISIBLE(M, C) ((M) == (&mon[C->mon]) && (C->tags & M->tagset[M->seltags])) |
47 #define ISVISIBLE(M, C) ((M) == (C->m) && (C->tags & M->tagset[M->seltags])) |
48 #define LENGTH(X) (sizeof X / sizeof X[0]) |
48 #define LENGTH(X) (sizeof X / sizeof X[0]) |
49 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
49 #define MAX(A, B) ((A) > (B) ? (A) : (B)) |
50 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
50 #define MIN(A, B) ((A) < (B) ? (A) : (B)) |
51 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
51 #define MOUSEMASK (BUTTONMASK|PointerMotionMask) |
52 #define WIDTH(X) ((X)->w + 2 * (X)->bw) |
52 #define WIDTH(X) ((X)->w + 2 * (X)->bw) |
147 static void attach(Client *c); |
149 static void attach(Client *c); |
148 static void attachstack(Client *c); |
150 static void attachstack(Client *c); |
149 static void buttonpress(XEvent *e); |
151 static void buttonpress(XEvent *e); |
150 static void checkotherwm(void); |
152 static void checkotherwm(void); |
151 static void cleanup(void); |
153 static void cleanup(void); |
|
154 static void cleanupmons(void); |
152 static void clearurgent(Client *c); |
155 static void clearurgent(Client *c); |
153 static void configure(Client *c); |
156 static void configure(Client *c); |
154 static void configurenotify(XEvent *e); |
157 static void configurenotify(XEvent *e); |
155 static void configurerequest(XEvent *e); |
158 static void configurerequest(XEvent *e); |
156 static void destroynotify(XEvent *e); |
159 static void destroynotify(XEvent *e); |
204 static void toggletag(const Arg *arg); |
207 static void toggletag(const Arg *arg); |
205 static void toggleview(const Arg *arg); |
208 static void toggleview(const Arg *arg); |
206 static void unmanage(Client *c); |
209 static void unmanage(Client *c); |
207 static void unmapnotify(XEvent *e); |
210 static void unmapnotify(XEvent *e); |
208 static void updategeom(void); |
211 static void updategeom(void); |
|
212 static void updatebars(void); |
209 static void updatenumlockmask(void); |
213 static void updatenumlockmask(void); |
210 static void updatesizehints(Client *c); |
214 static void updatesizehints(Client *c); |
211 static void updatestatus(void); |
215 static void updatestatus(void); |
212 static void updatetitle(Client *c); |
216 static void updatetitle(Client *c); |
213 static void updatewmhints(Client *c); |
217 static void updatewmhints(Client *c); |
445 XFreePixmap(dpy, dc.drawable); |
448 XFreePixmap(dpy, dc.drawable); |
446 XFreeGC(dpy, dc.gc); |
449 XFreeGC(dpy, dc.gc); |
447 XFreeCursor(dpy, cursor[CurNormal]); |
450 XFreeCursor(dpy, cursor[CurNormal]); |
448 XFreeCursor(dpy, cursor[CurResize]); |
451 XFreeCursor(dpy, cursor[CurResize]); |
449 XFreeCursor(dpy, cursor[CurMove]); |
452 XFreeCursor(dpy, cursor[CurMove]); |
450 for(i = 0; i < nmons; i++) |
453 cleanupmons(); |
451 XDestroyWindow(dpy, mon[i].barwin); |
|
452 free(mon); |
|
453 XSync(dpy, False); |
454 XSync(dpy, False); |
454 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
455 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); |
|
456 } |
|
457 |
|
458 void |
|
459 cleanupmons(void) { |
|
460 Monitor *m; |
|
461 |
|
462 while(mons) { |
|
463 m = mons->next; |
|
464 XUnmapWindow(dpy, mons->barwin); |
|
465 XDestroyWindow(dpy, mons->barwin); |
|
466 free(mons); |
|
467 mons = m; |
|
468 } |
455 } |
469 } |
456 |
470 |
457 void |
471 void |
458 clearurgent(Client *c) { |
472 clearurgent(Client *c) { |
459 XWMHints *wmh; |
473 XWMHints *wmh; |
484 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); |
498 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce); |
485 } |
499 } |
486 |
500 |
487 void |
501 void |
488 configurenotify(XEvent *e) { |
502 configurenotify(XEvent *e) { |
489 unsigned int i; |
503 Monitor *m; |
490 XConfigureEvent *ev = &e->xconfigure; |
504 XConfigureEvent *ev = &e->xconfigure; |
491 |
505 |
492 if(ev->window == root && (ev->width != sw || ev->height != sh)) { |
506 if(ev->window == root && (ev->width != sw || ev->height != sh)) { |
493 sw = ev->width; |
507 sw = ev->width; |
494 sh = ev->height; |
508 sh = ev->height; |
495 updategeom(); |
509 updategeom(); |
496 if(dc.drawable != 0) |
510 if(dc.drawable != 0) |
497 XFreePixmap(dpy, dc.drawable); |
511 XFreePixmap(dpy, dc.drawable); |
498 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
512 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
499 for(i = 0; i < nmons; i++) |
513 updatebars(); |
500 XMoveResizeWindow(dpy, mon[i].barwin, mon[i].wx, mon[i].by, mon[i].ww, bh); |
514 for(m = mons; m; m = m->next) |
|
515 XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh); |
501 arrange(); |
516 arrange(); |
502 } |
517 } |
503 } |
518 } |
504 |
519 |
505 void |
520 void |
1354 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
1376 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
1355 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1377 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); |
1356 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1378 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); |
1357 |
1379 |
1358 /* init cursors */ |
1380 /* init cursors */ |
1359 wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1381 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); |
1360 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1382 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); |
1361 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1383 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); |
1362 |
1384 |
1363 /* init appearance */ |
1385 /* init appearance */ |
1364 dc.norm[ColBorder] = getcolor(normbordercolor); |
1386 dc.norm[ColBorder] = getcolor(normbordercolor); |
1372 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1394 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1373 if(!dc.font.set) |
1395 if(!dc.font.set) |
1374 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1396 XSetFont(dpy, dc.gc, dc.font.xfont->fid); |
1375 |
1397 |
1376 /* init bars */ |
1398 /* init bars */ |
1377 wa.override_redirect = True; |
|
1378 wa.background_pixmap = ParentRelative; |
|
1379 wa.event_mask = ButtonPressMask|ExposureMask; |
|
1380 for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) { |
1399 for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) { |
1381 w = TEXTW(layouts[i].symbol); |
1400 w = TEXTW(layouts[i].symbol); |
1382 blw = MAX(blw, w); |
1401 blw = MAX(blw, w); |
1383 } |
1402 } |
1384 |
1403 updatebars(); |
1385 for(i = 0; i < nmons; i++) { |
|
1386 mon[i].barwin = XCreateWindow(dpy, root, mon[i].wx, mon[i].by, mon[i].ww, bh, 0, DefaultDepth(dpy, screen), |
|
1387 |
|
1388 CopyFromParent, DefaultVisual(dpy, screen), |
|
1389 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
|
1390 XDefineCursor(dpy, mon[i].barwin, cursor[CurNormal]); |
|
1391 XMapRaised(dpy, mon[i].barwin); |
|
1392 } |
|
1393 updatestatus(); |
1404 updatestatus(); |
1394 |
1405 |
1395 /* EWMH support per view */ |
1406 /* EWMH support per view */ |
1396 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1407 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1397 PropModeReplace, (unsigned char *) netatom, NetLast); |
1408 PropModeReplace, (unsigned char *) netatom, NetLast); |
1577 if((c = getclient(ev->window))) |
1593 if((c = getclient(ev->window))) |
1578 unmanage(c); |
1594 unmanage(c); |
1579 } |
1595 } |
1580 |
1596 |
1581 void |
1597 void |
|
1598 updatebars(void) { |
|
1599 Monitor *m; |
|
1600 XSetWindowAttributes wa; |
|
1601 |
|
1602 wa.cursor = cursor[CurNormal]; |
|
1603 wa.override_redirect = True; |
|
1604 wa.background_pixmap = ParentRelative; |
|
1605 wa.event_mask = ButtonPressMask|ExposureMask; |
|
1606 |
|
1607 for(m = mons; m; m = m->next) { |
|
1608 m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen), |
|
1609 |
|
1610 CopyFromParent, DefaultVisual(dpy, screen), |
|
1611 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
|
1612 XDefineCursor(dpy, m->barwin, cursor[CurNormal]); |
|
1613 XMapRaised(dpy, m->barwin); |
|
1614 } |
|
1615 } |
|
1616 |
|
1617 void |
1582 updategeom(void) { |
1618 updategeom(void) { |
|
1619 int i, n; |
|
1620 Client *c; |
|
1621 Monitor *newmons = NULL, *m; |
|
1622 |
1583 #ifdef XINERAMA |
1623 #ifdef XINERAMA |
1584 int n; |
|
1585 unsigned int i = 0; |
|
1586 Client *c; |
|
1587 XineramaScreenInfo *info = NULL; |
1624 XineramaScreenInfo *info = NULL; |
1588 |
1625 |
1589 /* window area geometry */ |
1626 if(XineramaIsActive(dpy)) |
1590 if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { |
1627 info = XineramaQueryScreens(dpy, &n); |
1591 if(n != nmons) { |
1628 #endif |
1592 for(c = clients; c; c = c->next) |
1629 /* allocate monitor(s) for the new geometry setup */ |
1593 if(c->mon >= n) |
1630 for(i = 0; i < n; i++) { |
1594 c->mon = n - 1; |
1631 m = (Monitor *)malloc(sizeof(Monitor)); |
1595 if(!(mon = (Monitor *)realloc(mon, sizeof(Monitor) * n))) |
1632 m->next = newmons; |
1596 die("fatal: could not realloc() %u bytes\n", sizeof(Monitor) * nmons); |
1633 newmons = m; |
1597 selmon = NULL; |
1634 } |
1598 } |
1635 |
1599 for(i = 0; i < n ; i++) { |
1636 /* initialise monitor(s) */ |
1600 /* TODO: consider re-using XineramaScreenInfo */ |
1637 #ifdef XINERAMA |
1601 mon[i].symbol[0] = '['; |
1638 if(XineramaIsActive(dpy)) { |
1602 mon[i].symbol[1] = '0' + info[i].screen_number; |
1639 for(i = 0, m = newmons; m; m = m->next, i++) { |
1603 mon[i].symbol[2] = ']'; |
1640 m->screen_number = info[i].screen_number; |
1604 mon[i].symbol[3] = 0; |
1641 m->wx = info[i].x_org; |
1605 if(!selmon) { /* not initialised yet */ |
1642 m->wy = info[i].y_org; |
1606 mon[i].mfact = mfact; |
1643 m->ww = info[i].width; |
1607 mon[i].showbar = showbar; |
1644 m->wh = info[i].height; |
1608 mon[i].topbar = topbar; |
|
1609 mon[i].tagset[0] = mon[i].tagset[1] = 1; |
|
1610 } |
|
1611 mon[i].wx = info[i].x_org; |
|
1612 mon[i].wy = mon[i].showbar && mon[i].topbar ? info[i].y_org + bh : info[i].y_org; |
|
1613 mon[i].ww = info[i].width; |
|
1614 mon[i].wh = mon[i].showbar ? info[i].height - bh : info[i].height; |
|
1615 mon[i].seltags = 0; |
|
1616 mon[i].sellt = 0; |
|
1617 if(mon[i].showbar) |
|
1618 mon[i].by = mon[i].topbar ? info[i].y_org : mon[i].wy + mon[i].wh; |
|
1619 else |
|
1620 mon[i].by = -bh; |
|
1621 } |
|
1622 nmons = (unsigned int)n; |
|
1623 if(!selmon) { |
|
1624 selmon = &mon[0]; |
|
1625 int di, x, y; |
|
1626 unsigned int dui; |
|
1627 Window dummy; |
|
1628 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) |
|
1629 for(i = 0; i < nmons; i++) |
|
1630 if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height)) { |
|
1631 selmon = &mon[i]; |
|
1632 break; |
|
1633 } |
|
1634 } |
1645 } |
1635 XFree(info); |
1646 XFree(info); |
1636 } |
1647 } |
1637 else |
1648 else |
1638 #endif /* XINERAMA */ |
1649 #endif |
|
1650 /* default monitor setup */ |
1639 { |
1651 { |
1640 if(!mon) { |
1652 m->screen_number = 0; |
1641 nmons = 1; |
1653 m->wx = sx; |
1642 if(!(mon = (Monitor *)malloc(sizeof(Monitor)))) |
1654 m->wy = sy; |
1643 die("fatal: could not malloc() %u bytes\n", sizeof(Monitor)); |
1655 m->ww = sw; |
1644 } |
1656 m->wh = sh; |
1645 if(!selmon) { |
1657 } |
1646 mon[0].symbol[0] = '['; |
1658 |
1647 mon[0].symbol[1] = '0'; |
1659 /* bar geometry setup */ |
1648 mon[0].symbol[2] = ']'; |
1660 for(m = newmons; m; m = m->next) { |
1649 mon[0].symbol[3] = 0; |
1661 /* TODO: consider removing the following values from config.h */ |
1650 mon[0].mfact = mfact; |
1662 m->seltags = 0; |
1651 mon[0].showbar = showbar; |
1663 m->sellt = 0; |
1652 mon[0].topbar = topbar; |
1664 m->tagset[0] = m->tagset[1] = 1; |
1653 mon[0].tagset[0] = mon[0].tagset[1] = 1; |
1665 m->mfact = mfact; |
1654 } |
1666 m->showbar = showbar; |
1655 mon[0].wx = sx; |
1667 m->topbar = topbar; |
1656 mon[0].wy = mon[0].showbar && mon[0].topbar ? sy + bh : sy; |
1668 if(m->showbar) { |
1657 mon[0].ww = sw; |
1669 m->wh -= bh; |
1658 mon[0].wh = mon[0].showbar ? sh - bh : sh; |
1670 m->by = m->topbar ? m->wy : m->wy + m->wh; |
1659 mon[0].seltags = 0; |
1671 m->wy = m->topbar ? m->wy + bh : m->wy; |
1660 mon[0].sellt = 0; |
1672 } |
1661 if(mon[0].showbar) |
|
1662 mon[0].by = mon[0].topbar ? sy : mon[0].wy + mon[0].wh; |
|
1663 else |
1673 else |
1664 mon[0].by = -bh; |
1674 m->by = -bh; |
1665 selmon = &mon[0]; |
1675 /* reassign all clients with same screen number */ |
1666 } |
1676 for(c = clients; c; c = c->next) |
|
1677 if(c->m->screen_number == m->screen_number) |
|
1678 c->m = m; |
|
1679 } |
|
1680 |
|
1681 /* reassign left over clients with disappeared screen number */ |
|
1682 for(c = clients; c; c = c->next) |
|
1683 if(c->m->screen_number >= n) |
|
1684 c->m = newmons; |
|
1685 |
|
1686 /* select focused monitor */ |
|
1687 if(!selmon) { |
|
1688 selmon = newmons; |
|
1689 int di, x, y; |
|
1690 unsigned int dui; |
|
1691 Window dummy; |
|
1692 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui)) |
|
1693 for(m = newmons; m; m = m->next) |
|
1694 if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh)) { |
|
1695 selmon = m; |
|
1696 break; |
|
1697 } |
|
1698 } |
|
1699 |
|
1700 /* final assignment of new monitors */ |
|
1701 cleanupmons(); |
|
1702 mons = newmons; |
1667 } |
1703 } |
1668 |
1704 |
1669 void |
1705 void |
1670 updatenumlockmask(void) { |
1706 updatenumlockmask(void) { |
1671 unsigned int i, j; |
1707 unsigned int i, j; |