2wm

dual window manager prototype (minimalist dwm with no tags, just one view)
git clone git://git.suckless.org/2wm
Log | Files | Refs | README | LICENSE

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 }