Mercurial > aewl
comparison aewl.c @ 777:3835ddb75a55
changed to status text setting through XA_WM_NAME (suggested by Neale Pickett)
author | meillo@marmaro.de |
---|---|
date | Mon, 16 Feb 2009 10:40:57 +0100 |
parents | a3399a8964c7 |
children | 7ea91d4d0882 |
comparison
equal
deleted
inserted
replaced
776:a3399a8964c7 | 777:3835ddb75a55 |
---|---|
6 * driven through handling X events. In contrast to other X clients, a window | 6 * driven through handling X events. In contrast to other X clients, a window |
7 * manager selects for SubstructureRedirectMask on the root window, to receive | 7 * manager selects for SubstructureRedirectMask on the root window, to receive |
8 * events about window (dis-)appearance. Only one X connection at a time is | 8 * events about window (dis-)appearance. Only one X connection at a time is |
9 * allowed to select for this event mask. | 9 * allowed to select for this event mask. |
10 * | 10 * |
11 * Calls to fetch an X event from the event queue are blocking. Due reading | 11 * The event handlers of dwm are organized in an array which is accessed |
12 * status text from standard input, a select()-driven main loop has been | 12 * whenever a new event has been fetched. This allows event dispatching in O(1) |
13 * implemented which selects for reads on the X connection and STDIN_FILENO to | 13 * time. |
14 * handle all data smoothly. The event handlers of dwm are organized in an | |
15 * array which is accessed whenever a new event has been fetched. This allows | |
16 * event dispatching in O(1) time. | |
17 * | 14 * |
18 * Each child of the root window is called a client, except windows which have | 15 * Each child of the root window is called a client, except windows which have |
19 * set the override_redirect flag. Clients are organized in a global | 16 * set the override_redirect flag. Clients are organized in a global |
20 * doubly-linked client list, the focus history is remembered through a global | 17 * doubly-linked client list, the focus history is remembered through a global |
21 * stack list. [...] | 18 * stack list. [...] |
44 #include <stdio.h> | 41 #include <stdio.h> |
45 #include <stdarg.h> | 42 #include <stdarg.h> |
46 #include <stdlib.h> | 43 #include <stdlib.h> |
47 #include <string.h> | 44 #include <string.h> |
48 #include <unistd.h> | 45 #include <unistd.h> |
49 #include <sys/select.h> | |
50 #include <sys/signal.h> | 46 #include <sys/signal.h> |
51 #include <sys/types.h> | 47 #include <sys/types.h> |
52 #include <sys/wait.h> | 48 #include <sys/wait.h> |
53 #include <X11/cursorfont.h> | 49 #include <X11/cursorfont.h> |
54 #include <X11/keysym.h> | 50 #include <X11/keysym.h> |
143 DC dc = {0}; /* global draw context */ | 139 DC dc = {0}; /* global draw context */ |
144 Display *dpy; | 140 Display *dpy; |
145 Window root, barwin; | 141 Window root, barwin; |
146 | 142 |
147 static int (*xerrorxlib)(Display *, XErrorEvent *); | 143 static int (*xerrorxlib)(Display *, XErrorEvent *); |
148 static Bool otherwm, readin; | 144 static Bool otherwm; |
149 static unsigned int len = 0; | 145 static unsigned int len = 0; |
150 | 146 |
151 | 147 |
152 | 148 |
153 void configure(Client *c); /* send synthetic configure event */ | 149 void configure(Client *c); /* send synthetic configure event */ |
158 void resize(Client *c, Bool sizehints); /* resize c*/ | 154 void resize(Client *c, Bool sizehints); /* resize c*/ |
159 void updatesizehints(Client *c); /* update the size hint variables of c */ | 155 void updatesizehints(Client *c); /* update the size hint variables of c */ |
160 void updatetitle(Client *c); /* update the name of c */ | 156 void updatetitle(Client *c); /* update the name of c */ |
161 void unmanage(Client *c); /* destroy c */ | 157 void unmanage(Client *c); /* destroy c */ |
162 | 158 |
163 void drawstatus(void); /* draw the bar */ | 159 void drawbar(void); /* draw the bar */ |
164 unsigned long getcolor(const char *colstr); /* return color of colstr */ | 160 unsigned long getcolor(const char *colstr); /* return color of colstr */ |
165 void setfont(const char *fontstr); /* set the font for DC */ | 161 void setfont(const char *fontstr); /* set the font for DC */ |
166 unsigned int textw(const char *text); /* return the width of text in px*/ | 162 unsigned int textw(const char *text); /* return the width of text in px*/ |
167 | 163 |
168 void grabkeys(void); /* grab all keys defined in config.h */ | 164 void grabkeys(void); /* grab all keys defined in config.h */ |
169 void procevent(void); /* process pending X events */ | |
170 | 165 |
171 void sendevent(Window w, Atom a, long value); /* send synthetic event to w */ | 166 void sendevent(Window w, Atom a, long value); /* send synthetic event to w */ |
172 int xerror(Display *dsply, XErrorEvent *ee); /* X error handler */ | 167 int xerror(Display *dsply, XErrorEvent *ee); /* X error handler */ |
173 | 168 |
174 Client *getnext(Client *c); /* returns next visible client */ | 169 Client *getnext(Client *c); /* returns next visible client */ |
193 void incnmaster(void); /* increments nmaster */ | 188 void incnmaster(void); /* increments nmaster */ |
194 void decnmaster(void); /* decrements nmaster */ | 189 void decnmaster(void); /* decrements nmaster */ |
195 void toggletag(void); /* toggles tag of c */ | 190 void toggletag(void); /* toggles tag of c */ |
196 void spawn(const char* cmd); /* forks a new subprocess with cmd */ | 191 void spawn(const char* cmd); /* forks a new subprocess with cmd */ |
197 | 192 |
193 void updatestatus(void); /* update the status text */ | |
198 | 194 |
199 | 195 |
200 RULES | 196 RULES |
201 KEYS | 197 KEYS |
202 | 198 |
372 void | 368 void |
373 restack(void) { | 369 restack(void) { |
374 Client *c; | 370 Client *c; |
375 XEvent ev; | 371 XEvent ev; |
376 | 372 |
377 drawstatus(); | 373 drawbar(); |
378 if(!sel) | 374 if(!sel) |
379 return; | 375 return; |
380 if(sel->isfloat) | 376 if(sel->isfloat) |
381 XRaiseWindow(dpy, sel->win); | 377 XRaiseWindow(dpy, sel->win); |
382 | 378 |
720 expose(XEvent *e) { | 716 expose(XEvent *e) { |
721 XExposeEvent *ev = &e->xexpose; | 717 XExposeEvent *ev = &e->xexpose; |
722 | 718 |
723 if(ev->count == 0) { | 719 if(ev->count == 0) { |
724 if(barwin == ev->window) | 720 if(barwin == ev->window) |
725 drawstatus(); | 721 drawbar(); |
726 } | 722 } |
727 } | 723 } |
728 | 724 |
729 void | 725 void |
730 keypress(XEvent *e) { | 726 keypress(XEvent *e) { |
781 propertynotify(XEvent *e) { | 777 propertynotify(XEvent *e) { |
782 Client *c; | 778 Client *c; |
783 Window trans; | 779 Window trans; |
784 XPropertyEvent *ev = &e->xproperty; | 780 XPropertyEvent *ev = &e->xproperty; |
785 | 781 |
786 if(ev->state == PropertyDelete) | 782 if((ev->window == root) && (ev->atom = XA_WM_NAME)) |
783 updatestatus(); | |
784 else if(ev->state == PropertyDelete) | |
787 return; /* ignore */ | 785 return; /* ignore */ |
788 if((c = getclient(ev->window))) { | 786 else if((c = getclient(ev->window))) { |
789 switch (ev->atom) { | 787 switch (ev->atom) { |
790 default: break; | 788 default: break; |
791 case XA_WM_TRANSIENT_FOR: | 789 case XA_WM_TRANSIENT_FOR: |
792 XGetTransientForHint(dpy, c->win, &trans); | 790 XGetTransientForHint(dpy, c->win, &trans); |
793 if(!c->isfloat && (c->isfloat = (trans != 0))) | 791 if(!c->isfloat && (c->isfloat = (trans != 0))) |
798 break; | 796 break; |
799 } | 797 } |
800 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { | 798 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) { |
801 updatetitle(c); | 799 updatetitle(c); |
802 if(c == sel) | 800 if(c == sel) |
803 drawstatus(); | 801 drawbar(); |
804 } | 802 } |
805 } | 803 } |
806 } | 804 } |
807 | 805 |
808 void | 806 void |
845 GrabModeAsync, GrabModeAsync); | 843 GrabModeAsync, GrabModeAsync); |
846 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, | 844 XGrabKey(dpy, code, key[i].mod | numlockmask, root, True, |
847 GrabModeAsync, GrabModeAsync); | 845 GrabModeAsync, GrabModeAsync); |
848 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, | 846 XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True, |
849 GrabModeAsync, GrabModeAsync); | 847 GrabModeAsync, GrabModeAsync); |
850 } | |
851 } | |
852 | |
853 void | |
854 procevent(void) { | |
855 XEvent ev; | |
856 | |
857 while(XPending(dpy)) { | |
858 XNextEvent(dpy, &ev); | |
859 if(handler[ev.type]) | |
860 (handler[ev.type])(&ev); /* call handler */ | |
861 } | 848 } |
862 } | 849 } |
863 | 850 |
864 /* from draw.c */ | 851 /* from draw.c */ |
865 | 852 |
918 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); | 905 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len); |
919 } | 906 } |
920 } | 907 } |
921 | 908 |
922 void | 909 void |
923 drawstatus(void) { | 910 drawbar(void) { |
924 int x; | 911 int x; |
925 unsigned long black[ColLast]; | 912 unsigned long black[ColLast]; |
926 black[ColBG] = getcolor("#000000"); | 913 black[ColBG] = getcolor("#000000"); |
927 black[ColFG] = getcolor("#ffffff"); | 914 black[ColFG] = getcolor("#ffffff"); |
928 | 915 |
1110 c->snext = stack; | 1097 c->snext = stack; |
1111 stack = c; | 1098 stack = c; |
1112 grabbuttons(c, True); | 1099 grabbuttons(c, True); |
1113 } | 1100 } |
1114 sel = c; | 1101 sel = c; |
1115 drawstatus(); | 1102 drawbar(); |
1116 if(!selscreen) | 1103 if(!selscreen) |
1117 return; | 1104 return; |
1118 if(c) { | 1105 if(c) { |
1119 XSetWindowBorder(dpy, c->win, dc.sel[ColBG]); | 1106 XSetWindowBorder(dpy, c->win, dc.sel[ColBG]); |
1120 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); | 1107 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime); |
1320 c->maxw == c->minw && c->maxh == c->minh); | 1307 c->maxw == c->minw && c->maxh == c->minh); |
1321 } | 1308 } |
1322 | 1309 |
1323 void | 1310 void |
1324 updatetitle(Client *c) { | 1311 updatetitle(Client *c) { |
1312 if (!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) { | |
1313 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); | |
1314 } | |
1315 } | |
1316 | |
1317 | |
1318 Bool | |
1319 gettextprop(Window w, Atom atom, char* text, unsigned int size) { | |
1325 char **list = NULL; | 1320 char **list = NULL; |
1326 int n; | 1321 int n; |
1327 XTextProperty name; | 1322 XTextProperty name; |
1328 | 1323 |
1329 name.nitems = 0; | 1324 if (!text || size == 0) { |
1330 c->name[0] = 0; | 1325 return False; |
1331 XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]); | 1326 } |
1327 text[0] = '\0'; | |
1328 XGetTextProperty(dpy, w, &name, atom); | |
1332 if(!name.nitems) | 1329 if(!name.nitems) |
1333 XGetWMName(dpy, c->win, &name); | 1330 return False; |
1334 if(!name.nitems) | |
1335 return; | |
1336 if(name.encoding == XA_STRING) | 1331 if(name.encoding == XA_STRING) |
1337 strncpy(c->name, (char *)name.value, sizeof c->name); | 1332 strncpy(text, (char *)name.value, size - 1); |
1338 else { | 1333 else { |
1339 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { | 1334 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) { |
1340 strncpy(c->name, *list, sizeof c->name); | 1335 strncpy(text, *list, size - 1); |
1341 XFreeStringList(list); | 1336 XFreeStringList(list); |
1342 } | 1337 } |
1343 } | 1338 } |
1339 text[size - 1] = '\0'; | |
1344 XFree(name.value); | 1340 XFree(name.value); |
1341 return True; | |
1345 } | 1342 } |
1346 | 1343 |
1347 void | 1344 void |
1348 unmanage(Client *c) { | 1345 unmanage(Client *c) { |
1349 Client *nc; | 1346 Client *nc; |
1368 | 1365 |
1369 /* from main.c */ | 1366 /* from main.c */ |
1370 | 1367 |
1371 void | 1368 void |
1372 cleanup(void) { | 1369 cleanup(void) { |
1373 close(STDIN_FILENO); | |
1374 while(stack) { | 1370 while(stack) { |
1375 resize(stack, True); | 1371 resize(stack, True); |
1376 unmanage(stack); | 1372 unmanage(stack); |
1377 } | 1373 } |
1378 if(dc.font.set) | 1374 if(dc.font.set) |
1416 int i, j; | 1412 int i, j; |
1417 unsigned int mask; | 1413 unsigned int mask; |
1418 Window w; | 1414 Window w; |
1419 XModifierKeymap *modmap; | 1415 XModifierKeymap *modmap; |
1420 XSetWindowAttributes wa; | 1416 XSetWindowAttributes wa; |
1417 | |
1418 screen = DefaultScreen(dpy); | |
1419 root = RootWindow(dpy, screen); | |
1421 | 1420 |
1422 /* init atoms */ | 1421 /* init atoms */ |
1423 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); | 1422 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); |
1424 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); | 1423 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); |
1425 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); | 1424 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); |
1441 } | 1440 } |
1442 } | 1441 } |
1443 XFreeModifiermap(modmap); | 1442 XFreeModifiermap(modmap); |
1444 /* select for events */ | 1443 /* select for events */ |
1445 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | 1444 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |
1446 | EnterWindowMask | LeaveWindowMask; | 1445 | EnterWindowMask | LeaveWindowMask | PropertyChangeMask; |
1447 wa.cursor = cursor[CurNormal]; | 1446 wa.cursor = cursor[CurNormal]; |
1448 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); | 1447 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); |
1449 grabkeys(); | 1448 grabkeys(); |
1450 seltag = True; | 1449 seltag = True; |
1451 /* style */ | 1450 /* style */ |
1480 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); | 1479 dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); |
1481 dc.gc = XCreateGC(dpy, root, 0, 0); | 1480 dc.gc = XCreateGC(dpy, root, 0, 0); |
1482 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); | 1481 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); |
1483 /* multihead support */ | 1482 /* multihead support */ |
1484 selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); | 1483 selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); |
1484 | |
1485 updatestatus(); | |
1485 } | 1486 } |
1486 | 1487 |
1487 /* | 1488 /* |
1488 * Startup Error handler to check if another window manager | 1489 * Startup Error handler to check if another window manager |
1489 * is already running. | 1490 * is already running. |
1508 XSync(dpy, False); | 1509 XSync(dpy, False); |
1509 } | 1510 } |
1510 | 1511 |
1511 void | 1512 void |
1512 quit() { | 1513 quit() { |
1513 readin = running = False; | 1514 running = False; |
1514 } | 1515 } |
1515 | 1516 |
1516 /* There's no way to check accesses to destroyed windows, thus those cases are | 1517 /* There's no way to check accesses to destroyed windows, thus those cases are |
1517 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs | 1518 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs |
1518 * default error handler, which may call exit. | 1519 * default error handler, which may call exit. |
1531 fprintf(stderr, "aewl: fatal error: request code=%d, error code=%d\n", | 1532 fprintf(stderr, "aewl: fatal error: request code=%d, error code=%d\n", |
1532 ee->request_code, ee->error_code); | 1533 ee->request_code, ee->error_code); |
1533 return xerrorxlib(dpy, ee); /* may call exit */ | 1534 return xerrorxlib(dpy, ee); /* may call exit */ |
1534 } | 1535 } |
1535 | 1536 |
1537 void | |
1538 checkotherwm(void) { | |
1539 otherwm = False; | |
1540 xerrorxlib = XSetErrorHandler(xerrorstart); | |
1541 /* this causes an error if some other window manager is running */ | |
1542 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); | |
1543 XSync(dpy, False); | |
1544 if(otherwm) { | |
1545 eprint("aewl: another window manager is already running\n"); | |
1546 } | |
1547 | |
1548 XSetErrorHandler(xerror); | |
1549 XSync(dpy, False); | |
1550 } | |
1551 | |
1552 void | |
1553 run(void) { | |
1554 XEvent ev; | |
1555 | |
1556 XSync(dpy, False); | |
1557 /* main event loop */ | |
1558 while(running && !XNextEvent(dpy, &ev)) { | |
1559 if(handler[ev.type]) { | |
1560 (handler[ev.type])(&ev); /* call handler */ | |
1561 } | |
1562 } | |
1563 } | |
1564 | |
1565 void | |
1566 updatestatus(void) { | |
1567 if (!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) { | |
1568 strcpy(stext, "aewl-"VERSION); | |
1569 } | |
1570 drawbar(); | |
1571 } | |
1572 | |
1536 int | 1573 int |
1537 main(int argc, char *argv[]) { | 1574 main(int argc, char *argv[]) { |
1538 char *p; | |
1539 int r, xfd; | |
1540 fd_set rd; | |
1541 | 1575 |
1542 if(argc == 2 && !strncmp("-v", argv[1], 3)) { | 1576 if(argc == 2 && !strncmp("-v", argv[1], 3)) { |
1543 fputs("aewl-"VERSION", Copyright 2008 markus schnalke <meillo@marmaro.de>\n", stdout); | 1577 fputs("aewl-"VERSION", Copyright 2008 markus schnalke <meillo@marmaro.de>\n", stdout); |
1544 fputs("forked off dwm-3.4, (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); | 1578 fputs("forked off dwm-3.4, (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout); |
1545 exit(EXIT_SUCCESS); | 1579 exit(EXIT_SUCCESS); |
1549 setlocale(LC_CTYPE, ""); | 1583 setlocale(LC_CTYPE, ""); |
1550 dpy = XOpenDisplay(0); | 1584 dpy = XOpenDisplay(0); |
1551 if(!dpy) { | 1585 if(!dpy) { |
1552 eprint("aewl: cannot open display\n"); | 1586 eprint("aewl: cannot open display\n"); |
1553 } | 1587 } |
1554 xfd = ConnectionNumber(dpy); | 1588 |
1555 screen = DefaultScreen(dpy); | 1589 checkotherwm(); |
1556 root = RootWindow(dpy, screen); | |
1557 otherwm = False; | |
1558 XSetErrorHandler(xerrorstart); | |
1559 /* this causes an error if some other window manager is running */ | |
1560 XSelectInput(dpy, root, SubstructureRedirectMask); | |
1561 XSync(dpy, False); | |
1562 if(otherwm) { | |
1563 eprint("aewl: another window manager is already running\n"); | |
1564 } | |
1565 | |
1566 XSync(dpy, False); | |
1567 XSetErrorHandler(NULL); | |
1568 xerrorxlib = XSetErrorHandler(xerror); | |
1569 XSync(dpy, False); | |
1570 setup(); | 1590 setup(); |
1571 drawstatus(); | |
1572 scan(); | 1591 scan(); |
1573 | 1592 run(); |
1574 /* main event loop, also reads status text from stdin */ | |
1575 XSync(dpy, False); | |
1576 procevent(); | |
1577 readin = True; | |
1578 while(running) { | |
1579 FD_ZERO(&rd); | |
1580 if(readin) | |
1581 FD_SET(STDIN_FILENO, &rd); | |
1582 FD_SET(xfd, &rd); | |
1583 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { | |
1584 if(errno == EINTR) | |
1585 continue; | |
1586 eprint("select failed\n"); | |
1587 } | |
1588 if(FD_ISSET(STDIN_FILENO, &rd)) { | |
1589 switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { | |
1590 case -1: | |
1591 strncpy(stext, strerror(errno), sizeof stext - 1); | |
1592 stext[sizeof stext - 1] = '\0'; | |
1593 readin = False; | |
1594 break; | |
1595 case 0: | |
1596 strncpy(stext, "EOF", 4); | |
1597 readin = False; | |
1598 break; | |
1599 default: | |
1600 for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); | |
1601 for(; p >= stext && *p != '\n'; --p); | |
1602 if(p > stext) | |
1603 strncpy(stext, p + 1, sizeof stext); | |
1604 } | |
1605 drawstatus(); | |
1606 } | |
1607 if(FD_ISSET(xfd, &rd)) | |
1608 procevent(); | |
1609 } | |
1610 cleanup(); | 1593 cleanup(); |
1594 | |
1611 XCloseDisplay(dpy); | 1595 XCloseDisplay(dpy); |
1612 return 0; | 1596 return 0; |
1613 } | 1597 } |