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 }