main.c (5917B)
1 /* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com> 2 * See LICENSE file for license details. 3 */ 4 5 #include "2wm.h" 6 #include <errno.h> 7 #include <locale.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <unistd.h> 12 #include <sys/select.h> 13 #include <X11/cursorfont.h> 14 #include <X11/keysym.h> 15 #include <X11/Xatom.h> 16 #include <X11/Xproto.h> 17 18 /* extern */ 19 20 int screen, sx, sy, sw, sh; 21 unsigned int master, nmaster, numlockmask; 22 unsigned long normcol, selcol; 23 Atom wmatom[WMLast], netatom[NetLast]; 24 Bool running = True; 25 Bool selscreen = True; 26 Bool view = True; 27 Client *clients = NULL; 28 Client *sel = NULL; 29 Client *stack = NULL; 30 Cursor cursor[CurLast]; 31 Display *dpy; 32 Window root; 33 34 /* static */ 35 36 static int (*xerrorxlib)(Display *, XErrorEvent *); 37 static Bool otherwm; 38 39 static unsigned long 40 getcolor(const char *colstr) { 41 Colormap cmap = DefaultColormap(dpy, screen); 42 XColor color; 43 44 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color)) 45 eprint("error, cannot allocate color '%s'\n", colstr); 46 return color.pixel; 47 } 48 49 static void 50 cleanup(void) { 51 close(STDIN_FILENO); 52 while(stack) { 53 resize(stack, True); 54 unmanage(stack); 55 } 56 XUngrabKey(dpy, AnyKey, AnyModifier, root); 57 XFreeCursor(dpy, cursor[CurNormal]); 58 XFreeCursor(dpy, cursor[CurResize]); 59 XFreeCursor(dpy, cursor[CurMove]); 60 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); 61 XSync(dpy, False); 62 } 63 64 static void 65 scan(void) { 66 unsigned int i, num; 67 Window *wins, d1, d2; 68 XWindowAttributes wa; 69 70 wins = NULL; 71 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) { 72 for(i = 0; i < num; i++) { 73 if(!XGetWindowAttributes(dpy, wins[i], &wa)) 74 continue; 75 if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1)) 76 continue; 77 if(wa.map_state == IsViewable) 78 manage(wins[i], &wa); 79 } 80 } 81 if(wins) 82 XFree(wins); 83 } 84 85 /* 86 * Startup Error handler to check if another window manager 87 * is already running. 88 */ 89 static int 90 xerrorstart(Display *dsply, XErrorEvent *ee) { 91 otherwm = True; 92 return -1; 93 } 94 95 /* extern */ 96 97 void 98 sendevent(Window w, Atom a, long value) { 99 XEvent e; 100 101 e.type = ClientMessage; 102 e.xclient.window = w; 103 e.xclient.message_type = a; 104 e.xclient.format = 32; 105 e.xclient.data.l[0] = value; 106 e.xclient.data.l[1] = CurrentTime; 107 XSendEvent(dpy, w, False, NoEventMask, &e); 108 XSync(dpy, False); 109 } 110 111 void 112 quit(Arg *arg) { 113 running = False; 114 } 115 116 /* There's no sy to check accesses to destroyed windows, thus those cases are 117 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs 118 * default error handler, which may call exit. 119 */ 120 int 121 xerror(Display *dpy, XErrorEvent *ee) { 122 if(ee->error_code == BadWindow 123 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch) 124 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable) 125 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable) 126 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable) 127 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) 128 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess) 129 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable)) 130 return 0; 131 fprintf(stderr, "2wm: fatal error: request code=%d, error code=%d\n", 132 ee->request_code, ee->error_code); 133 return xerrorxlib(dpy, ee); /* may call exit */ 134 } 135 136 int 137 main(int argc, char *argv[]) { 138 int i, j; 139 unsigned int mask; 140 Window w; 141 XEvent ev; 142 XModifierKeymap *modmap; 143 XSetWindowAttributes wa; 144 145 if(argc == 2 && !strncmp("-v", argv[1], 3)) 146 eprint("2wm-"VERSION", (C)opyright MMVII Anselm R. Garbe\n"); 147 else if(argc != 1) 148 eprint("usage: 2wm [-v]\n"); 149 setlocale(LC_CTYPE, ""); 150 dpy = XOpenDisplay(0); 151 if(!dpy) 152 eprint("2wm: cannot open display\n"); 153 screen = DefaultScreen(dpy); 154 root = RootWindow(dpy, screen); 155 otherwm = False; 156 XSetErrorHandler(xerrorstart); 157 /* this causes an error if some other window manager is running */ 158 XSelectInput(dpy, root, SubstructureRedirectMask); 159 XSync(dpy, False); 160 if(otherwm) 161 eprint("2wm: another window manager is already running\n"); 162 163 XSync(dpy, False); 164 XSetErrorHandler(NULL); 165 xerrorxlib = XSetErrorHandler(xerror); 166 XSync(dpy, False); 167 168 /* init atoms */ 169 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False); 170 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 171 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False); 172 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False); 173 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False); 174 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32, 175 PropModeReplace, (unsigned char *) netatom, NetLast); 176 /* init cursors */ 177 cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr); 178 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing); 179 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur); 180 /* init modifier map */ 181 numlockmask = 0; 182 modmap = XGetModifierMapping(dpy); 183 for (i = 0; i < 8; i++) { 184 for (j = 0; j < modmap->max_keypermod; j++) { 185 if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock)) 186 numlockmask = (1 << i); 187 } 188 } 189 XFreeModifiermap(modmap); 190 /* select for events */ 191 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask 192 | EnterWindowMask | LeaveWindowMask; 193 wa.cursor = cursor[CurNormal]; 194 XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa); 195 grabkeys(); 196 initrregs(); 197 /* style */ 198 normcol = getcolor(NORMCOLOR); 199 selcol = getcolor(SELCOLOR); 200 /* geometry */ 201 sx = 0; 202 sy = SY; 203 sw = DisplayWidth(dpy, screen); 204 sh = SH; 205 master = MASTER; 206 nmaster = NMASTER; 207 /* multihead support */ 208 selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask); 209 scan(); 210 211 /* main event loop, also reads status text from stdin */ 212 XSync(dpy, False); 213 214 while(running) { 215 XNextEvent(dpy, &ev); 216 if(handler[ev.type]) 217 (handler[ev.type])(&ev); /* call handler */ 218 } 219 cleanup(); 220 XCloseDisplay(dpy); 221 return 0; 222 }