all repos — dwm @ e7438365417ba4bb0cff56b44b029c797be18fe5

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