all repos — dwm @ a1d0f819661f2be48f7a03ddd001f2a1a8f325e4

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	Window w;
194	XEvent ev;
195
196	for(i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
197		switch (argv[i][1]) {
198		case 'v':
199			fprintf(stdout, "%s", version);
200			exit(0);
201			break;
202		default:
203			usage();
204			break;
205		}
206	}
207
208	dpy = XOpenDisplay(0);
209	if(!dpy)
210		error("dwm: cannot connect X server\n");
211
212	screen = DefaultScreen(dpy);
213	root = RootWindow(dpy, screen);
214
215	/* check if another WM is already running */
216	other_wm_running = False;
217	XSetErrorHandler(startup_error_handler);
218	/* this causes an error if some other WM is running */
219	XSelectInput(dpy, root, SubstructureRedirectMask);
220	XFlush(dpy);
221
222	if(other_wm_running)
223		error("dwm: another window manager is already running\n");
224
225	XSetErrorHandler(0);
226	x_error_handler = XSetErrorHandler(error_handler);
227
228	/* init atoms */
229	wm_atom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
230	wm_atom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
231	net_atom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
232	net_atom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
233	XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
234			PropModeReplace, (unsigned char *) net_atom, NetLast);
235
236	/* init cursors */
237	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
238	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
239	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
240
241	update_keys();
242
243	/* style */
244	dc.bg = initcolor(BGCOLOR);
245	dc.fg = initcolor(FGCOLOR);
246	dc.border = initcolor(BORDERCOLOR);
247	initfont(FONT);
248
249	sx = sy = 0;
250	sw = DisplayWidth(dpy, screen);
251	sh = DisplayHeight(dpy, screen);
252	mw = (sw * MASTERW) / 100;
253
254	wa.override_redirect = 1;
255	wa.background_pixmap = ParentRelative;
256	wa.event_mask = ButtonPressMask | ExposureMask;
257
258	bx = by = 0;
259	bw = sw;
260	dc.h = bh = dc.font.height + 4;
261	barwin = XCreateWindow(dpy, root, bx, by, bw, bh, 0, DefaultDepth(dpy, screen),
262			CopyFromParent, DefaultVisual(dpy, screen),
263			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
264	XDefineCursor(dpy, barwin, cursor[CurNormal]);
265	XMapRaised(dpy, barwin);
266
267	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
268	dc.gc = XCreateGC(dpy, root, 0, 0);
269	draw_bar();
270
271	issel = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
272
273	wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
274					| LeaveWindowMask;
275	wa.cursor = cursor[CurNormal];
276
277	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
278
279	strcpy(stext, "dwm-"VERSION);
280	scan_wins();
281
282	/* main event loop, reads status text from stdin as well */
283Mainloop:
284	while(running) {
285		FD_ZERO(&rd);
286		FD_SET(0, &rd);
287		FD_SET(ConnectionNumber(dpy), &rd);
288
289		i = select(ConnectionNumber(dpy) + 1, &rd, 0, 0, 0);
290		if(i == -1 && errno == EINTR)
291			continue;
292		if(i < 0)
293			error("select failed\n");
294		else if(i > 0) {
295			if(FD_ISSET(ConnectionNumber(dpy), &rd) && XPending(dpy) > 0) {
296				XNextEvent(dpy, &ev);
297				if(handler[ev.type])
298					(handler[ev.type])(&ev); /* call handler */
299			}
300			if(FD_ISSET(0, &rd)) {
301				i = n = 0;
302				for(;;) {
303					if((i = getchar()) == EOF) {
304						stext[0] = 0;
305						goto Mainloop;
306					}
307					if(i == '\n' || n >= sizeof(stext) - 1)
308						break;
309					stext[n++] = i;
310				}
311				stext[n] = 0;
312				draw_bar();
313			}
314		}
315	}
316
317	cleanup();
318	XCloseDisplay(dpy);
319
320	return 0;
321}