wm.c
changeset 0 491f34c11291
child 2 a79188fe4a40
equal deleted inserted replaced
-1:000000000000 0:491f34c11291
       
     1 /*
       
     2  * (C)opyright MMVI Anselm R. Garbe <garbeam at gmail dot com>
       
     3  * See LICENSE file for license details.
       
     4  */
       
     5 
       
     6 #include <stdarg.h>
       
     7 #include <stdio.h>
       
     8 #include <stdlib.h>
       
     9 
       
    10 #include <X11/cursorfont.h>
       
    11 #include <X11/Xatom.h>
       
    12 #include <X11/Xproto.h>
       
    13 
       
    14 #include "wm.h"
       
    15 
       
    16 Display *dpy;
       
    17 Window root;
       
    18 XRectangle rect;
       
    19 int screen, sel_screen;
       
    20 Atom wm_atom[WMLast];
       
    21 Atom net_atom[NetLast];
       
    22 Cursor cursor[CurLast];
       
    23 unsigned int kmask, numlock_mask;
       
    24 Pixmap pmap;
       
    25 
       
    26 enum { WM_PROTOCOL_DELWIN = 1 };
       
    27 
       
    28 static Bool other_wm_running;
       
    29 static int (*x_error_handler) (Display *, XErrorEvent *);
       
    30 static char version[] = "gridwm - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
       
    31 
       
    32 static void
       
    33 usage()
       
    34 {
       
    35 	fputs("usage: gridwm [-v]\n", stderr);
       
    36 	exit(1);
       
    37 }
       
    38 
       
    39 void
       
    40 error(char *errstr, ...) {
       
    41 	va_list ap;
       
    42 	va_start(ap, errstr);
       
    43 	vfprintf(stderr, errstr, ap);
       
    44 	va_end(ap);
       
    45 	exit(1);
       
    46 }
       
    47 
       
    48 static void
       
    49 scan_wins()
       
    50 {
       
    51 	unsigned int i, num;
       
    52 	Window *wins;
       
    53 	XWindowAttributes wa;
       
    54 	Window d1, d2;
       
    55 
       
    56 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
       
    57 		for(i = 0; i < num; i++) {
       
    58 			if(!XGetWindowAttributes(dpy, wins[i], &wa))
       
    59 				continue;
       
    60 			if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
       
    61 				continue;
       
    62 			if(wa.map_state == IsViewable)
       
    63 				/*manage*/;
       
    64 		}
       
    65 	}
       
    66 	if(wins)
       
    67 		XFree(wins);
       
    68 }
       
    69 
       
    70 static int
       
    71 win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
       
    72 {
       
    73 	Atom real;
       
    74 	int format;
       
    75 	unsigned long res, extra;
       
    76 	int status;
       
    77 
       
    78 	status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
       
    79 			&res, &extra, prop);
       
    80 
       
    81 	if(status != Success || *prop == 0) {
       
    82 		return 0;
       
    83 	}
       
    84 	if(res == 0) {
       
    85 		free((void *) *prop);
       
    86 	}
       
    87 	return res;
       
    88 }
       
    89 
       
    90 int
       
    91 win_proto(Window w)
       
    92 {
       
    93 	Atom *protocols;
       
    94 	long res;
       
    95 	int protos = 0;
       
    96 	int i;
       
    97 
       
    98 	res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L,
       
    99 			((unsigned char **) &protocols));
       
   100 	if(res <= 0) {
       
   101 		return protos;
       
   102 	}
       
   103 	for(i = 0; i < res; i++) {
       
   104 		if(protocols[i] == wm_atom[WMDelete])
       
   105 			protos |= WM_PROTOCOL_DELWIN;
       
   106 	}
       
   107 	free((char *) protocols);
       
   108 	return protos;
       
   109 }
       
   110 
       
   111 /*
       
   112  * There's no way to check accesses to destroyed windows, thus
       
   113  * those cases are ignored (especially on UnmapNotify's).
       
   114  * Other types of errors call Xlib's default error handler, which
       
   115  * calls exit().
       
   116  */
       
   117 static int
       
   118 error_handler(Display *dpy, XErrorEvent *error)
       
   119 {
       
   120 	if(error->error_code == BadWindow
       
   121 			|| (error->request_code == X_SetInputFocus
       
   122 				&& error->error_code == BadMatch)
       
   123 			|| (error->request_code == X_PolyText8
       
   124 				&& error->error_code == BadDrawable)
       
   125 			|| (error->request_code == X_PolyFillRectangle
       
   126 				&& error->error_code == BadDrawable)
       
   127 			|| (error->request_code == X_PolySegment
       
   128 				&& error->error_code == BadDrawable)
       
   129 			|| (error->request_code == X_ConfigureWindow
       
   130 				&& error->error_code == BadMatch)
       
   131 			|| (error->request_code == X_GrabKey
       
   132 				&& error->error_code == BadAccess))
       
   133 		return 0;
       
   134 	fprintf(stderr, "gridwm: fatal error: request code=%d, error code=%d\n",
       
   135 			error->request_code, error->error_code);
       
   136 	return x_error_handler(dpy, error); /* may call exit() */
       
   137 }
       
   138 
       
   139 /*
       
   140  * Startup Error handler to check if another window manager
       
   141  * is already running.
       
   142  */
       
   143 static int
       
   144 startup_error_handler(Display *dpy, XErrorEvent *error)
       
   145 {
       
   146 	other_wm_running = True;
       
   147 	return -1;
       
   148 }
       
   149 
       
   150 static void
       
   151 init_lock_keys()
       
   152 {
       
   153 	XModifierKeymap *modmap;
       
   154 	KeyCode numlock;
       
   155 	int i;
       
   156 	static int masks[] = {
       
   157 		ShiftMask, LockMask, ControlMask, Mod1Mask,
       
   158 		Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
       
   159 	};
       
   160 
       
   161 	numlock_mask = 0;
       
   162 	modmap = XGetModifierMapping(dpy);
       
   163 	numlock = XKeysymToKeycode(dpy, XStringToKeysym("Num_Lock"));
       
   164 
       
   165 	if(modmap && modmap->max_keypermod > 0) {
       
   166 		int max = (sizeof(masks) / sizeof(int)) * modmap->max_keypermod;
       
   167 		for(i = 0; i < max; i++)
       
   168 			if(numlock && (modmap->modifiermap[i] == numlock))
       
   169 				numlock_mask = masks[i / modmap->max_keypermod];
       
   170 	}
       
   171 	XFreeModifiermap(modmap);
       
   172 
       
   173 	kmask = 255 & ~(numlock_mask | LockMask);
       
   174 }
       
   175 
       
   176 static void
       
   177 cleanup()
       
   178 {
       
   179 	/*
       
   180 	Client *c;
       
   181 	for(c=client; c; c=c->next)
       
   182 		reparent_client(c, root, c->sel->rect.x, c->sel->rect.y);
       
   183 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
       
   184 	*/
       
   185 }
       
   186 
       
   187 int
       
   188 main(int argc, char *argv[])
       
   189 {
       
   190 	int i;
       
   191 	XSetWindowAttributes wa;
       
   192 	unsigned int mask;
       
   193 	Window w;
       
   194 
       
   195 	/* command line args */
       
   196 	for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
       
   197 		switch (argv[i][1]) {
       
   198 		case 'v':
       
   199 			fprintf(stdout, "%s", version);
       
   200 			exit(0);
       
   201 			break;
       
   202 		default:
       
   203 			usage();
       
   204 			break;
       
   205 		}
       
   206 	}
       
   207 
       
   208 	dpy = XOpenDisplay(0);
       
   209 	if(!dpy)
       
   210 		error("gridwm: cannot connect X server\n");
       
   211 
       
   212 	screen = DefaultScreen(dpy);
       
   213 	root = RootWindow(dpy, screen);
       
   214 
       
   215 	/* check if another WM is already running */
       
   216 	other_wm_running = False;
       
   217 	XSetErrorHandler(startup_error_handler);
       
   218 	/* this causes an error if some other WM is running */
       
   219 	XSelectInput(dpy, root, SubstructureRedirectMask);
       
   220 	XSync(dpy, False);
       
   221 
       
   222 	if(other_wm_running)
       
   223 		error("gridwm: another window manager is already running\n");
       
   224 
       
   225 	rect.x = rect.y = 0;
       
   226 	rect.width = DisplayWidth(dpy, screen);
       
   227 	rect.height = DisplayHeight(dpy, screen);
       
   228 	sel_screen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
       
   229 
       
   230 	XSetErrorHandler(0);
       
   231 	x_error_handler = XSetErrorHandler(error_handler);
       
   232 
       
   233 	/* init atoms */
       
   234 	wm_atom[WMState] = XInternAtom(dpy, "WM_STATE", False);
       
   235 	wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
       
   236 	wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
       
   237 	net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
       
   238 	net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
       
   239 
       
   240 	XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
       
   241 			PropModeReplace, (unsigned char *) net_atom, NetLast);
       
   242 
       
   243 
       
   244 	/* init cursors */
       
   245 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
       
   246 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
       
   247 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
       
   248 
       
   249 	init_lock_keys();
       
   250 
       
   251 	pmap = XCreatePixmap(dpy, root, rect.width, rect.height,
       
   252 			DefaultDepth(dpy, screen));
       
   253 
       
   254 	wa.event_mask = SubstructureRedirectMask | EnterWindowMask | LeaveWindowMask;
       
   255 	wa.cursor = cursor[CurNormal];
       
   256 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
       
   257 
       
   258 	scan_wins();
       
   259 
       
   260 	cleanup();
       
   261 	XCloseDisplay(dpy);
       
   262 
       
   263 	return 0;
       
   264 }