4 * driven through handling X events. In contrast to other X clients, a window |
4 * driven through handling X events. In contrast to other X clients, a window |
5 * manager selects for SubstructureRedirectMask on the root window, to receive |
5 * manager selects for SubstructureRedirectMask on the root window, to receive |
6 * events about window (dis-)appearance. Only one X connection at a time is |
6 * events about window (dis-)appearance. Only one X connection at a time is |
7 * allowed to select for this event mask. |
7 * allowed to select for this event mask. |
8 * |
8 * |
9 * Calls to fetch an X event from the event queue are blocking. Due reading |
9 * The event handlers of dwm are organized in an array which is accessed |
10 * status text from standard input, a select()-driven main loop has been |
10 * whenever a new event has been fetched. This allows event dispatching |
11 * implemented which selects for reads on the X connection and STDIN_FILENO to |
11 * in O(1) time. |
12 * handle all data smoothly. The event handlers of dwm are organized in an |
|
13 * array which is accessed whenever a new event has been fetched. This allows |
|
14 * event dispatching in O(1) time. |
|
15 * |
12 * |
16 * Each child of the root window is called a client, except windows which have |
13 * Each child of the root window is called a client, except windows which have |
17 * set the override_redirect flag. Clients are organized in a global |
14 * set the override_redirect flag. Clients are organized in a global |
18 * linked client list, the focus history is remembered through a global |
15 * linked client list, the focus history is remembered through a global |
19 * stack list. Each client contains a bit array to indicate the tags of a |
16 * stack list. Each client contains a bit array to indicate the tags of a |
194 static void unmapnotify(XEvent *e); |
190 static void unmapnotify(XEvent *e); |
195 static void updatebar(void); |
191 static void updatebar(void); |
196 static void updategeom(void); |
192 static void updategeom(void); |
197 static void updatenumlockmask(void); |
193 static void updatenumlockmask(void); |
198 static void updatesizehints(Client *c); |
194 static void updatesizehints(Client *c); |
|
195 static void updatestatus(void); |
199 static void updatetitle(Client *c); |
196 static void updatetitle(Client *c); |
200 static void updatewmhints(Client *c); |
197 static void updatewmhints(Client *c); |
201 static void view(const Arg *arg); |
198 static void view(const Arg *arg); |
202 static int xerror(Display *dpy, XErrorEvent *ee); |
199 static int xerror(Display *dpy, XErrorEvent *ee); |
203 static int xerrordummy(Display *dpy, XErrorEvent *ee); |
200 static int xerrordummy(Display *dpy, XErrorEvent *ee); |
996 propertynotify(XEvent *e) { |
993 propertynotify(XEvent *e) { |
997 Client *c; |
994 Client *c; |
998 Window trans; |
995 Window trans; |
999 XPropertyEvent *ev = &e->xproperty; |
996 XPropertyEvent *ev = &e->xproperty; |
1000 |
997 |
1001 if(ev->state == PropertyDelete) |
998 if((ev->window == root) && (ev->atom = XA_WM_NAME)) |
|
999 updatestatus(); |
|
1000 else if(ev->state == PropertyDelete) |
1002 return; /* ignore */ |
1001 return; /* ignore */ |
1003 if((c = getclient(ev->window))) { |
1002 else if((c = getclient(ev->window))) { |
1004 switch (ev->atom) { |
1003 switch (ev->atom) { |
1005 default: break; |
1004 default: break; |
1006 case XA_WM_TRANSIENT_FOR: |
1005 case XA_WM_TRANSIENT_FOR: |
1007 XGetTransientForHint(dpy, c->win, &trans); |
1006 XGetTransientForHint(dpy, c->win, &trans); |
1008 if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) |
1007 if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL))) |
1178 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1177 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev)); |
1179 } |
1178 } |
1180 |
1179 |
1181 void |
1180 void |
1182 run(void) { |
1181 run(void) { |
1183 char *p; |
|
1184 char sbuf[sizeof stext]; |
|
1185 fd_set rd; |
|
1186 int r, xfd; |
|
1187 unsigned int len, offset; |
|
1188 XEvent ev; |
1182 XEvent ev; |
1189 |
1183 |
1190 /* main event loop, also reads status text from stdin */ |
1184 /* main event loop */ |
1191 XSync(dpy, False); |
1185 XSync(dpy, False); |
1192 xfd = ConnectionNumber(dpy); |
1186 while(running && !XNextEvent(dpy, &ev)) { |
1193 offset = 0; |
1187 if(handler[ev.type]) |
1194 len = sizeof stext - 1; |
1188 (handler[ev.type])(&ev); /* call handler */ |
1195 sbuf[len] = stext[len] = '\0'; /* 0-terminator is never touched */ |
|
1196 while(running) { |
|
1197 FD_ZERO(&rd); |
|
1198 if(readin) |
|
1199 FD_SET(STDIN_FILENO, &rd); |
|
1200 FD_SET(xfd, &rd); |
|
1201 if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { |
|
1202 if(errno == EINTR) |
|
1203 continue; |
|
1204 die("select failed\n"); |
|
1205 } |
|
1206 if(FD_ISSET(STDIN_FILENO, &rd)) { |
|
1207 switch((r = read(STDIN_FILENO, sbuf + offset, len - offset))) { |
|
1208 case -1: |
|
1209 strncpy(stext, strerror(errno), len); |
|
1210 readin = False; |
|
1211 break; |
|
1212 case 0: |
|
1213 strncpy(stext, "EOF", 4); |
|
1214 readin = False; |
|
1215 break; |
|
1216 default: |
|
1217 for(p = sbuf + offset; r > 0; p++, r--, offset++) |
|
1218 if(*p == '\n' || *p == '\0') { |
|
1219 *p = '\0'; |
|
1220 strncpy(stext, sbuf, len); |
|
1221 p += r - 1; /* p is sbuf + offset + r - 1 */ |
|
1222 for(r = 0; *(p - r) && *(p - r) != '\n'; r++); |
|
1223 offset = r; |
|
1224 if(r) |
|
1225 memmove(sbuf, p - r + 1, r); |
|
1226 break; |
|
1227 } |
|
1228 break; |
|
1229 } |
|
1230 drawbar(); |
|
1231 } |
|
1232 while(XPending(dpy)) { |
|
1233 XNextEvent(dpy, &ev); |
|
1234 if(handler[ev.type]) |
|
1235 (handler[ev.type])(&ev); /* call handler */ |
|
1236 } |
|
1237 } |
1189 } |
1238 } |
1190 } |
1239 |
1191 |
1240 void |
1192 void |
1241 scan(void) { |
1193 scan(void) { |
1354 barwin = XCreateWindow(dpy, root, wx, by, ww, bh, 0, DefaultDepth(dpy, screen), |
1306 barwin = XCreateWindow(dpy, root, wx, by, ww, bh, 0, DefaultDepth(dpy, screen), |
1355 CopyFromParent, DefaultVisual(dpy, screen), |
1307 CopyFromParent, DefaultVisual(dpy, screen), |
1356 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1308 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa); |
1357 XDefineCursor(dpy, barwin, cursor[CurNormal]); |
1309 XDefineCursor(dpy, barwin, cursor[CurNormal]); |
1358 XMapRaised(dpy, barwin); |
1310 XMapRaised(dpy, barwin); |
1359 strcpy(stext, "dwm-"VERSION); |
1311 updatestatus(); |
1360 drawbar(); |
|
1361 |
1312 |
1362 /* EWMH support per view */ |
1313 /* EWMH support per view */ |
1363 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1314 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, |
1364 PropModeReplace, (unsigned char *) netatom, NetLast); |
1315 PropModeReplace, (unsigned char *) netatom, NetLast); |
1365 |
1316 |
1366 /* select for events */ |
1317 /* select for events */ |
1367 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask |
1318 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask |
1368 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask; |
1319 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask |
|
1320 |PropertyChangeMask; |
1369 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1321 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa); |
1370 XSelectInput(dpy, root, wa.event_mask); |
1322 XSelectInput(dpy, root, wa.event_mask); |
1371 |
1323 |
1372 grabkeys(); |
1324 grabkeys(); |
1373 } |
1325 } |
1642 |
1594 |
1643 void |
1595 void |
1644 updatetitle(Client *c) { |
1596 updatetitle(Client *c) { |
1645 if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) |
1597 if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name)) |
1646 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); |
1598 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name); |
|
1599 } |
|
1600 |
|
1601 void |
|
1602 updatestatus() { |
|
1603 if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext))) |
|
1604 strcpy(stext, "dwm-"VERSION); |
|
1605 drawbar(); |
1647 } |
1606 } |
1648 |
1607 |
1649 void |
1608 void |
1650 updatewmhints(Client *c) { |
1609 updatewmhints(Client *c) { |
1651 XWMHints *wmh; |
1610 XWMHints *wmh; |