all repos — dwm @ 39677ec76616fe4165ef92afb14db2bef2488e30

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