arg@643: /* (C)opyright MMVII Anselm R. Garbe garbeam@0: * See LICENSE file for license details. garbeam@0: */ garbeam@0: garbeam@76: #include "dwm.h" garbeam@59: #include arg@619: #include garbeam@0: #include garbeam@0: #include garbeam@57: #include garbeam@59: #include arg@138: #include garbeam@0: #include arg@291: #include garbeam@0: #include garbeam@0: #include garbeam@0: arg@333: /* extern */ arg@333: arg@333: char stext[1024]; arg@333: Bool *seltag; arg@565: int bx, by, bw, bh, bmw, masterd, screen, sx, sy, sw, sh, wax, way, waw, wah; arg@524: unsigned int master, ntags, numlockmask; arg@333: Atom wmatom[WMLast], netatom[NetLast]; arg@333: Bool running = True; arg@333: Bool issel = True; arg@333: Client *clients = NULL; arg@333: Client *sel = NULL; arg@446: Client *stack = NULL; arg@333: Cursor cursor[CurLast]; arg@333: Display *dpy; arg@333: DC dc = {0}; arg@333: Window root, barwin; arg@333: garbeam@84: /* static */ garbeam@0: arg@123: static int (*xerrorxlib)(Display *, XErrorEvent *); arg@302: static Bool otherwm, readin; garbeam@0: garbeam@0: static void arg@487: cleanup(void) { arg@302: close(STDIN_FILENO); arg@641: while(clients) { arg@641: resize(clients, True, TopLeft); arg@641: unmanage(clients); garbeam@76: } arg@295: if(dc.font.set) arg@295: XFreeFontSet(dpy, dc.font.set); arg@295: else arg@295: XFreeFont(dpy, dc.font.xfont); arg@292: XUngrabKey(dpy, AnyKey, AnyModifier, root); arg@295: XFreePixmap(dpy, dc.drawable); arg@295: XFreeGC(dpy, dc.gc); arg@309: XDestroyWindow(dpy, barwin); arg@616: XFreeCursor(dpy, cursor[CurNormal]); arg@616: XFreeCursor(dpy, cursor[CurResize]); arg@616: XFreeCursor(dpy, cursor[CurMove]); garbeam@76: XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); arg@292: XSync(dpy, False); arg@433: free(seltag); garbeam@76: } garbeam@0: garbeam@0: static void arg@487: scan(void) { garbeam@0: unsigned int i, num; arg@123: Window *wins, d1, d2; garbeam@0: XWindowAttributes wa; garbeam@0: arg@292: wins = NULL; garbeam@0: if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { garbeam@0: for(i = 0; i < num; i++) { garbeam@0: if(!XGetWindowAttributes(dpy, wins[i], &wa)) garbeam@0: continue; garbeam@0: if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) garbeam@0: continue; garbeam@0: if(wa.map_state == IsViewable) garbeam@10: manage(wins[i], &wa); garbeam@0: } garbeam@0: } garbeam@0: if(wins) garbeam@0: XFree(wins); garbeam@0: } garbeam@0: arg@333: static void arg@487: setup(void) { arg@333: int i, j; arg@333: unsigned int mask; arg@333: Window w; arg@333: XModifierKeymap *modmap; arg@333: XSetWindowAttributes wa; arg@333: arg@333: /* init atoms */ arg@333: wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); arg@333: wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); arg@333: netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); arg@333: netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); arg@333: XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, arg@333: PropModeReplace, (unsigned char *) netatom, NetLast); arg@333: /* init cursors */ arg@333: cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); arg@333: cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); arg@333: cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); arg@532: /* init modifier map */ arg@333: modmap = XGetModifierMapping(dpy); arg@333: for (i = 0; i < 8; i++) { arg@333: for (j = 0; j < modmap->max_keypermod; j++) { arg@333: if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock)) arg@333: numlockmask = (1 << i); arg@333: } arg@333: } arg@616: XFreeModifiermap(modmap); arg@532: /* select for events */ arg@461: wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask arg@461: | EnterWindowMask | LeaveWindowMask; arg@333: wa.cursor = cursor[CurNormal]; arg@333: XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); arg@333: grabkeys(); arg@333: initrregs(); arg@333: for(ntags = 0; tags[ntags]; ntags++); arg@333: seltag = emallocz(sizeof(Bool) * ntags); arg@333: seltag[0] = True; arg@333: /* style */ arg@353: dc.norm[ColBG] = getcolor(NORMBGCOLOR); arg@353: dc.norm[ColFG] = getcolor(NORMFGCOLOR); arg@353: dc.sel[ColBG] = getcolor(SELBGCOLOR); arg@353: dc.sel[ColFG] = getcolor(SELFGCOLOR); arg@353: dc.status[ColBG] = getcolor(STATUSBGCOLOR); arg@353: dc.status[ColFG] = getcolor(STATUSFGCOLOR); arg@333: setfont(FONT); arg@532: /* geometry */ arg@530: bmw = textw(TILESYMBOL) > textw(FLOATSYMBOL) ? textw(TILESYMBOL) : textw(FLOATSYMBOL); arg@333: sx = sy = 0; arg@333: sw = DisplayWidth(dpy, screen); arg@333: sh = DisplayHeight(dpy, screen); arg@524: master = MASTER; arg@532: /* bar */ arg@570: bx = sx; arg@570: by = sy; arg@333: bw = sw; arg@353: dc.h = bh = dc.font.height + 2; arg@333: wa.override_redirect = 1; arg@333: wa.background_pixmap = ParentRelative; arg@333: wa.event_mask = ButtonPressMask | ExposureMask; arg@333: barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen), arg@333: CopyFromParent, DefaultVisual(dpy, screen), arg@333: CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); arg@333: XDefineCursor(dpy, barwin, cursor[CurNormal]); arg@333: XMapRaised(dpy, barwin); arg@532: strcpy(stext, "dwm-"VERSION); arg@565: /* windowarea */ arg@565: wax = sx; arg@570: way = sy + bh; arg@565: wah = sh - bh; arg@565: waw = sw; arg@532: /* pixmap for everything */ arg@333: dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen)); arg@333: dc.gc = XCreateGC(dpy, root, 0, 0); arg@344: XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter); arg@532: /* multihead support */ arg@333: issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); arg@333: } arg@333: garbeam@76: /* garbeam@76: * Startup Error handler to check if another window manager garbeam@76: * is already running. garbeam@76: */ garbeam@76: static int arg@461: xerrorstart(Display *dsply, XErrorEvent *ee) { garbeam@76: otherwm = True; garbeam@76: return -1; garbeam@76: } garbeam@76: garbeam@84: /* extern */ garbeam@84: garbeam@13: int arg@461: getproto(Window w) { arg@329: int i, format, protos, status; arg@328: unsigned long extra, res; arg@328: Atom *protocols, real; garbeam@13: arg@329: protos = 0; arg@329: status = XGetWindowProperty(dpy, w, wmatom[WMProtocols], 0L, 20L, False, arg@329: XA_ATOM, &real, &format, &res, &extra, (unsigned char **)&protocols); arg@328: if(status != Success || protocols == 0) garbeam@13: return protos; arg@329: for(i = 0; i < res; i++) garbeam@77: if(protocols[i] == wmatom[WMDelete]) arg@157: protos |= PROTODELWIN; arg@328: free(protocols); garbeam@13: return protos; garbeam@13: } garbeam@13: garbeam@13: void arg@461: sendevent(Window w, Atom a, long value) { garbeam@13: XEvent e; garbeam@13: garbeam@13: e.type = ClientMessage; garbeam@13: e.xclient.window = w; garbeam@13: e.xclient.message_type = a; garbeam@13: e.xclient.format = 32; garbeam@13: e.xclient.data.l[0] = value; garbeam@13: e.xclient.data.l[1] = CurrentTime; garbeam@13: XSendEvent(dpy, w, False, NoEventMask, &e); garbeam@79: XSync(dpy, False); garbeam@13: } garbeam@13: garbeam@76: void arg@461: quit(Arg *arg) { arg@302: readin = running = False; garbeam@75: } garbeam@75: arg@532: /* There's no way to check accesses to destroyed windows, thus those cases are garbeam@84: * ignored (especially on UnmapNotify's). Other types of errors call Xlibs arg@455: * default error handler, which may call exit. garbeam@0: */ garbeam@10: int arg@461: xerror(Display *dpy, XErrorEvent *ee) { garbeam@75: if(ee->error_code == BadWindow arg@123: || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) arg@123: || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) arg@123: || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) arg@123: || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) arg@123: || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) arg@458: || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) arg@458: || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) garbeam@0: return 0; garbeam@34: fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n", arg@123: ee->request_code, ee->error_code); arg@455: return xerrorxlib(dpy, ee); /* may call exit */ garbeam@27: } garbeam@27: garbeam@0: int arg@461: main(int argc, char *argv[]) { arg@581: char *p; arg@333: int r, xfd; garbeam@59: fd_set rd; garbeam@0: arg@137: if(argc == 2 && !strncmp("-v", argv[1], 3)) { arg@643: fputs("dwm-"VERSION", (C)opyright MMVII Anselm R. Garbe\n", stdout); arg@137: exit(EXIT_SUCCESS); garbeam@0: } arg@137: else if(argc != 1) arg@137: eprint("usage: dwm [-v]\n"); arg@619: setlocale(LC_CTYPE, ""); garbeam@0: dpy = XOpenDisplay(0); garbeam@0: if(!dpy) arg@197: eprint("dwm: cannot open display\n"); arg@265: xfd = ConnectionNumber(dpy); garbeam@0: screen = DefaultScreen(dpy); garbeam@0: root = RootWindow(dpy, screen); garbeam@75: otherwm = False; garbeam@75: XSetErrorHandler(xerrorstart); arg@197: /* this causes an error if some other window manager is running */ garbeam@0: XSelectInput(dpy, root, SubstructureRedirectMask); garbeam@78: XSync(dpy, False); garbeam@75: if(otherwm) garbeam@75: eprint("dwm: another window manager is already running\n"); garbeam@0: arg@292: XSync(dpy, False); garbeam@78: XSetErrorHandler(NULL); garbeam@75: xerrorxlib = XSetErrorHandler(xerror); arg@275: XSync(dpy, False); arg@333: setup(); garbeam@74: drawstatus(); garbeam@75: scan(); garbeam@3: arg@214: /* main event loop, also reads status text from stdin */ arg@242: XSync(dpy, False); arg@292: procevent(); arg@302: readin = True; garbeam@5: while(running) { garbeam@59: FD_ZERO(&rd); arg@164: if(readin) arg@164: FD_SET(STDIN_FILENO, &rd); arg@265: FD_SET(xfd, &rd); arg@578: if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) { arg@578: if(errno == EINTR) arg@578: continue; arg@581: eprint("select failed\n"); arg@578: } arg@578: if(FD_ISSET(STDIN_FILENO, &rd)) { arg@581: switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) { arg@578: case -1: arg@581: strncpy(stext, strerror(errno), sizeof stext - 1); arg@583: stext[sizeof stext - 1] = '\0'; arg@578: readin = False; arg@578: break; arg@578: case 0: arg@583: strncpy(stext, "EOF", 4); arg@578: readin = False; arg@578: break; arg@578: default: arg@582: for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0'); arg@582: for(p = stext + strlen(stext) - 1; p >= stext && *p != '\n'; --p); arg@581: if(p > stext) arg@581: strncpy(stext, p + 1, sizeof stext); garbeam@59: } arg@578: drawstatus(); garbeam@59: } arg@578: if(FD_ISSET(xfd, &rd)) arg@578: procevent(); garbeam@5: } garbeam@0: cleanup(); garbeam@0: XCloseDisplay(dpy); garbeam@0: return 0; garbeam@0: }