all repos — dwm @ 8a34fa50f75f4d6d8af234ac0c4f6d40b988d700

fork of suckless dynamic window manager

wm.c (view raw)

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