all repos — dwm @ dba23062bad40afb1a90f60b6897cf9e1ca5035b

fork of suckless dynamic window manager

main.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 <errno.h>
  7#include <stdarg.h>
  8#include <stdio.h>
  9#include <stdlib.h>
 10#include <string.h>
 11#include <unistd.h>
 12
 13#include <X11/cursorfont.h>
 14#include <X11/Xatom.h>
 15#include <X11/Xproto.h>
 16
 17#include "dwm.h"
 18
 19/********** CUSTOMIZE **********/
 20
 21char *tags[TLast] = {
 22	[Tscratch] = "scratch",
 23	[Tdev] = "dev",
 24	[Twww] = "www",
 25	[Twork] = "work",
 26};
 27
 28/********** CUSTOMIZE **********/
 29
 30/* X structs */
 31Display *dpy;
 32Window root, barwin;
 33Atom wm_atom[WMLast], net_atom[NetLast];
 34Cursor cursor[CurLast];
 35Bool running = True;
 36Bool issel;
 37
 38int tsel = Tdev; /* default tag */
 39int screen, sx, sy, sw, sh, bx, by, bw, bh, mw;
 40char stext[1024];
 41
 42DC dc = {0};
 43Client *clients = NULL;
 44Client *sel = NULL;
 45
 46static Bool otherwm;
 47static const char version[] =
 48	"dwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
 49static int (*xerrorxlib)(Display *, XErrorEvent *);
 50
 51static void
 52usage() {	eprint("usage: dwm [-v]\n"); }
 53
 54static void
 55scan()
 56{
 57	unsigned int i, num;
 58	Window *wins;
 59	XWindowAttributes wa;
 60	Window d1, d2;
 61
 62	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
 63		for(i = 0; i < num; i++) {
 64			if(!XGetWindowAttributes(dpy, wins[i], &wa))
 65				continue;
 66			if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
 67				continue;
 68			if(wa.map_state == IsViewable)
 69				manage(wins[i], &wa);
 70		}
 71	}
 72	if(wins)
 73		XFree(wins);
 74}
 75
 76static void
 77cleanup()
 78{
 79	while(sel) {
 80		resize(sel, True);
 81		unmanage(sel);
 82	}
 83	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
 84}
 85
 86void
 87quit(Arg *arg)
 88{
 89	running = False;
 90}
 91
 92static int
 93win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
 94{
 95	Atom real;
 96	int format;
 97	unsigned long res, extra;
 98	int status;
 99
100	status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
101			&res, &extra, prop);
102
103	if(status != Success || *prop == 0) {
104		return 0;
105	}
106	if(res == 0) {
107		free((void *) *prop);
108	}
109	return res;
110}
111
112int
113getproto(Window w)
114{
115	unsigned char *protocols;
116	long res;
117	int protos = 0;
118	int i;
119
120	res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols);
121	if(res <= 0) {
122		return protos;
123	}
124	for(i = 0; i < res; i++) {
125		if(protocols[i] == wm_atom[WMDelete])
126			protos |= WM_PROTOCOL_DELWIN;
127	}
128	free((char *) protocols);
129	return protos;
130}
131
132void
133sendevent(Window w, Atom a, long value)
134{
135	XEvent e;
136
137	e.type = ClientMessage;
138	e.xclient.window = w;
139	e.xclient.message_type = a;
140	e.xclient.format = 32;
141	e.xclient.data.l[0] = value;
142	e.xclient.data.l[1] = CurrentTime;
143	XSendEvent(dpy, w, False, NoEventMask, &e);
144	XFlush(dpy);
145}
146
147/*
148 * Startup Error handler to check if another window manager
149 * is already running.
150 */
151static int
152xerrorstart(Display *dsply, XErrorEvent *ee)
153{
154	otherwm = True;
155	return -1;
156}
157
158/*
159 * There's no way to check accesses to destroyed windows, thus
160 * those cases are ignored (especially on UnmapNotify's).
161 * Other types of errors call Xlib's default error handler, which
162 * calls exit().
163 */
164int
165xerror(Display *dpy, XErrorEvent *ee)
166{
167	if(ee->error_code == BadWindow
168			|| (ee->request_code == X_SetInputFocus
169				&& ee->error_code == BadMatch)
170			|| (ee->request_code == X_PolyText8
171				&& ee->error_code == BadDrawable)
172			|| (ee->request_code == X_PolyFillRectangle
173				&& ee->error_code == BadDrawable)
174			|| (ee->request_code == X_PolySegment
175				&& ee->error_code == BadDrawable)
176			|| (ee->request_code == X_ConfigureWindow
177				&& ee->error_code == BadMatch)
178			|| (ee->request_code == X_GrabKey
179				&& ee->error_code == BadAccess))
180		return 0;
181	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
182			ee->request_code, ee->error_code);
183	return xerrorxlib(dpy, ee); /* may call exit() */
184}
185
186int
187main(int argc, char *argv[])
188{
189	int i, n;
190	fd_set rd;
191	XSetWindowAttributes wa;
192	unsigned int mask;
193	Bool readstdin = True;
194	Window w;
195	XEvent ev;
196
197	for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
198		switch (argv[i][1]) {
199		case 'v':
200			fprintf(stdout, "%s", version);
201			exit(0);
202			break;
203		default:
204			usage();
205			break;
206		}
207	}
208
209	dpy = XOpenDisplay(0);
210	if(!dpy)
211		eprint("dwm: cannot connect X server\n");
212
213	screen = DefaultScreen(dpy);
214	root = RootWindow(dpy, screen);
215
216	/* check if another WM is already running */
217	otherwm = False;
218	XSetErrorHandler(xerrorstart);
219	/* this causes an error if some other WM is running */
220	XSelectInput(dpy, root, SubstructureRedirectMask);
221	XFlush(dpy);
222
223	if(otherwm)
224		eprint("dwm: another window manager is already running\n");
225
226	XSetErrorHandler(0);
227	xerrorxlib = XSetErrorHandler(xerror);
228
229	/* init atoms */
230	wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
231	wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
232	net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
233	net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
234	XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
235			PropModeReplace, (unsigned char *) net_atom, NetLast);
236
237	/* init cursors */
238	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
239	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
240	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
241
242	grabkeys();
243
244	/* style */
245	dc.bg = getcolor(BGCOLOR);
246	dc.fg = getcolor(FGCOLOR);
247	dc.border = getcolor(BORDERCOLOR);
248	setfont(FONT);
249
250	sx = sy = 0;
251	sw = DisplayWidth(dpy, screen);
252	sh = DisplayHeight(dpy, screen);
253	mw = (sw * MASTERW) / 100;
254
255	wa.override_redirect = 1;
256	wa.background_pixmap = ParentRelative;
257	wa.event_mask = ButtonPressMask | ExposureMask;
258
259	bx = by = 0;
260	bw = sw;
261	dc.h = bh = dc.font.height + 4;
262	barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen),
263			CopyFromParent, DefaultVisual(dpy, screen),
264			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
265	XDefineCursor(dpy, barwin, cursor[CurNormal]);
266	XMapRaised(dpy, barwin);
267
268	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
269	dc.gc = XCreateGC(dpy, root, 0, 0);
270	drawstatus();
271
272	issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
273
274	wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
275					| LeaveWindowMask;
276	wa.cursor = cursor[CurNormal];
277
278	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
279
280	strcpy(stext, "dwm-"VERSION);
281	scan();
282
283	/* main event loop, reads status text from stdin as well */
284Mainloop:
285	while(running) {
286		FD_ZERO(&rd);
287		if(readstdin)
288			FD_SET(STDIN_FILENO, &rd);
289		FD_SET(ConnectionNumber(dpy), &rd);
290
291		i = select(ConnectionNumber(dpy) + 1, &rd, 0, 0, 0);
292		if(i == -1 && errno == EINTR)
293			continue;
294		if(i < 0)
295			eprint("select failed\n");
296		else if(i > 0) {
297			if(FD_ISSET(ConnectionNumber(dpy), &rd)) {
298				while(XPending(dpy)) {
299					XNextEvent(dpy, &ev);
300					if(handler[ev.type])
301						(handler[ev.type])(&ev); /* call handler */
302				}
303			}
304			if(readstdin && FD_ISSET(STDIN_FILENO, &rd)) {
305				i = n = 0;
306				for(;;) {
307					if((i = getchar()) == EOF) {
308						/* broken pipe/end of producer */
309						readstdin = False;
310						strcpy(stext, "broken pipe");
311						goto Mainloop;
312					}
313					if(i == '\n' || n >= sizeof(stext) - 1)
314						break;
315					stext[n++] = i;
316				}
317				stext[n] = 0;
318				drawstatus();
319			}
320		}
321	}
322
323	cleanup();
324	XCloseDisplay(dpy);
325
326	return 0;
327}