diff main.c @ 0:7024076fa948

initial add
author paulo@localhost
date Sun, 22 Mar 2009 23:26:35 -0700
parents
children faa4cb9d7bd6
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/main.c	Sun Mar 22 23:26:35 2009 -0700
     1.3 @@ -0,0 +1,338 @@
     1.4 +/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
     1.5 + * See LICENSE file for license details.
     1.6 + */
     1.7 +
     1.8 +#include "dwm.h"
     1.9 +#include <errno.h>
    1.10 +#include <locale.h>
    1.11 +#include <stdio.h>
    1.12 +#include <stdlib.h>
    1.13 +#include <string.h>
    1.14 +#include <unistd.h>
    1.15 +#include <sys/select.h>
    1.16 +#include <X11/cursorfont.h>
    1.17 +#include <X11/keysym.h>
    1.18 +#include <X11/Xatom.h>
    1.19 +#include <X11/Xproto.h>
    1.20 +
    1.21 +/* extern */
    1.22 +
    1.23 +char stext[256];
    1.24 +int screen, sx, sy, sw, sh, wax, way, waw, wah;
    1.25 +unsigned int bh, ntags, numlockmask;
    1.26 +Atom wmatom[WMLast], netatom[NetLast];
    1.27 +Bool *seltag;
    1.28 +Bool selscreen = True;
    1.29 +Client *clients = NULL;
    1.30 +Client *sel = NULL;
    1.31 +Client *stack = NULL;
    1.32 +Cursor cursor[CurLast];
    1.33 +Display *dpy;
    1.34 +DC dc = {0};
    1.35 +Window root, barwin;
    1.36 +
    1.37 +/* static */
    1.38 +
    1.39 +static int (*xerrorxlib)(Display *, XErrorEvent *);
    1.40 +static Bool otherwm, readin;
    1.41 +static Bool running = True;
    1.42 +
    1.43 +static void
    1.44 +cleanup(void) {
    1.45 +	close(STDIN_FILENO);
    1.46 +	while(stack) {
    1.47 +		if(stack->isbanned)
    1.48 +			XMoveWindow(dpy, stack->win, stack->x, stack->y);
    1.49 +		unmanage(stack);
    1.50 +	}
    1.51 +	if(dc.font.set)
    1.52 +		XFreeFontSet(dpy, dc.font.set);
    1.53 +	else
    1.54 +		XFreeFont(dpy, dc.font.xfont);
    1.55 +	XUngrabKey(dpy, AnyKey, AnyModifier, root);
    1.56 +	XFreePixmap(dpy, dc.drawable);
    1.57 +	XFreeGC(dpy, dc.gc);
    1.58 +	XDestroyWindow(dpy, barwin);
    1.59 +	XFreeCursor(dpy, cursor[CurNormal]);
    1.60 +	XFreeCursor(dpy, cursor[CurResize]);
    1.61 +	XFreeCursor(dpy, cursor[CurMove]);
    1.62 +	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
    1.63 +	XSync(dpy, False);
    1.64 +	free(seltag);
    1.65 +}
    1.66 +
    1.67 +static unsigned long
    1.68 +initcolor(const char *colstr) {
    1.69 +	Colormap cmap = DefaultColormap(dpy, screen);
    1.70 +	XColor color;
    1.71 +
    1.72 +	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
    1.73 +		eprint("error, cannot allocate color '%s'\n", colstr);
    1.74 +	return color.pixel;
    1.75 +}
    1.76 +
    1.77 +static void
    1.78 +initfont(const char *fontstr) {
    1.79 +	char *def, **missing;
    1.80 +	int i, n;
    1.81 +
    1.82 +	missing = NULL;
    1.83 +	if(dc.font.set)
    1.84 +		XFreeFontSet(dpy, dc.font.set);
    1.85 +	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
    1.86 +	if(missing) {
    1.87 +		while(n--)
    1.88 +			fprintf(stderr, "missing fontset: %s\n", missing[n]);
    1.89 +		XFreeStringList(missing);
    1.90 +	}
    1.91 +	if(dc.font.set) {
    1.92 +		XFontSetExtents *font_extents;
    1.93 +		XFontStruct **xfonts;
    1.94 +		char **font_names;
    1.95 +		dc.font.ascent = dc.font.descent = 0;
    1.96 +		font_extents = XExtentsOfFontSet(dc.font.set);
    1.97 +		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
    1.98 +		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
    1.99 +			if(dc.font.ascent < (*xfonts)->ascent)
   1.100 +				dc.font.ascent = (*xfonts)->ascent;
   1.101 +			if(dc.font.descent < (*xfonts)->descent)
   1.102 +				dc.font.descent = (*xfonts)->descent;
   1.103 +			xfonts++;
   1.104 +		}
   1.105 +	}
   1.106 +	else {
   1.107 +		if(dc.font.xfont)
   1.108 +			XFreeFont(dpy, dc.font.xfont);
   1.109 +		dc.font.xfont = NULL;
   1.110 +		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
   1.111 +			eprint("error, cannot load font: '%s'\n", fontstr);
   1.112 +		dc.font.ascent = dc.font.xfont->ascent;
   1.113 +		dc.font.descent = dc.font.xfont->descent;
   1.114 +	}
   1.115 +	dc.font.height = dc.font.ascent + dc.font.descent;
   1.116 +}
   1.117 +
   1.118 +static void
   1.119 +scan(void) {
   1.120 +	unsigned int i, num;
   1.121 +	Window *wins, d1, d2;
   1.122 +	XWindowAttributes wa;
   1.123 +
   1.124 +	wins = NULL;
   1.125 +	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
   1.126 +		for(i = 0; i < num; i++) {
   1.127 +			if(!XGetWindowAttributes(dpy, wins[i], &wa)
   1.128 +			|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
   1.129 +				continue;
   1.130 +			if(wa.map_state == IsViewable)
   1.131 +				manage(wins[i], &wa);
   1.132 +		}
   1.133 +	}
   1.134 +	if(wins)
   1.135 +		XFree(wins);
   1.136 +}
   1.137 +
   1.138 +static void
   1.139 +setup(void) {
   1.140 +	int i, j;
   1.141 +	unsigned int mask;
   1.142 +	Window w;
   1.143 +	XModifierKeymap *modmap;
   1.144 +	XSetWindowAttributes wa;
   1.145 +
   1.146 +	/* init atoms */
   1.147 +	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
   1.148 +	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
   1.149 +	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
   1.150 +	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
   1.151 +	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
   1.152 +	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
   1.153 +			PropModeReplace, (unsigned char *) netatom, NetLast);
   1.154 +	/* init cursors */
   1.155 +	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
   1.156 +	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
   1.157 +	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
   1.158 +	/* init modifier map */
   1.159 +	numlockmask = 0;
   1.160 +	modmap = XGetModifierMapping(dpy);
   1.161 +	for (i = 0; i < 8; i++)
   1.162 +		for (j = 0; j < modmap->max_keypermod; j++) {
   1.163 +			if(modmap->modifiermap[i * modmap->max_keypermod + j]
   1.164 +					== XKeysymToKeycode(dpy, XK_Num_Lock))
   1.165 +				numlockmask = (1 << i);
   1.166 +		}
   1.167 +	XFreeModifiermap(modmap);
   1.168 +	/* select for events */
   1.169 +	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
   1.170 +		| EnterWindowMask | LeaveWindowMask;
   1.171 +	wa.cursor = cursor[CurNormal];
   1.172 +	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
   1.173 +	grabkeys();
   1.174 +	compileregs();
   1.175 +	for(ntags = 0; tags[ntags]; ntags++);
   1.176 +	seltag = emallocz(sizeof(Bool) * ntags);
   1.177 +	seltag[0] = True;
   1.178 +	/* style */
   1.179 +	dc.norm[ColBorder] = initcolor(NORMBORDERCOLOR);
   1.180 +	dc.norm[ColBG] = initcolor(NORMBGCOLOR);
   1.181 +	dc.norm[ColFG] = initcolor(NORMFGCOLOR);
   1.182 +	dc.sel[ColBorder] = initcolor(SELBORDERCOLOR);
   1.183 +	dc.sel[ColBG] = initcolor(SELBGCOLOR);
   1.184 +	dc.sel[ColFG] = initcolor(SELFGCOLOR);
   1.185 +	initfont(FONT);
   1.186 +	/* geometry */
   1.187 +	sx = sy = 0;
   1.188 +	sw = DisplayWidth(dpy, screen);
   1.189 +	sh = DisplayHeight(dpy, screen);
   1.190 +	initlayouts();
   1.191 +	/* bar */
   1.192 +	dc.h = bh = dc.font.height + 2;
   1.193 +	wa.override_redirect = 1;
   1.194 +	wa.background_pixmap = ParentRelative;
   1.195 +	wa.event_mask = ButtonPressMask | ExposureMask;
   1.196 +	barwin = XCreateWindow(dpy, root, sx, sy + (TOPBAR ? 0 : sh - bh), sw, bh, 0,
   1.197 +			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
   1.198 +			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
   1.199 +	XDefineCursor(dpy, barwin, cursor[CurNormal]);
   1.200 +	XMapRaised(dpy, barwin);
   1.201 +	strcpy(stext, "dwm-"VERSION);
   1.202 +	/* windowarea */
   1.203 +	wax = sx;
   1.204 +	way = sy + (TOPBAR ? bh : 0);
   1.205 +	wah = sh - bh;
   1.206 +	waw = sw;
   1.207 +	/* pixmap for everything */
   1.208 +	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
   1.209 +	dc.gc = XCreateGC(dpy, root, 0, 0);
   1.210 +	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
   1.211 +	/* multihead support */
   1.212 +	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
   1.213 +}
   1.214 +
   1.215 +/*
   1.216 + * Startup Error handler to check if another window manager
   1.217 + * is already running.
   1.218 + */
   1.219 +static int
   1.220 +xerrorstart(Display *dsply, XErrorEvent *ee) {
   1.221 +	otherwm = True;
   1.222 +	return -1;
   1.223 +}
   1.224 +
   1.225 +/* extern */
   1.226 +
   1.227 +void
   1.228 +sendevent(Window w, Atom a, long value) {
   1.229 +	XEvent e;
   1.230 +
   1.231 +	e.type = ClientMessage;
   1.232 +	e.xclient.window = w;
   1.233 +	e.xclient.message_type = a;
   1.234 +	e.xclient.format = 32;
   1.235 +	e.xclient.data.l[0] = value;
   1.236 +	e.xclient.data.l[1] = CurrentTime;
   1.237 +	XSendEvent(dpy, w, False, NoEventMask, &e);
   1.238 +	XSync(dpy, False);
   1.239 +}
   1.240 +
   1.241 +void
   1.242 +quit(Arg *arg) {
   1.243 +	readin = running = False;
   1.244 +}
   1.245 +
   1.246 +/* There's no way to check accesses to destroyed windows, thus those cases are
   1.247 + * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
   1.248 + * default error handler, which may call exit.
   1.249 + */
   1.250 +int
   1.251 +xerror(Display *dpy, XErrorEvent *ee) {
   1.252 +	if(ee->error_code == BadWindow
   1.253 +	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
   1.254 +	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
   1.255 +	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
   1.256 +	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
   1.257 +	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
   1.258 +	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
   1.259 +	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
   1.260 +		return 0;
   1.261 +	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
   1.262 +		ee->request_code, ee->error_code);
   1.263 +	return xerrorxlib(dpy, ee); /* may call exit */
   1.264 +}
   1.265 +
   1.266 +int
   1.267 +main(int argc, char *argv[]) {
   1.268 +	char *p;
   1.269 +	int r, xfd;
   1.270 +	fd_set rd;
   1.271 +	XEvent ev;
   1.272 +
   1.273 +	if(argc == 2 && !strncmp("-v", argv[1], 3))
   1.274 +		eprint("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n");
   1.275 +	else if(argc != 1)
   1.276 +		eprint("usage: dwm [-v]\n");
   1.277 +	setlocale(LC_CTYPE, "");
   1.278 +	if(!(dpy = XOpenDisplay(0)))
   1.279 +		eprint("dwm: cannot open display\n");
   1.280 +	xfd = ConnectionNumber(dpy);
   1.281 +	screen = DefaultScreen(dpy);
   1.282 +	root = RootWindow(dpy, screen);
   1.283 +	otherwm = False;
   1.284 +	XSetErrorHandler(xerrorstart);
   1.285 +	/* this causes an error if some other window manager is running */
   1.286 +	XSelectInput(dpy, root, SubstructureRedirectMask);
   1.287 +	XSync(dpy, False);
   1.288 +	if(otherwm)
   1.289 +		eprint("dwm: another window manager is already running\n");
   1.290 +
   1.291 +	XSync(dpy, False);
   1.292 +	XSetErrorHandler(NULL);
   1.293 +	xerrorxlib = XSetErrorHandler(xerror);
   1.294 +	XSync(dpy, False);
   1.295 +	setup();
   1.296 +	drawstatus();
   1.297 +	scan();
   1.298 +
   1.299 +	/* main event loop, also reads status text from stdin */
   1.300 +	XSync(dpy, False);
   1.301 +	readin = True;
   1.302 +	while(running) {
   1.303 +		FD_ZERO(&rd);
   1.304 +		if(readin)
   1.305 +			FD_SET(STDIN_FILENO, &rd);
   1.306 +		FD_SET(xfd, &rd);
   1.307 +		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
   1.308 +			if(errno == EINTR)
   1.309 +				continue;
   1.310 +			eprint("select failed\n");
   1.311 +		}
   1.312 +		if(FD_ISSET(STDIN_FILENO, &rd)) {
   1.313 +			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
   1.314 +			case -1:
   1.315 +				strncpy(stext, strerror(errno), sizeof stext - 1);
   1.316 +				stext[sizeof stext - 1] = '\0';
   1.317 +				readin = False;
   1.318 +				break;
   1.319 +			case 0:
   1.320 +				strncpy(stext, "EOF", 4);
   1.321 +				readin = False;
   1.322 +				break;
   1.323 +			default:
   1.324 +				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
   1.325 +				for(; p >= stext && *p != '\n'; --p);
   1.326 +				if(p > stext)
   1.327 +					strncpy(stext, p + 1, sizeof stext);
   1.328 +			}
   1.329 +			drawstatus();
   1.330 +		}
   1.331 +		if(FD_ISSET(xfd, &rd))
   1.332 +			while(XPending(dpy)) {
   1.333 +				XNextEvent(dpy, &ev);
   1.334 +				if(handler[ev.type])
   1.335 +					(handler[ev.type])(&ev); /* call handler */
   1.336 +			}
   1.337 +	}
   1.338 +	cleanup();
   1.339 +	XCloseDisplay(dpy);
   1.340 +	return 0;
   1.341 +}