/* * (C)opyright MMIV-MMVI Anselm R. Garbe * See LICENSE file for license details. */ #include #include #include #include #include #include #include #include #include #include #include #include "wm.h" static int other_wm_running; static int (*x_error_handler) (Display *, XErrorEvent *); static char version[] = "wmiiwm - " VERSION ", (C)opyright MMIV-MMVI Anselm R. Garbe\n"; static void usage() { fprintf(stderr, "%s", "usage: wmiiwm -a
[-c] [-v]\n"); exit(1); } Client * win2client(Window w) { unsigned int i; for(i = 0; (i < clientsz) && client[i]; i++) if(client[i]->win == w) return client[i]; return nil; } void scan_wins() { int i; unsigned int num; Window *wins; XWindowAttributes wa; Window d1, d2; if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { for(i = 0; i < num; i++) { if(!XGetWindowAttributes(dpy, wins[i], &wa)) continue; if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) continue; if(wa.map_state == IsViewable) manage_client(alloc_client(wins[i], &wa)); } } if(wins) XFree(wins); } static int win_property(Window w, Atom a, Atom t, long l, unsigned char **prop) { Atom real; int format; unsigned long res, extra; int status; status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format, &res, &extra, prop); if(status != Success || *prop == 0) { return 0; } if(res == 0) { free((void *) *prop); } return res; } int win_proto(Window w) { Atom *protocols; long res; int protos = 0; int i; res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, ((unsigned char **) &protocols)); if(res <= 0) { return protos; } for(i = 0; i < res; i++) { if(protocols[i] == wm_atom[WMDelete]) protos |= PROTO_DEL; } free((char *) protocols); return protos; } int win_state(Window w) { /* state hints */ XWMHints *hints = XGetWMHints(dpy, w); int res; long *prop = 0; if(win_property(w, wm_atom[WMState], wm_atom[WMState], 2L, ((unsigned char **) &prop)) > 0) { res = (int) *prop; free((long *) prop); } else { res = hints ? hints->initial_state : NormalState; } if(hints) { free(hints); } return res; } static void init_atoms() { wm_atom[WMState] = XInternAtom(dpy, "WM_STATE", False); wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); } static void init_cursors() { cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); cursor[CurW] = XCreateFontCursor(dpy, XC_left_side); cursor[CurE] = XCreateFontCursor(dpy, XC_right_side); cursor[CurN] = XCreateFontCursor(dpy, XC_top_side); cursor[CurS] = XCreateFontCursor(dpy, XC_bottom_side); cursor[CurNW] = XCreateFontCursor(dpy, XC_top_left_corner); cursor[CurNE] = XCreateFontCursor(dpy, XC_top_right_corner); cursor[CurSW] = XCreateFontCursor(dpy, XC_bottom_left_corner); cursor[CurSE] = XCreateFontCursor(dpy, XC_bottom_right_corner); } static void init_screen() { XGCValues gcv; gcv.subwindow_mode = IncludeInferiors; gcv.function = GXxor; gcv.foreground = def.sel.bg; gcv.line_width = 4; gcv.plane_mask = AllPlanes; gcv.graphics_exposures = False; gc_xor = XCreateGC(dpy, root, GCForeground | GCGraphicsExposures | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv); rect.x = rect.y = 0; rect.width = DisplayWidth(dpy, screen); rect.height = DisplayHeight(dpy, screen); XDefineCursor(dpy, root, cursor[CurNormal]); } /* * There's no way to check accesses to destroyed windows, thus * those cases are ignored (especially on UnmapNotify's). * Other types of errors call Xlib's default error handler, which * calls exit(). */ static int wmii_error_handler(Display * dpy, XErrorEvent * error) { if(error->error_code == BadWindow || (error->request_code == X_SetInputFocus && error->error_code == BadMatch) || (error->request_code == X_PolyText8 && error->error_code == BadDrawable) || (error->request_code == X_PolyFillRectangle && error->error_code == BadDrawable) || (error->request_code == X_PolySegment && error->error_code == BadDrawable) || (error->request_code == X_ConfigureWindow && error->error_code == BadMatch)) return 0; fprintf(stderr, "%s", "wmiiwm: fatal error"); return x_error_handler(dpy, error); /* calls exit() */ } /* * Startup Error handler to check if another window manager * is already running. */ static int startup_error_handler(Display * dpy, XErrorEvent * error) { other_wm_running = 1; return -1; } static void cleanup() { unsigned int i; Client *c; for(i = 0; client && client[i]; i++) { c = client[i]; reparent_client(c, root, c->frame[c->sel]->rect.x, c->frame[c->sel]->rect.y); } XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XSync(dpy, False); } int main(int argc, char *argv[]) { int i; int checkwm = 0; char *address = nil, *errstr; XSetWindowAttributes wa; /* command line args */ if(argc > 1) { for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) { switch (argv[i][1]) { case 'v': fprintf(stdout, "%s", version); exit(0); break; case 'c': checkwm = 1; break; case 'a': if(i + 1 < argc) address = argv[++i]; else usage(); break; default: usage(); break; } } } dpy = XOpenDisplay(0); if(!dpy) { fprintf(stderr, "%s", "wmiiwm: cannot open display\n"); exit(1); } screen = DefaultScreen(dpy); root = RootWindow(dpy, screen); /* check if another WM is already running */ other_wm_running = 0; XSetErrorHandler(startup_error_handler); /* this causes an error if some other WM is running */ XSelectInput(dpy, root, ROOT_MASK); XSync(dpy, False); if(other_wm_running) { fprintf(stderr, "wmiiwm: another window manager is already running\n"); exit(1); } if(checkwm) { XCloseDisplay(dpy); exit(0); } /* above -c is checked */ if(!address) usage(); XSetErrorHandler(0); x_error_handler = XSetErrorHandler(wmii_error_handler); errstr = nil; i = ixp_create_sock(address, &errstr); if(i < 0) { fprintf(stderr, "wmii: fatal: %s\n", errstr); exit(1); } /* IXP server */ ixp_server_open_conn(&srv, i, new_ixp_conn, ixp_server_close_conn); root_qid.type = IXP_QTDIR; root_qid.version = 0; root_qid.path = mkqpath(FsDroot, 0, 0, 0); /* X server */ ixp_server_open_conn(&srv, ConnectionNumber(dpy), check_x_event, nil); init_x_event_handler(); nctag = ctagsz = ntag = nclient = tagsz = clientsz = sel = 0; tag = nil; ctag = nil; client = nil; key = nil; keysz = nkey = 0; label = nil; nlabel = labelsz = iexpand = 0; class = nil; nclass = classsz = 0; def.font = strdup(BLITZ_FONT); def.border = DEF_BORDER; def.snap = DEF_SNAP; cext_strlcpy(def.tag, "1", sizeof(def.tag)); cext_strlcpy(def.selcolor, BLITZ_SELCOLORS, sizeof(def.selcolor)); blitz_loadcolor(dpy, screen, def.selcolor, &def.sel); cext_strlcpy(def.normcolor, BLITZ_NORMCOLORS, sizeof(def.normcolor)); blitz_loadcolor(dpy, screen, def.normcolor, &def.norm); init_atoms(); init_cursors(); xfont = blitz_getfont(dpy, def.font); init_lock_modifiers(); init_screen(); wa.override_redirect = 1; wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | ButtonPressMask | SubstructureRedirectMask | SubstructureNotifyMask; brect = rect; brect.height = xfont->ascent + xfont->descent + 4; brect.y = rect.height - brect.height; winbar = XCreateWindow(dpy, RootWindow(dpy, screen), brect.x, brect.y, brect.width, brect.height, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); XDefineCursor(dpy, winbar, XCreateFontCursor(dpy, XC_left_ptr)); XSync(dpy, False); gcbar = XCreateGC(dpy, winbar, 0, 0); pmapbar = XCreatePixmap(dpy, winbar, brect.width, brect.height, DefaultDepth(dpy, screen)); XMapRaised(dpy, winbar); draw_bar(); scan_wins(); /* main event loop */ errstr = ixp_server_loop(&srv); if(errstr) fprintf(stderr, "wmii: fatal: %s\n", errstr); ixp_server_close(&srv); cleanup(); XCloseDisplay(dpy); return errstr ? 1 : 0; }