main.c
changeset 43 989178822938
parent 34 cd30cce52b78
child 49 466591c2f967
equal deleted inserted replaced
42:040a7074d23c 43:989178822938
       
     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 "dwm.h"
       
    15 
       
    16 /********** CUSTOMIZE **********/
       
    17 
       
    18 char *tags[TLast] = {
       
    19 	[Tscratch] = "scratch",
       
    20 	[Tdev] = "dev",
       
    21 	[Tirc] = "irc",
       
    22 	[Twww] = "www",
       
    23 	[Twork] = "work",
       
    24 };
       
    25 
       
    26 /********** CUSTOMIZE **********/
       
    27 
       
    28 /* X structs */
       
    29 Display *dpy;
       
    30 Window root, barwin;
       
    31 Atom wm_atom[WMLast], net_atom[NetLast];
       
    32 Cursor cursor[CurLast];
       
    33 Bool running = True;
       
    34 Bool issel;
       
    35 
       
    36 char stext[1024];
       
    37 int tsel = Tdev; /* default tag */
       
    38 int screen, sx, sy, sw, sh, th;
       
    39 
       
    40 DC dc = {0};
       
    41 Client *clients = NULL;
       
    42 Client *stack = NULL;
       
    43 
       
    44 static Bool other_wm_running;
       
    45 static const char version[] =
       
    46 	"dwm - " VERSION ", (C)opyright MMVI Anselm R. Garbe\n";
       
    47 static int (*x_error_handler) (Display *, XErrorEvent *);
       
    48 
       
    49 static void
       
    50 usage() {	error("usage: dwm [-v]\n"); }
       
    51 
       
    52 static void
       
    53 scan_wins()
       
    54 {
       
    55 	unsigned int i, num;
       
    56 	Window *wins;
       
    57 	XWindowAttributes wa;
       
    58 	Window d1, d2;
       
    59 
       
    60 	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
       
    61 		for(i = 0; i < num; i++) {
       
    62 			if(!XGetWindowAttributes(dpy, wins[i], &wa))
       
    63 				continue;
       
    64 			if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
       
    65 				continue;
       
    66 			if(wa.map_state == IsViewable)
       
    67 				manage(wins[i], &wa);
       
    68 		}
       
    69 	}
       
    70 	if(wins)
       
    71 		XFree(wins);
       
    72 }
       
    73 
       
    74 static int
       
    75 win_property(Window w, Atom a, Atom t, long l, unsigned char **prop)
       
    76 {
       
    77 	Atom real;
       
    78 	int format;
       
    79 	unsigned long res, extra;
       
    80 	int status;
       
    81 
       
    82 	status = XGetWindowProperty(dpy, w, a, 0L, l, False, t, &real, &format,
       
    83 			&res, &extra, prop);
       
    84 
       
    85 	if(status != Success || *prop == 0) {
       
    86 		return 0;
       
    87 	}
       
    88 	if(res == 0) {
       
    89 		free((void *) *prop);
       
    90 	}
       
    91 	return res;
       
    92 }
       
    93 
       
    94 int
       
    95 win_proto(Window w)
       
    96 {
       
    97 	unsigned char *protocols;
       
    98 	long res;
       
    99 	int protos = 0;
       
   100 	int i;
       
   101 
       
   102 	res = win_property(w, wm_atom[WMProtocols], XA_ATOM, 20L, &protocols);
       
   103 	if(res <= 0) {
       
   104 		return protos;
       
   105 	}
       
   106 	for(i = 0; i < res; i++) {
       
   107 		if(protocols[i] == wm_atom[WMDelete])
       
   108 			protos |= WM_PROTOCOL_DELWIN;
       
   109 	}
       
   110 	free((char *) protocols);
       
   111 	return protos;
       
   112 }
       
   113 
       
   114 void
       
   115 send_message(Window w, Atom a, long value)
       
   116 {
       
   117 	XEvent e;
       
   118 
       
   119 	e.type = ClientMessage;
       
   120 	e.xclient.window = w;
       
   121 	e.xclient.message_type = a;
       
   122 	e.xclient.format = 32;
       
   123 	e.xclient.data.l[0] = value;
       
   124 	e.xclient.data.l[1] = CurrentTime;
       
   125 	XSendEvent(dpy, w, False, NoEventMask, &e);
       
   126 	XFlush(dpy);
       
   127 }
       
   128 
       
   129 /*
       
   130  * There's no way to check accesses to destroyed windows, thus
       
   131  * those cases are ignored (especially on UnmapNotify's).
       
   132  * Other types of errors call Xlib's default error handler, which
       
   133  * calls exit().
       
   134  */
       
   135 int
       
   136 error_handler(Display *dpy, XErrorEvent *error)
       
   137 {
       
   138 	if(error->error_code == BadWindow
       
   139 			|| (error->request_code == X_SetInputFocus
       
   140 				&& error->error_code == BadMatch)
       
   141 			|| (error->request_code == X_PolyText8
       
   142 				&& error->error_code == BadDrawable)
       
   143 			|| (error->request_code == X_PolyFillRectangle
       
   144 				&& error->error_code == BadDrawable)
       
   145 			|| (error->request_code == X_PolySegment
       
   146 				&& error->error_code == BadDrawable)
       
   147 			|| (error->request_code == X_ConfigureWindow
       
   148 				&& error->error_code == BadMatch)
       
   149 			|| (error->request_code == X_GrabKey
       
   150 				&& error->error_code == BadAccess))
       
   151 		return 0;
       
   152 	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
       
   153 			error->request_code, error->error_code);
       
   154 	return x_error_handler(dpy, error); /* may call exit() */
       
   155 }
       
   156 
       
   157 /*
       
   158  * Startup Error handler to check if another window manager
       
   159  * is already running.
       
   160  */
       
   161 static int
       
   162 startup_error_handler(Display *dpy, XErrorEvent *error)
       
   163 {
       
   164 	other_wm_running = True;
       
   165 	return -1;
       
   166 }
       
   167 
       
   168 static void
       
   169 cleanup()
       
   170 {
       
   171 	while(clients)
       
   172 		unmanage(clients);
       
   173 	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
       
   174 }
       
   175 
       
   176 void
       
   177 quit(void *aux)
       
   178 {
       
   179 	running = False;
       
   180 }
       
   181 
       
   182 int
       
   183 main(int argc, char *argv[])
       
   184 {
       
   185 	int i;
       
   186 	XSetWindowAttributes wa;
       
   187 	unsigned int mask;
       
   188 	Window w;
       
   189 	XEvent ev;
       
   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("dwm: 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("dwm: another window manager is already running\n");
       
   220 
       
   221 	sx = sy = 0;
       
   222 	sw = DisplayWidth(dpy, screen);
       
   223 	sh = DisplayHeight(dpy, screen);
       
   224 	issel = 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[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 
       
   235 	XChangeProperty(dpy, root, net_atom[NetSupported], XA_ATOM, 32,
       
   236 			PropModeReplace, (unsigned char *) net_atom, NetLast);
       
   237 
       
   238 
       
   239 	/* init cursors */
       
   240 	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
       
   241 	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
       
   242 	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
       
   243 
       
   244 	update_keys();
       
   245 
       
   246 	/* style */
       
   247 	dc.bg = initcolor(BGCOLOR);
       
   248 	dc.fg = initcolor(FGCOLOR);
       
   249 	dc.border = initcolor(BORDERCOLOR);
       
   250 	initfont(FONT);
       
   251 
       
   252 	th = dc.font.height + 4;
       
   253 
       
   254 	dc.drawable = XCreatePixmap(dpy, root, sw, th, DefaultDepth(dpy, screen));
       
   255 	dc.gc = XCreateGC(dpy, root, 0, 0);
       
   256 
       
   257 	wa.event_mask = SubstructureRedirectMask | EnterWindowMask \
       
   258 					| LeaveWindowMask;
       
   259 	wa.cursor = cursor[CurNormal];
       
   260 	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
       
   261 
       
   262 	scan_wins();
       
   263 
       
   264 	while(running) {
       
   265 		XNextEvent(dpy, &ev);
       
   266 		if(handler[ev.type])
       
   267 			(handler[ev.type])(&ev); /* call handler */
       
   268 	}
       
   269 
       
   270 	cleanup();
       
   271 	XCloseDisplay(dpy);
       
   272 
       
   273 	return 0;
       
   274 }