all repos — dwm @ 29355bd38284ed9aec8d3ffabde61db73947c9f9

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 other_wm_running;
 47static const char version[] =
 48	"dwm-" VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
 49static int (*x_error_handler) (Display *, XErrorEvent *);
 50
 51static void
 52usage() {	error("usage: dwm [-v]\n"); }
 53
 54static void
 55scan_wins()
 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 int
 77win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
 78{
 79	Atom real;
 80	int format;
 81	unsigned long res, extra;
 82	int status;
 83
 84	status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
 85			&res, &extra, prop);
 86
 87	if(status != Success || *prop == 0) {
 88		return 0;
 89	}
 90	if(res == 0) {
 91		free((void *) *prop);
 92	}
 93	return res;
 94}
 95
 96int
 97win_proto(Window w)
 98{
 99	unsigned char *protocols;
100	long res;
101	int protos = 0;
102	int i;
103
104	res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols);
105	if(res <= 0) {
106		return protos;
107	}
108	for(i = 0; i < res; i++) {
109		if(protocols[i] == wm_atom[WMDelete])
110			protos |= WM_PROTOCOL_DELWIN;
111	}
112	free((char *) protocols);
113	return protos;
114}
115
116void
117send_message(Window w, Atom a, long value)
118{
119	XEvent e;
120
121	e.type = ClientMessage;
122	e.xclient.window = w;
123	e.xclient.message_type = a;
124	e.xclient.format = 32;
125	e.xclient.data.l[0] = value;
126	e.xclient.data.l[1] = CurrentTime;
127	XSendEvent(dpy, w, False, NoEventMask, &e);
128	XFlush(dpy);
129}
130
131/*
132 * There's no way to check accesses to destroyed windows, thus
133 * those cases are ignored (especially on UnmapNotify's).
134 * Other types of errors call Xlib's default error handler, which
135 * calls exit().
136 */
137int
138error_handler(Display *dpy, XErrorEvent *error)
139{
140	if(error->error_code == BadWindow
141			|| (error->request_code == X_SetInputFocus
142				&& error->error_code == BadMatch)
143			|| (error->request_code == X_PolyText8
144				&& error->error_code == BadDrawable)
145			|| (error->request_code == X_PolyFillRectangle
146				&& error->error_code == BadDrawable)
147			|| (error->request_code == X_PolySegment
148				&& error->error_code == BadDrawable)
149			|| (error->request_code == X_ConfigureWindow
150				&& error->error_code == BadMatch)
151			|| (error->request_code == X_GrabKey
152				&& error->error_code == BadAccess))
153		return 0;
154	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
155			error->request_code, error->error_code);
156	return x_error_handler(dpy, error); /* may call exit() */
157}
158
159/*
160 * Startup Error handler to check if another window manager
161 * is already running.
162 */
163static int
164startup_error_handler(Display *dpy, XErrorEvent *error)
165{
166	other_wm_running = True;
167	return -1;
168}
169
170static void
171cleanup()
172{
173	while(sel) {
174		resize(sel, True);
175		unmanage(sel);
176	}
177	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
178}
179
180void
181quit(Arg *arg)
182{
183	running = False;
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		error("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	other_wm_running = False;
218	XSetErrorHandler(startup_error_handler);
219	/* this causes an error if some other WM is running */
220	XSelectInput(dpy, root, SubstructureRedirectMask);
221	XFlush(dpy);
222
223	if(other_wm_running)
224		error("dwm: another window manager is already running\n");
225
226	XSetErrorHandler(0);
227	x_error_handler = XSetErrorHandler(error_handler);
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 = initcolor(BGCOLOR);
246	dc.fg = initcolor(FGCOLOR);
247	dc.border = initcolor(BORDERCOLOR);
248	initfont(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	draw_bar();
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_wins();
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			error("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				draw_bar();
319			}
320		}
321	}
322
323	cleanup();
324	XCloseDisplay(dpy);
325
326	return 0;
327}