aewl

changeset 759:45f23169563e

renamed dwm to aewl updated copyright notices updated man page
author meillo@marmaro.de
date Fri, 30 May 2008 22:18:18 +0200
parents bc512840e5a5
children 014c4cb1ae4a
files LICENSE Makefile aewl.1 aewl.c config.mk dwm.1 dwm.c
diffstat 7 files changed, 1943 insertions(+), 1962 deletions(-) [+]
line diff
     1.1 --- a/LICENSE	Fri May 30 21:57:51 2008 +0200
     1.2 +++ b/LICENSE	Fri May 30 22:18:18 2008 +0200
     1.3 @@ -2,21 +2,22 @@
     1.4  
     1.5  (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
     1.6  (C)opyright MMVI-MMVII Sander van Dijk <a dot h dot vandijk at gmail dot com>
     1.7 +(C)opyright MMVIII markus schnalke <meillo at marmaro dot de>
     1.8  
     1.9  Permission is hereby granted, free of charge, to any person obtaining a
    1.10  copy of this software and associated documentation files (the "Software"),
    1.11  to deal in the Software without restriction, including without limitation
    1.12  the rights to use, copy, modify, merge, publish, distribute, sublicense,
    1.13 -and/or sell copies of the Software, and to permit persons to whom the 
    1.14 +and/or sell copies of the Software, and to permit persons to whom the
    1.15  Software is furnished to do so, subject to the following conditions:
    1.16  
    1.17 -The above copyright notice and this permission notice shall be included in 
    1.18 -all copies or substantial portions of the Software. 
    1.19 +The above copyright notice and this permission notice shall be included in
    1.20 +all copies or substantial portions of the Software.
    1.21  
    1.22 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
    1.23 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
    1.24 -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
    1.25 -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
    1.26 -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
    1.27 -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
    1.28 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    1.29 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    1.30 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
    1.31 +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    1.32 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    1.33 +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    1.34  DEALINGS IN THE SOFTWARE.
     2.1 --- a/Makefile	Fri May 30 21:57:51 2008 +0200
     2.2 +++ b/Makefile	Fri May 30 22:18:18 2008 +0200
     2.3 @@ -1,53 +1,53 @@
     2.4 -# dwm - dynamic window manager
     2.5 +# aewl - a fork of dwm, the dynamic window manager
     2.6  #   (C)opyright MMVI-MMVII Anselm R. Garbe
     2.7  
     2.8  include config.mk
     2.9  
    2.10  
    2.11 -all: options dwm
    2.12 +all: options aewl
    2.13  
    2.14  options:
    2.15 -	@echo dwm build options:
    2.16 +	@echo aewl build options:
    2.17  	@echo "CFLAGS   = ${CFLAGS}"
    2.18  	@echo "LDFLAGS  = ${LDFLAGS}"
    2.19  	@echo "CC       = ${CC}"
    2.20  
    2.21 -dwm.o: dwm.c config.h config.mk
    2.22 +aewl.o: aewl.c config.h config.mk
    2.23  	@echo CC $<
    2.24  	@${CC} -c ${CFLAGS} $<
    2.25  
    2.26 -dwm: dwm.o
    2.27 +aewl: aewl.o
    2.28  	@echo CC -o $@
    2.29 -	@${CC} -o $@ dwm.o ${LDFLAGS}
    2.30 +	@${CC} -o $@ aewl.o ${LDFLAGS}
    2.31  	@strip $@
    2.32  
    2.33  clean:
    2.34  	@echo cleaning
    2.35 -	@rm -f dwm *.o dwm-${VERSION}.tar.gz
    2.36 +	@rm -f aewl *.o aewl-*.tar.gz
    2.37  
    2.38  dist: clean
    2.39  	@echo creating dist tarball
    2.40 -	@mkdir -p dwm-${VERSION}
    2.41 -	@cp -R LICENSE Makefile README config.*.h config.mk \
    2.42 -		dwm.1 dwm.h ${SRC} dwm-${VERSION}
    2.43 -	@tar -cf dwm-${VERSION}.tar dwm-${VERSION}
    2.44 -	@gzip dwm-${VERSION}.tar
    2.45 -	@rm -rf dwm-${VERSION}
    2.46 +	@mkdir -p aewl-${VERSION}
    2.47 +	@cp -R LICENSE Makefile README config.h config.mk \
    2.48 +		aewl.1 aewl.h ${SRC} aewl-${VERSION}
    2.49 +	@tar -cf aewl-${VERSION}.tar aewl-${VERSION}
    2.50 +	@gzip aewl-${VERSION}.tar
    2.51 +	@rm -rf aewl-${VERSION}
    2.52  
    2.53  install: all
    2.54  	@echo installing executable file to ${DESTDIR}${PREFIX}/bin
    2.55  	@mkdir -p ${DESTDIR}${PREFIX}/bin
    2.56 -	@cp -f dwm ${DESTDIR}${PREFIX}/bin
    2.57 -	@chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
    2.58 +	@cp -f aewl ${DESTDIR}${PREFIX}/bin
    2.59 +	@chmod 755 ${DESTDIR}${PREFIX}/bin/aewl
    2.60  	@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
    2.61  	@mkdir -p ${DESTDIR}${MANPREFIX}/man1
    2.62 -	@sed 's/VERSION/${VERSION}/g' < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
    2.63 -	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
    2.64 +	@sed 's/VERSION/${VERSION}/g' < aewl.1 > ${DESTDIR}${MANPREFIX}/man1/aewl.1
    2.65 +	@chmod 644 ${DESTDIR}${MANPREFIX}/man1/aewl.1
    2.66  
    2.67  uninstall:
    2.68  	@echo removing executable file from ${DESTDIR}${PREFIX}/bin
    2.69 -	@rm -f ${DESTDIR}${PREFIX}/bin/dwm
    2.70 +	@rm -f ${DESTDIR}${PREFIX}/bin/aewl
    2.71  	@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
    2.72 -	@rm -f ${DESTDIR}${MANPREFIX}/man1/dwm.1
    2.73 +	@rm -f ${DESTDIR}${MANPREFIX}/man1/aewl.1
    2.74  
    2.75  .PHONY: all options clean dist install uninstall
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/aewl.1	Fri May 30 22:18:18 2008 +0200
     3.3 @@ -0,0 +1,127 @@
     3.4 +.TH AEWL 1 aewl-VERSION
     3.5 +
     3.6 +
     3.7 +.SH NAME
     3.8 +aewl \- a fork of dwm, the dynamic window manager
     3.9 +
    3.10 +
    3.11 +.SH SYNOPSIS
    3.12 +.B aewl
    3.13 +.RB [ \-v ]
    3.14 +
    3.15 +
    3.16 +.SH DESCRIPTION
    3.17 +This man page is the one from dwm 4.4.1 on which aewl is based.
    3.18 +It is partly updated, but not totally.
    3.19 +.P
    3.20 +dwm is a dynamic window manager for X. It manages windows in tiling and
    3.21 +floating modes. Either mode can be applied dynamically, optimizing the
    3.22 +environment for the application in use and the task performed.
    3.23 +.P
    3.24 +In tiling mode windows are managed in a master and stacking area. The master
    3.25 +area contains the windows which currently need most attention, whereas the
    3.26 +stacking area contains all other windows. In floating mode windows can be
    3.27 +resized and moved freely. Dialog windows are always managed floating,
    3.28 +regardless of the mode applied.
    3.29 +.P
    3.30 +Windows are grouped by tags. Each window can be tagged with one or multiple
    3.31 +tags. Selecting certain tags displays all windows with these tags.
    3.32 +.P
    3.33 +dwm contains a small status bar which displays all available tags, the mode,
    3.34 +the title of the focused window, and the text read from standard input. The
    3.35 +selected tags are indicated with a different color. The tags of the focused
    3.36 +window are indicated with a filled square in the top left corner.  The tags
    3.37 +which are applied to one or more windows are indicated with an empty square in
    3.38 +the top left corner.
    3.39 +.P
    3.40 +dwm draws a small border around windows to indicate the focus state.
    3.41 +
    3.42 +
    3.43 +.SH OPTIONS
    3.44 +.TP
    3.45 +.B \-v
    3.46 +prints version information to standard output, then exits.
    3.47 +
    3.48 +
    3.49 +.SH USAGE
    3.50 +
    3.51 +.SS Status bar
    3.52 +.TP
    3.53 +.B Standard input
    3.54 +is read and displayed in the status text area.
    3.55 +.TP
    3.56 +.B Button1
    3.57 +click on the bar to display the other tag.
    3.58 +
    3.59 +.SS Keyboard commands
    3.60 +.TP
    3.61 +.B Mod1-Shift-Return
    3.62 +Start
    3.63 +.BR xterm (1).
    3.64 +.TP
    3.65 +.B Mod1-Tab
    3.66 +Focus next window.
    3.67 +.TP
    3.68 +.B Mod1-i
    3.69 +Increase the number of windows in the master area (tiling mode only).
    3.70 +.TP
    3.71 +.B Mod1-d
    3.72 +Decrease the number of windows in the master area (tiling mode only).
    3.73 +.TP
    3.74 +.B Mod1-F1
    3.75 +View other tag.
    3.76 +.TP
    3.77 +.B Mod1-F3
    3.78 +Move current window to other tag.
    3.79 +.TP
    3.80 +.B Mod1-^
    3.81 +Start
    3.82 +.BR dmenu (1)
    3.83 +.TP
    3.84 +.B Mod1-1
    3.85 +Zooms/cycles current window to/from master area (tiling mode), toggles maximization current window (floating mode).
    3.86 +.TP
    3.87 +.B Mod1-2
    3.88 +Close focused window.
    3.89 +.TP
    3.90 +.B Mod1-space
    3.91 +Toggle between tiling and max mode (affects all windows).
    3.92 +.TP
    3.93 +.B Mod1-Shift-space
    3.94 +Toggle focused window between floating and non-floating state.
    3.95 +.TP
    3.96 +.B Mod1-Shift-q
    3.97 +Quit dwm.
    3.98 +
    3.99 +.SS Mouse commands
   3.100 +.TP
   3.101 +.B Mod1-Button1
   3.102 +Move current window while dragging (floating mode only).
   3.103 +.TP
   3.104 +.B Mod1-Button3
   3.105 +Resize current window while dragging (floating mode only).
   3.106 +
   3.107 +
   3.108 +.SH CUSTOMIZATION
   3.109 +dwm is customized by creating a custom config.h and (re)compiling the source
   3.110 +code. This keeps it fast, secure and simple.
   3.111 +
   3.112 +
   3.113 +.SH SEE ALSO
   3.114 +.BR dmenu (1)
   3.115 +
   3.116 +
   3.117 +.SH BUGS
   3.118 +The status bar may display
   3.119 +.BR "EOF"
   3.120 +when dwm has been started by an X session manager like
   3.121 +.BR xdm (1),
   3.122 +because those close standard output before executing dwm.
   3.123 +.P
   3.124 +Java applications which use the XToolkit/XAWT backend may draw grey windows
   3.125 +only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
   3.126 +JDK 1.6 versions, because it assumes a reparenting window manager. As a workaround
   3.127 +you can use JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or you
   3.128 +can set the following environment variable (to use the older Motif
   3.129 +backend instead):
   3.130 +.BR AWT_TOOLKIT=MToolkit .
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/aewl.c	Fri May 30 22:18:18 2008 +0200
     4.3 @@ -0,0 +1,1783 @@
     4.4 +/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
     4.5 + * (C)opyright MMVIII markus schnalke <meillo at marmaro dot de>
     4.6 + * See LICENSE file for license details.
     4.7 + *
     4.8 + * dynamic window manager is designed like any other X client as well. It is
     4.9 + * driven through handling X events. In contrast to other X clients, a window
    4.10 + * manager selects for SubstructureRedirectMask on the root window, to receive
    4.11 + * events about window (dis-)appearance.  Only one X connection at a time is
    4.12 + * allowed to select for this event mask.
    4.13 + *
    4.14 + * Calls to fetch an X event from the event queue are blocking.  Due reading
    4.15 + * status text from standard input, a select()-driven main loop has been
    4.16 + * implemented which selects for reads on the X connection and STDIN_FILENO to
    4.17 + * handle all data smoothly. The event handlers of dwm are organized in an
    4.18 + * array which is accessed whenever a new event has been fetched. This allows
    4.19 + * event dispatching in O(1) time.
    4.20 + *
    4.21 + * Each child of the root window is called a client, except windows which have
    4.22 + * set the override_redirect flag.  Clients are organized in a global
    4.23 + * doubly-linked client list, the focus history is remembered through a global
    4.24 + * stack list. Each client contains an array of Bools of the same size as the
    4.25 + * global tags array to indicate the tags of a client.  For each client dwm
    4.26 + * creates a small title window, which is resized whenever the (_NET_)WM_NAME
    4.27 + * properties are updated or the client is moved/resized.
    4.28 + *
    4.29 + * Keys and tagging rules are organized as arrays and defined in the config.h
    4.30 + * file. These arrays are kept static in event.o and tag.o respectively,
    4.31 + * because no other part of dwm needs access to them.  The current mode is
    4.32 + * represented by the arrange() function pointer, which wether points to
    4.33 + * dofloat() or dotile().
    4.34 + *
    4.35 + * To understand everything else, start reading main.c:main().
    4.36 + */
    4.37 +
    4.38 +#include "config.h"
    4.39 +#include <errno.h>
    4.40 +#include <locale.h>
    4.41 +#include <regex.h>
    4.42 +#include <stdio.h>
    4.43 +#include <stdarg.h>
    4.44 +#include <stdlib.h>
    4.45 +#include <string.h>
    4.46 +#include <unistd.h>
    4.47 +#include <sys/select.h>
    4.48 +#include <sys/types.h>
    4.49 +#include <sys/wait.h>
    4.50 +#include <X11/cursorfont.h>
    4.51 +#include <X11/keysym.h>
    4.52 +#include <X11/Xatom.h>
    4.53 +#include <X11/Xlib.h>
    4.54 +#include <X11/Xproto.h>
    4.55 +#include <X11/Xutil.h>
    4.56 +
    4.57 +/* mask shorthands, used in event.c and client.c */
    4.58 +#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
    4.59 +
    4.60 +enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    4.61 +enum { WMProtocols, WMDelete, WMState, WMLast };	/* default atoms */
    4.62 +enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    4.63 +enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    4.64 +
    4.65 +typedef struct {
    4.66 +	int ascent;
    4.67 +	int descent;
    4.68 +	int height;
    4.69 +	XFontSet set;
    4.70 +	XFontStruct *xfont;
    4.71 +} Fnt;
    4.72 +
    4.73 +typedef struct {
    4.74 +	int x, y, w, h;
    4.75 +	unsigned long norm[ColLast];
    4.76 +	unsigned long sel[ColLast];
    4.77 +	Drawable drawable;
    4.78 +	Fnt font;
    4.79 +	GC gc;
    4.80 +} DC; /* draw context */
    4.81 +
    4.82 +typedef struct Client Client;
    4.83 +struct Client {
    4.84 +	char name[256];
    4.85 +	int x, y, w, h;
    4.86 +	int rx, ry, rw, rh; /* revert geometry */
    4.87 +	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    4.88 +	int minax, minay, maxax, maxay;
    4.89 +	long flags;
    4.90 +	unsigned int border;
    4.91 +	Bool isfixed, isfloat, ismax;
    4.92 +	Bool tag;
    4.93 +	Client *next;
    4.94 +	Client *prev;
    4.95 +	Client *snext;
    4.96 +	Window win;
    4.97 +};
    4.98 +
    4.99 +typedef struct {
   4.100 +	const char *clpattern;
   4.101 +	int tag;
   4.102 +	Bool isfloat;
   4.103 +} Rule;
   4.104 +
   4.105 +typedef struct {
   4.106 +	regex_t *clregex;
   4.107 +} RReg;
   4.108 +
   4.109 +
   4.110 +typedef struct {
   4.111 +	unsigned long mod;
   4.112 +	KeySym keysym;
   4.113 +	void (*func)(const char* cmd);
   4.114 +	const char* cmd;
   4.115 +} Key;
   4.116 +
   4.117 +
   4.118 +#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
   4.119 +#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
   4.120 +
   4.121 +
   4.122 +
   4.123 +const char *tags[];			/* all tags */
   4.124 +char stext[256];				/* status text */
   4.125 +int bh, bmw;				/* bar height, bar mode label width */
   4.126 +int screen, sx, sy, sw, sh;		/* screen geometry */
   4.127 +int wax, way, wah, waw;			/* windowarea geometry */
   4.128 +unsigned int nmaster;		/* number of master clients */
   4.129 +unsigned int ntags, numlockmask;		/* number of tags, dynamic lock mask */
   4.130 +void (*handler[LASTEvent])(XEvent *);	/* event handler */
   4.131 +void (*arrange)(void);			/* arrange function, indicates mode  */
   4.132 +Atom wmatom[WMLast], netatom[NetLast];
   4.133 +Bool running, selscreen, seltag;	/* seltag is array of Bool */
   4.134 +Client *clients, *sel, *stack;		/* global client list and stack */
   4.135 +Cursor cursor[CurLast];
   4.136 +DC dc;					/* global draw context */
   4.137 +Display *dpy;
   4.138 +Window root, barwin;
   4.139 +
   4.140 +Bool running = True;
   4.141 +Bool selscreen = True;
   4.142 +Client *clients = NULL;
   4.143 +Client *sel = NULL;
   4.144 +Client *stack = NULL;
   4.145 +DC dc = {0};
   4.146 +
   4.147 +static int (*xerrorxlib)(Display *, XErrorEvent *);
   4.148 +static Bool otherwm, readin;
   4.149 +static RReg *rreg = NULL;
   4.150 +static unsigned int len = 0;
   4.151 +
   4.152 +
   4.153 +TAGS
   4.154 +RULES
   4.155 +
   4.156 +
   4.157 +/* client.c */
   4.158 +void configure(Client *c);		/* send synthetic configure event */
   4.159 +void focus(Client *c);			/* focus c, c may be NULL */
   4.160 +Client *getclient(Window w);		/* return client of w */
   4.161 +Bool isprotodel(Client *c);		/* returns True if c->win supports wmatom[WMDelete] */
   4.162 +void manage(Window w, XWindowAttributes *wa);	/* manage new client */
   4.163 +void resize(Client *c, Bool sizehints);	/* resize c*/
   4.164 +void updatesizehints(Client *c);		/* update the size hint variables of c */
   4.165 +void updatetitle(Client *c);		/* update the name of c */
   4.166 +void unmanage(Client *c);		/* destroy c */
   4.167 +
   4.168 +/* draw.c */
   4.169 +void drawstatus(void);			/* draw the bar */
   4.170 +unsigned long getcolor(const char *colstr);	/* return color of colstr */
   4.171 +void setfont(const char *fontstr);	/* set the font for DC */
   4.172 +unsigned int textw(const char *text);	/* return the width of text in px*/
   4.173 +
   4.174 +/* event.c */
   4.175 +void grabkeys(void);			/* grab all keys defined in config.h */
   4.176 +void procevent(void);			/* process pending X events */
   4.177 +
   4.178 +/* main.c */
   4.179 +void sendevent(Window w, Atom a, long value);	/* send synthetic event to w */
   4.180 +int xerror(Display *dsply, XErrorEvent *ee);	/* dwm's X error handler */
   4.181 +
   4.182 +/* tag.c */
   4.183 +void initrregs(void);			/* initialize regexps of rules defined in config.h */
   4.184 +Client *getnext(Client *c);		/* returns next visible client */
   4.185 +void settags(Client *c, Client *trans);	/* sets tags of c */
   4.186 +
   4.187 +/* util.c */
   4.188 +void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */
   4.189 +void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */
   4.190 +
   4.191 +/* view.c */
   4.192 +void detach(Client *c);			/* detaches c from global client list */
   4.193 +void dofloat(void);			/* arranges all windows floating */
   4.194 +void dotile(void);			/* arranges all windows tiled */
   4.195 +void domax(void);            /* arranges all windows fullscreen */
   4.196 +Bool isvisible(Client *c);		/* returns True if client is visible */
   4.197 +void restack(void);			/* restores z layers of all clients */
   4.198 +
   4.199 +
   4.200 +void toggleview();			/* toggle the viewed tag */
   4.201 +void focusnext();		/* focuses next visible client  */
   4.202 +void zoom();			/* zooms the focused client to master area */
   4.203 +void killclient();		/* kill c nicely */
   4.204 +void quit();			/* quit dwm nicely */
   4.205 +void togglemode();		/* toggles global arrange function (dotile/dofloat) */
   4.206 +void togglefloat();		/* toggles focusesd client between floating/non-floating state */
   4.207 +void incnmaster();		/* increments nmaster */
   4.208 +void decnmaster();		/* decrements nmaster */
   4.209 +void toggletag();		/* toggles c tag */
   4.210 +void spawn(const char* cmd);			/* forks a new subprocess with cmd */
   4.211 +
   4.212 +
   4.213 +
   4.214 +
   4.215 +
   4.216 +
   4.217 +
   4.218 +
   4.219 +
   4.220 +
   4.221 +/* from view.c */
   4.222 +/* static */
   4.223 +
   4.224 +static Client *
   4.225 +nexttiled(Client *c) {
   4.226 +	for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
   4.227 +	return c;
   4.228 +}
   4.229 +
   4.230 +static void
   4.231 +togglemax(Client *c) {
   4.232 +	XEvent ev;
   4.233 +		
   4.234 +	if(c->isfixed)
   4.235 +		return;
   4.236 +
   4.237 +	if((c->ismax = !c->ismax)) {
   4.238 +		c->rx = c->x; c->x = wax;
   4.239 +		c->ry = c->y; c->y = way;
   4.240 +		c->rw = c->w; c->w = waw - 2 * BORDERPX;
   4.241 +		c->rh = c->h; c->h = wah - 2 * BORDERPX;
   4.242 +	}
   4.243 +	else {
   4.244 +		c->x = c->rx;
   4.245 +		c->y = c->ry;
   4.246 +		c->w = c->rw;
   4.247 +		c->h = c->rh;
   4.248 +	}
   4.249 +	resize(c, True);
   4.250 +	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
   4.251 +}
   4.252 +
   4.253 +
   4.254 +
   4.255 +void (*arrange)(void) = DEFMODE;
   4.256 +
   4.257 +void
   4.258 +detach(Client *c) {
   4.259 +	if(c->prev)
   4.260 +		c->prev->next = c->next;
   4.261 +	if(c->next)
   4.262 +		c->next->prev = c->prev;
   4.263 +	if(c == clients)
   4.264 +		clients = c->next;
   4.265 +	c->next = c->prev = NULL;
   4.266 +}
   4.267 +
   4.268 +void
   4.269 +dofloat(void) {
   4.270 +	Client *c;
   4.271 +
   4.272 +	for(c = clients; c; c = c->next) {
   4.273 +		if(isvisible(c)) {
   4.274 +			resize(c, True);
   4.275 +		}
   4.276 +		else
   4.277 +			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   4.278 +	}
   4.279 +	if(!sel || !isvisible(sel)) {
   4.280 +		for(c = stack; c && !isvisible(c); c = c->snext);
   4.281 +		focus(c);
   4.282 +	}
   4.283 +	restack();
   4.284 +}
   4.285 +
   4.286 +void
   4.287 +dotile(void) {
   4.288 +	unsigned int i, n, mw, mh, tw, th;
   4.289 +	Client *c;
   4.290 +
   4.291 +	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
   4.292 +		n++;
   4.293 +	/* window geoms */
   4.294 +	mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
   4.295 +	mw = (n > nmaster) ? waw / 2 : waw;
   4.296 +	th = (n > nmaster) ? wah / (n - nmaster) : 0;
   4.297 +	tw = waw - mw;
   4.298 +
   4.299 +	for(i = 0, c = clients; c; c = c->next)
   4.300 +		if(isvisible(c)) {
   4.301 +			if(c->isfloat) {
   4.302 +				resize(c, True);
   4.303 +				continue;
   4.304 +			}
   4.305 +			c->ismax = False;
   4.306 +			c->x = wax;
   4.307 +			c->y = way;
   4.308 +			if(i < nmaster) {
   4.309 +				c->y += i * mh;
   4.310 +				c->w = mw - 2 * BORDERPX;
   4.311 +				c->h = mh - 2 * BORDERPX;
   4.312 +			}
   4.313 +			else {  /* tile window */
   4.314 +				c->x += mw;
   4.315 +				c->w = tw - 2 * BORDERPX;
   4.316 +				if(th > 2 * BORDERPX) {
   4.317 +					c->y += (i - nmaster) * th;
   4.318 +					c->h = th - 2 * BORDERPX;
   4.319 +				}
   4.320 +				else /* fallback if th <= 2 * BORDERPX */
   4.321 +					c->h = wah - 2 * BORDERPX;
   4.322 +			}
   4.323 +			resize(c, False);
   4.324 +			i++;
   4.325 +		}
   4.326 +		else
   4.327 +			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   4.328 +	if(!sel || !isvisible(sel)) {
   4.329 +		for(c = stack; c && !isvisible(c); c = c->snext);
   4.330 +		focus(c);
   4.331 +	}
   4.332 +	restack();
   4.333 +}
   4.334 +
   4.335 +/* begin code by mitch */
   4.336 +void
   4.337 +arrangemax(Client *c) {
   4.338 +  if(c == sel) {
   4.339 +    c->ismax = True;
   4.340 +    c->x = sx;
   4.341 +    c->y = bh;
   4.342 +    c->w = sw - 2 * BORDERPX;
   4.343 +    c->h = sh - bh - 2 * BORDERPX;
   4.344 +    XRaiseWindow(dpy, c->win);
   4.345 +  } else {
   4.346 +    c->ismax = False;
   4.347 +    XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   4.348 +    XLowerWindow(dpy, c->win);
   4.349 +  }
   4.350 +}
   4.351 +
   4.352 +void
   4.353 +domax(void) {
   4.354 +  Client *c;
   4.355 +
   4.356 +  for(c = clients; c; c = c->next) {
   4.357 +    if(isvisible(c)) {
   4.358 +      if(c->isfloat) {
   4.359 +        resize(c, True);
   4.360 +        continue;
   4.361 +      }
   4.362 +      arrangemax(c);
   4.363 +      resize(c, False);
   4.364 +    } else {
   4.365 +      XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   4.366 +    }
   4.367 +
   4.368 +  }
   4.369 +  if(!sel || !isvisible(sel)) {
   4.370 +    for(c = stack; c && !isvisible(c); c = c->snext);
   4.371 +    focus(c);
   4.372 +  }
   4.373 +  restack();
   4.374 +}
   4.375 +/* end code by mitch */
   4.376 +
   4.377 +void
   4.378 +focusnext() {
   4.379 +	Client *c;
   4.380 +
   4.381 +	if(!sel)
   4.382 +		return;
   4.383 +	if(!(c = getnext(sel->next)))
   4.384 +		c = getnext(clients);
   4.385 +	if(c) {
   4.386 +		focus(c);
   4.387 +		restack();
   4.388 +	}
   4.389 +}
   4.390 +
   4.391 +void
   4.392 +incnmaster() {
   4.393 +	if((arrange == dofloat) || (wah / (nmaster + 1) <= 2 * BORDERPX))
   4.394 +		return;
   4.395 +	nmaster++;
   4.396 +	if(sel)
   4.397 +		arrange();
   4.398 +	else
   4.399 +		drawstatus();
   4.400 +}
   4.401 +
   4.402 +void
   4.403 +decnmaster() {
   4.404 +	if((arrange == dofloat) || (nmaster <= 1))
   4.405 +		return;
   4.406 +	nmaster--;
   4.407 +	if(sel)
   4.408 +		arrange();
   4.409 +	else
   4.410 +		drawstatus();
   4.411 +}
   4.412 +
   4.413 +Bool
   4.414 +isvisible(Client *c) {
   4.415 +	if((c->tag && seltag) || (!c->tag && !seltag)) {
   4.416 +		return True;
   4.417 +	}
   4.418 +	return False;
   4.419 +}
   4.420 +
   4.421 +void
   4.422 +restack(void) {
   4.423 +	Client *c;
   4.424 +	XEvent ev;
   4.425 +
   4.426 +	drawstatus();
   4.427 +	if(!sel)
   4.428 +		return;
   4.429 +	if(sel->isfloat || arrange == dofloat)
   4.430 +		XRaiseWindow(dpy, sel->win);
   4.431 +
   4.432 +  /* begin code by mitch */
   4.433 +  if(arrange == domax) {
   4.434 +    for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
   4.435 +      arrangemax(c);
   4.436 +      resize(c, False);
   4.437 +    }
   4.438 +
   4.439 +  } else if (arrange == dotile) {
   4.440 +  /* end code by mitch */
   4.441 +
   4.442 +		if(!sel->isfloat)
   4.443 +			XLowerWindow(dpy, sel->win);
   4.444 +		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
   4.445 +			if(c == sel)
   4.446 +				continue;
   4.447 +			XLowerWindow(dpy, c->win);
   4.448 +		}
   4.449 +	}
   4.450 +	XSync(dpy, False);
   4.451 +	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
   4.452 +}
   4.453 +
   4.454 +void
   4.455 +togglefloat() {
   4.456 +	if (!sel || arrange == dofloat)
   4.457 +		return;
   4.458 +	sel->isfloat = !sel->isfloat;
   4.459 +	arrange();
   4.460 +}
   4.461 +
   4.462 +void
   4.463 +togglemode() {
   4.464 +  /* only toggle between tile and max - float is just available through togglefloat */
   4.465 +  arrange = (arrange == dotile) ? domax : dotile;
   4.466 +	if(sel)
   4.467 +		arrange();
   4.468 +	else
   4.469 +		drawstatus();
   4.470 +}
   4.471 +
   4.472 +void
   4.473 +toggleview() {
   4.474 +	seltag = !seltag;
   4.475 +	arrange();
   4.476 +}
   4.477 +
   4.478 +void
   4.479 +zoom() {
   4.480 +	unsigned int n;
   4.481 +	Client *c;
   4.482 +
   4.483 +	if(!sel)
   4.484 +		return;
   4.485 +	if(sel->isfloat || (arrange == dofloat)) {
   4.486 +		togglemax(sel);
   4.487 +		return;
   4.488 +	}
   4.489 +	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
   4.490 +		n++;
   4.491 +
   4.492 +	if((c = sel) == nexttiled(clients))
   4.493 +		if(!(c = nexttiled(c->next)))
   4.494 +			return;
   4.495 +	detach(c);
   4.496 +	if(clients)
   4.497 +		clients->prev = c;
   4.498 +	c->next = clients;
   4.499 +	clients = c;
   4.500 +	focus(c);
   4.501 +	arrange();
   4.502 +}
   4.503 +
   4.504 +
   4.505 +
   4.506 +
   4.507 +
   4.508 +
   4.509 +
   4.510 +
   4.511 +
   4.512 +
   4.513 +
   4.514 +
   4.515 +
   4.516 +
   4.517 +
   4.518 +
   4.519 +/* from util.c */
   4.520 +
   4.521 +
   4.522 +void *
   4.523 +emallocz(unsigned int size) {
   4.524 +	void *res = calloc(1, size);
   4.525 +
   4.526 +	if(!res)
   4.527 +		eprint("fatal: could not malloc() %u bytes\n", size);
   4.528 +	return res;
   4.529 +}
   4.530 +
   4.531 +void
   4.532 +eprint(const char *errstr, ...) {
   4.533 +	va_list ap;
   4.534 +
   4.535 +	va_start(ap, errstr);
   4.536 +	vfprintf(stderr, errstr, ap);
   4.537 +	va_end(ap);
   4.538 +	exit(EXIT_FAILURE);
   4.539 +}
   4.540 +
   4.541 +void
   4.542 +spawn(const char* cmd) {
   4.543 +	static char *shell = NULL;
   4.544 +
   4.545 +	if(!shell && !(shell = getenv("SHELL")))
   4.546 +		shell = "/bin/sh";
   4.547 +	if(!cmd)
   4.548 +		return;
   4.549 +	/* The double-fork construct avoids zombie processes and keeps the code
   4.550 +	 * clean from stupid signal handlers. */
   4.551 +	if(fork() == 0) {
   4.552 +		if(fork() == 0) {
   4.553 +			if(dpy)
   4.554 +				close(ConnectionNumber(dpy));
   4.555 +			setsid();
   4.556 +			execl(shell, shell, "-c", cmd, (char *)NULL);
   4.557 +			fprintf(stderr, "dwm: execl '%s -c %s'", shell, cmd);
   4.558 +			perror(" failed");
   4.559 +		}
   4.560 +		exit(0);
   4.561 +	}
   4.562 +	wait(0);
   4.563 +}
   4.564 +
   4.565 +
   4.566 +
   4.567 +
   4.568 +
   4.569 +
   4.570 +
   4.571 +
   4.572 +
   4.573 +
   4.574 +
   4.575 +
   4.576 +
   4.577 +/* from tag.c */
   4.578 +
   4.579 +/* static */
   4.580 +
   4.581 +Client *
   4.582 +getnext(Client *c) {
   4.583 +	for(; c && !isvisible(c); c = c->next);
   4.584 +	return c;
   4.585 +}
   4.586 +
   4.587 +void
   4.588 +initrregs(void) {
   4.589 +	unsigned int i;
   4.590 +	regex_t *reg;
   4.591 +
   4.592 +	if(rreg)
   4.593 +		return;
   4.594 +	len = sizeof rule / sizeof rule[0];
   4.595 +	rreg = emallocz(len * sizeof(RReg));
   4.596 +	for(i = 0; i < len; i++) {
   4.597 +		if(rule[i].clpattern) {
   4.598 +			reg = emallocz(sizeof(regex_t));
   4.599 +			if(regcomp(reg, rule[i].clpattern, REG_EXTENDED))
   4.600 +				free(reg);
   4.601 +			else
   4.602 +				rreg[i].clregex = reg;
   4.603 +		}
   4.604 +	}
   4.605 +}
   4.606 +
   4.607 +void
   4.608 +settags(Client *c, Client *trans) {
   4.609 +	char prop[512];
   4.610 +	unsigned int i;
   4.611 +	regmatch_t tmp;
   4.612 +	Bool matched = trans != NULL;
   4.613 +	XClassHint ch = { 0 };
   4.614 +
   4.615 +	if(matched) {
   4.616 +		c->tag = trans->tag;
   4.617 +	} else {
   4.618 +		XGetClassHint(dpy, c->win, &ch);
   4.619 +		snprintf(prop, sizeof prop, "%s:%s:%s",
   4.620 +				ch.res_class ? ch.res_class : "",
   4.621 +				ch.res_name ? ch.res_name : "", c->name);
   4.622 +		for(i = 0; i < len; i++)
   4.623 +			if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) {
   4.624 +				c->isfloat = rule[i].isfloat;
   4.625 +				if (rule[i].tag < 0) {
   4.626 +					c->tag = seltag;
   4.627 +				} else if (rule[i].tag == 0) {
   4.628 +					c->tag = True;
   4.629 +				} else {
   4.630 +					c->tag = False;
   4.631 +				}
   4.632 +				matched = True;
   4.633 +        break;  /* perform only the first rule matching */
   4.634 +			}
   4.635 +		if(ch.res_class)
   4.636 +			XFree(ch.res_class);
   4.637 +		if(ch.res_name)
   4.638 +			XFree(ch.res_name);
   4.639 +	}
   4.640 +	if(!matched) {
   4.641 +		c->tag = seltag;
   4.642 +	}
   4.643 +}
   4.644 +
   4.645 +void
   4.646 +toggletag() {
   4.647 +	if(!sel)
   4.648 +		return;
   4.649 +	sel->tag = !sel->tag;
   4.650 +	toggleview();
   4.651 +}
   4.652 +
   4.653 +
   4.654 +
   4.655 +
   4.656 +
   4.657 +
   4.658 +
   4.659 +
   4.660 +
   4.661 +
   4.662 +
   4.663 +
   4.664 +
   4.665 +
   4.666 +
   4.667 +
   4.668 +
   4.669 +/* from event.c */
   4.670 +/* static */
   4.671 +
   4.672 +KEYS
   4.673 +
   4.674 +
   4.675 +
   4.676 +static void
   4.677 +movemouse(Client *c) {
   4.678 +	int x1, y1, ocx, ocy, di;
   4.679 +	unsigned int dui;
   4.680 +	Window dummy;
   4.681 +	XEvent ev;
   4.682 +
   4.683 +	ocx = c->x;
   4.684 +	ocy = c->y;
   4.685 +	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
   4.686 +			None, cursor[CurMove], CurrentTime) != GrabSuccess)
   4.687 +		return;
   4.688 +	c->ismax = False;
   4.689 +	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
   4.690 +	for(;;) {
   4.691 +		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
   4.692 +		switch (ev.type) {
   4.693 +		case ButtonRelease:
   4.694 +			resize(c, True);
   4.695 +			XUngrabPointer(dpy, CurrentTime);
   4.696 +			return;
   4.697 +		case ConfigureRequest:
   4.698 +		case Expose:
   4.699 +		case MapRequest:
   4.700 +			handler[ev.type](&ev);
   4.701 +			break;
   4.702 +		case MotionNotify:
   4.703 +			XSync(dpy, False);
   4.704 +			c->x = ocx + (ev.xmotion.x - x1);
   4.705 +			c->y = ocy + (ev.xmotion.y - y1);
   4.706 +			if(abs(wax + c->x) < SNAP)
   4.707 +				c->x = wax;
   4.708 +			else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
   4.709 +				c->x = wax + waw - c->w - 2 * c->border;
   4.710 +			if(abs(way - c->y) < SNAP)
   4.711 +				c->y = way;
   4.712 +			else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
   4.713 +				c->y = way + wah - c->h - 2 * c->border;
   4.714 +			resize(c, False);
   4.715 +			break;
   4.716 +		}
   4.717 +	}
   4.718 +}
   4.719 +
   4.720 +static void
   4.721 +resizemouse(Client *c) {
   4.722 +	int ocx, ocy;
   4.723 +	int nw, nh;
   4.724 +	XEvent ev;
   4.725 +
   4.726 +	ocx = c->x;
   4.727 +	ocy = c->y;
   4.728 +	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
   4.729 +			None, cursor[CurResize], CurrentTime) != GrabSuccess)
   4.730 +		return;
   4.731 +	c->ismax = False;
   4.732 +	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
   4.733 +	for(;;) {
   4.734 +		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
   4.735 +		switch(ev.type) {
   4.736 +		case ButtonRelease:
   4.737 +			resize(c, True);
   4.738 +			XUngrabPointer(dpy, CurrentTime);
   4.739 +			return;
   4.740 +		case ConfigureRequest:
   4.741 +		case Expose:
   4.742 +		case MapRequest:
   4.743 +			handler[ev.type](&ev);
   4.744 +			break;
   4.745 +		case MotionNotify:
   4.746 +			XSync(dpy, False);
   4.747 +			nw = ev.xmotion.x - ocx - 2 * c->border + 1;
   4.748 +			c->w = nw > 0 ? nw : 1;
   4.749 +			nh = ev.xmotion.y - ocy - 2 * c->border + 1;
   4.750 +			c->h = nh > 0 ? nh : 1;
   4.751 +			resize(c, True);
   4.752 +			break;
   4.753 +		}
   4.754 +	}
   4.755 +}
   4.756 +
   4.757 +static void
   4.758 +buttonpress(XEvent *e) {
   4.759 +	int x;
   4.760 +	int i;
   4.761 +	Client *c;
   4.762 +	XButtonPressedEvent *ev = &e->xbutton;
   4.763 +
   4.764 +	if(barwin == ev->window) {
   4.765 +		if(ev->button == Button1) {
   4.766 +			toggleview();
   4.767 +		}
   4.768 +		return;
   4.769 +	} else if((c = getclient(ev->window))) {
   4.770 +		focus(c);
   4.771 +		if(CLEANMASK(ev->state) != MODKEY)
   4.772 +			return;
   4.773 +		if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
   4.774 +			restack();
   4.775 +			movemouse(c);
   4.776 +		} else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) && !c->isfixed) {
   4.777 +			restack();
   4.778 +			resizemouse(c);
   4.779 +		}
   4.780 +	}
   4.781 +}
   4.782 +
   4.783 +static void
   4.784 +configurerequest(XEvent *e) {
   4.785 +	unsigned long newmask;
   4.786 +	Client *c;
   4.787 +	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   4.788 +	XWindowChanges wc;
   4.789 +
   4.790 +	if((c = getclient(ev->window))) {
   4.791 +		c->ismax = False;
   4.792 +		if(ev->value_mask & CWX)
   4.793 +			c->x = ev->x;
   4.794 +		if(ev->value_mask & CWY)
   4.795 +			c->y = ev->y;
   4.796 +		if(ev->value_mask & CWWidth)
   4.797 +			c->w = ev->width;
   4.798 +		if(ev->value_mask & CWHeight)
   4.799 +			c->h = ev->height;
   4.800 +		if(ev->value_mask & CWBorderWidth)
   4.801 +			c->border = ev->border_width;
   4.802 +		wc.x = c->x;
   4.803 +		wc.y = c->y;
   4.804 +		wc.width = c->w;
   4.805 +		wc.height = c->h;
   4.806 +		newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
   4.807 +		if(newmask)
   4.808 +			XConfigureWindow(dpy, c->win, newmask, &wc);
   4.809 +		else
   4.810 +			configure(c);
   4.811 +		XSync(dpy, False);
   4.812 +		if(c->isfloat) {
   4.813 +			resize(c, False);
   4.814 +			if(!isvisible(c))
   4.815 +				XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   4.816 +		}
   4.817 +		else
   4.818 +			arrange();
   4.819 +	} else {
   4.820 +		wc.x = ev->x;
   4.821 +		wc.y = ev->y;
   4.822 +		wc.width = ev->width;
   4.823 +		wc.height = ev->height;
   4.824 +		wc.border_width = ev->border_width;
   4.825 +		wc.sibling = ev->above;
   4.826 +		wc.stack_mode = ev->detail;
   4.827 +		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
   4.828 +		XSync(dpy, False);
   4.829 +	}
   4.830 +}
   4.831 +
   4.832 +static void
   4.833 +destroynotify(XEvent *e) {
   4.834 +	Client *c;
   4.835 +	XDestroyWindowEvent *ev = &e->xdestroywindow;
   4.836 +
   4.837 +	if((c = getclient(ev->window)))
   4.838 +		unmanage(c);
   4.839 +}
   4.840 +
   4.841 +static void
   4.842 +enternotify(XEvent *e) {
   4.843 +	Client *c;
   4.844 +	XCrossingEvent *ev = &e->xcrossing;
   4.845 +
   4.846 +	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
   4.847 +		return;
   4.848 +	if((c = getclient(ev->window)) && isvisible(c))
   4.849 +		focus(c);
   4.850 +	else if(ev->window == root) {
   4.851 +		selscreen = True;
   4.852 +		for(c = stack; c && !isvisible(c); c = c->snext);
   4.853 +		focus(c);
   4.854 +	}
   4.855 +}
   4.856 +
   4.857 +static void
   4.858 +expose(XEvent *e) {
   4.859 +	XExposeEvent *ev = &e->xexpose;
   4.860 +
   4.861 +	if(ev->count == 0) {
   4.862 +		if(barwin == ev->window)
   4.863 +			drawstatus();
   4.864 +	}
   4.865 +}
   4.866 +
   4.867 +static void
   4.868 +keypress(XEvent *e) {
   4.869 +	static unsigned int len = sizeof key / sizeof key[0];
   4.870 +	unsigned int i;
   4.871 +	KeySym keysym;
   4.872 +	XKeyEvent *ev = &e->xkey;
   4.873 +
   4.874 +	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
   4.875 +	for(i = 0; i < len; i++) {
   4.876 +		if(keysym == key[i].keysym && CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) {
   4.877 +			if(key[i].func)
   4.878 +				key[i].func(key[i].cmd);
   4.879 +		}
   4.880 +	}
   4.881 +}
   4.882 +
   4.883 +static void
   4.884 +leavenotify(XEvent *e) {
   4.885 +	XCrossingEvent *ev = &e->xcrossing;
   4.886 +
   4.887 +	if((ev->window == root) && !ev->same_screen) {
   4.888 +		selscreen = False;
   4.889 +		focus(NULL);
   4.890 +	}
   4.891 +}
   4.892 +
   4.893 +static void
   4.894 +mappingnotify(XEvent *e) {
   4.895 +	XMappingEvent *ev = &e->xmapping;
   4.896 +
   4.897 +	XRefreshKeyboardMapping(ev);
   4.898 +	if(ev->request == MappingKeyboard)
   4.899 +		grabkeys();
   4.900 +}
   4.901 +
   4.902 +static void
   4.903 +maprequest(XEvent *e) {
   4.904 +	static XWindowAttributes wa;
   4.905 +	XMapRequestEvent *ev = &e->xmaprequest;
   4.906 +
   4.907 +	if(!XGetWindowAttributes(dpy, ev->window, &wa))
   4.908 +		return;
   4.909 +	if(wa.override_redirect) {
   4.910 +		XSelectInput(dpy, ev->window,
   4.911 +				(StructureNotifyMask | PropertyChangeMask));
   4.912 +		return;
   4.913 +	}
   4.914 +	if(!getclient(ev->window))
   4.915 +		manage(ev->window, &wa);
   4.916 +}
   4.917 +
   4.918 +static void
   4.919 +propertynotify(XEvent *e) {
   4.920 +	Client *c;
   4.921 +	Window trans;
   4.922 +	XPropertyEvent *ev = &e->xproperty;
   4.923 +
   4.924 +	if(ev->state == PropertyDelete)
   4.925 +		return; /* ignore */
   4.926 +	if((c = getclient(ev->window))) {
   4.927 +		switch (ev->atom) {
   4.928 +			default: break;
   4.929 +			case XA_WM_TRANSIENT_FOR:
   4.930 +				XGetTransientForHint(dpy, c->win, &trans);
   4.931 +				if(!c->isfloat && (c->isfloat = (trans != 0)))
   4.932 +					arrange();
   4.933 +				break;
   4.934 +			case XA_WM_NORMAL_HINTS:
   4.935 +				updatesizehints(c);
   4.936 +				break;
   4.937 +		}
   4.938 +		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
   4.939 +			updatetitle(c);
   4.940 +			if(c == sel)
   4.941 +				drawstatus();
   4.942 +		}
   4.943 +	}
   4.944 +}
   4.945 +
   4.946 +static void
   4.947 +unmapnotify(XEvent *e) {
   4.948 +	Client *c;
   4.949 +	XUnmapEvent *ev = &e->xunmap;
   4.950 +
   4.951 +	if((c = getclient(ev->window)))
   4.952 +		unmanage(c);
   4.953 +}
   4.954 +
   4.955 +
   4.956 +
   4.957 +void (*handler[LASTEvent]) (XEvent *) = {
   4.958 +	[ButtonPress] = buttonpress,
   4.959 +	[ConfigureRequest] = configurerequest,
   4.960 +	[DestroyNotify] = destroynotify,
   4.961 +	[EnterNotify] = enternotify,
   4.962 +	[LeaveNotify] = leavenotify,
   4.963 +	[Expose] = expose,
   4.964 +	[KeyPress] = keypress,
   4.965 +	[MappingNotify] = mappingnotify,
   4.966 +	[MapRequest] = maprequest,
   4.967 +	[PropertyNotify] = propertynotify,
   4.968 +	[UnmapNotify] = unmapnotify
   4.969 +};
   4.970 +
   4.971 +void
   4.972 +grabkeys(void) {
   4.973 +	static unsigned int len = sizeof key / sizeof key[0];
   4.974 +	unsigned int i;
   4.975 +	KeyCode code;
   4.976 +
   4.977 +	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   4.978 +	for(i = 0; i < len; i++) {
   4.979 +		code = XKeysymToKeycode(dpy, key[i].keysym);
   4.980 +		XGrabKey(dpy, code, key[i].mod, root, True,
   4.981 +				GrabModeAsync, GrabModeAsync);
   4.982 +		XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
   4.983 +				GrabModeAsync, GrabModeAsync);
   4.984 +		XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
   4.985 +				GrabModeAsync, GrabModeAsync);
   4.986 +		XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
   4.987 +				GrabModeAsync, GrabModeAsync);
   4.988 +	}
   4.989 +}
   4.990 +
   4.991 +void
   4.992 +procevent(void) {
   4.993 +	XEvent ev;
   4.994 +
   4.995 +	while(XPending(dpy)) {
   4.996 +		XNextEvent(dpy, &ev);
   4.997 +		if(handler[ev.type])
   4.998 +			(handler[ev.type])(&ev); /* call handler */
   4.999 +	}
  4.1000 +}
  4.1001 +
  4.1002 +
  4.1003 +
  4.1004 +
  4.1005 +
  4.1006 +
  4.1007 +
  4.1008 +
  4.1009 +
  4.1010 +
  4.1011 +
  4.1012 +
  4.1013 +
  4.1014 +
  4.1015 +
  4.1016 +/* from draw.c */
  4.1017 +/* static */
  4.1018 +
  4.1019 +static unsigned int
  4.1020 +textnw(const char *text, unsigned int len) {
  4.1021 +	XRectangle r;
  4.1022 +
  4.1023 +	if(dc.font.set) {
  4.1024 +		XmbTextExtents(dc.font.set, text, len, NULL, &r);
  4.1025 +		return r.width;
  4.1026 +	}
  4.1027 +	return XTextWidth(dc.font.xfont, text, len);
  4.1028 +}
  4.1029 +
  4.1030 +static void
  4.1031 +drawtext(const char *text, unsigned long col[ColLast]) {
  4.1032 +	int x, y, w, h;
  4.1033 +	static char buf[256];
  4.1034 +	unsigned int len, olen;
  4.1035 +	XGCValues gcv;
  4.1036 +	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
  4.1037 +
  4.1038 +	XSetForeground(dpy, dc.gc, col[ColBG]);
  4.1039 +	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
  4.1040 +	if(!text)
  4.1041 +		return;
  4.1042 +	w = 0;
  4.1043 +	olen = len = strlen(text);
  4.1044 +	if(len >= sizeof buf)
  4.1045 +		len = sizeof buf - 1;
  4.1046 +	memcpy(buf, text, len);
  4.1047 +	buf[len] = 0;
  4.1048 +	h = dc.font.ascent + dc.font.descent;
  4.1049 +	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
  4.1050 +	x = dc.x + (h / 2);
  4.1051 +	/* shorten text if necessary */
  4.1052 +	while(len && (w = textnw(buf, len)) > dc.w - h)
  4.1053 +		buf[--len] = 0;
  4.1054 +	if(len < olen) {
  4.1055 +		if(len > 1)
  4.1056 +			buf[len - 1] = '.';
  4.1057 +		if(len > 2)
  4.1058 +			buf[len - 2] = '.';
  4.1059 +		if(len > 3)
  4.1060 +			buf[len - 3] = '.';
  4.1061 +	}
  4.1062 +	if(w > dc.w)
  4.1063 +		return; /* too long */
  4.1064 +	gcv.foreground = col[ColFG];
  4.1065 +	if(dc.font.set) {
  4.1066 +		XChangeGC(dpy, dc.gc, GCForeground, &gcv);
  4.1067 +		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
  4.1068 +	} else {
  4.1069 +		gcv.font = dc.font.xfont->fid;
  4.1070 +		XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
  4.1071 +		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
  4.1072 +	}
  4.1073 +}
  4.1074 +
  4.1075 +
  4.1076 +
  4.1077 +void
  4.1078 +drawstatus(void) {
  4.1079 +	int x;
  4.1080 +	unsigned int i;
  4.1081 +
  4.1082 +	dc.x = dc.y = 0;
  4.1083 +	for(i = 0; i < ntags; i++) {
  4.1084 +		dc.w = textw(tags[i]);
  4.1085 +		drawtext(tags[i], ( ((i == 0 && seltag) || (i == 1 && !seltag)) ? dc.sel : dc.norm));
  4.1086 +		dc.x += dc.w + 1;
  4.1087 +	}
  4.1088 +	dc.w = bmw;
  4.1089 +	drawtext("", dc.norm);
  4.1090 +	x = dc.x + dc.w;
  4.1091 +	dc.w = textw(stext);
  4.1092 +	dc.x = sw - dc.w;
  4.1093 +	if(dc.x < x) {
  4.1094 +		dc.x = x;
  4.1095 +		dc.w = sw - x;
  4.1096 +	}
  4.1097 +	drawtext(stext, dc.norm);
  4.1098 +	if((dc.w = dc.x - x) > bh) {
  4.1099 +		dc.x = x;
  4.1100 +		drawtext(sel ? sel->name : NULL, dc.norm);
  4.1101 +	}
  4.1102 +	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
  4.1103 +	XSync(dpy, False);
  4.1104 +}
  4.1105 +
  4.1106 +unsigned long
  4.1107 +getcolor(const char *colstr) {
  4.1108 +	Colormap cmap = DefaultColormap(dpy, screen);
  4.1109 +	XColor color;
  4.1110 +
  4.1111 +	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
  4.1112 +		eprint("error, cannot allocate color '%s'\n", colstr);
  4.1113 +	return color.pixel;
  4.1114 +}
  4.1115 +
  4.1116 +void
  4.1117 +setfont(const char *fontstr) {
  4.1118 +	char *def, **missing;
  4.1119 +	int i, n;
  4.1120 +
  4.1121 +	missing = NULL;
  4.1122 +	if(dc.font.set)
  4.1123 +		XFreeFontSet(dpy, dc.font.set);
  4.1124 +	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
  4.1125 +	if(missing) {
  4.1126 +		while(n--)
  4.1127 +			fprintf(stderr, "missing fontset: %s\n", missing[n]);
  4.1128 +		XFreeStringList(missing);
  4.1129 +	}
  4.1130 +	if(dc.font.set) {
  4.1131 +		XFontSetExtents *font_extents;
  4.1132 +		XFontStruct **xfonts;
  4.1133 +		char **font_names;
  4.1134 +		dc.font.ascent = dc.font.descent = 0;
  4.1135 +		font_extents = XExtentsOfFontSet(dc.font.set);
  4.1136 +		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
  4.1137 +		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
  4.1138 +			if(dc.font.ascent < (*xfonts)->ascent)
  4.1139 +				dc.font.ascent = (*xfonts)->ascent;
  4.1140 +			if(dc.font.descent < (*xfonts)->descent)
  4.1141 +				dc.font.descent = (*xfonts)->descent;
  4.1142 +			xfonts++;
  4.1143 +		}
  4.1144 +	} else {
  4.1145 +		if(dc.font.xfont)
  4.1146 +			XFreeFont(dpy, dc.font.xfont);
  4.1147 +		dc.font.xfont = NULL;
  4.1148 +		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
  4.1149 +			eprint("error, cannot load font: '%s'\n", fontstr);
  4.1150 +		dc.font.ascent = dc.font.xfont->ascent;
  4.1151 +		dc.font.descent = dc.font.xfont->descent;
  4.1152 +	}
  4.1153 +	dc.font.height = dc.font.ascent + dc.font.descent;
  4.1154 +}
  4.1155 +
  4.1156 +unsigned int
  4.1157 +textw(const char *text) {
  4.1158 +	return textnw(text, strlen(text)) + dc.font.height;
  4.1159 +}
  4.1160 +
  4.1161 +
  4.1162 +
  4.1163 +
  4.1164 +
  4.1165 +
  4.1166 +
  4.1167 +
  4.1168 +
  4.1169 +
  4.1170 +
  4.1171 +/* from client.c */
  4.1172 +/* static */
  4.1173 +
  4.1174 +static void
  4.1175 +detachstack(Client *c) {
  4.1176 +	Client **tc;
  4.1177 +	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
  4.1178 +	*tc = c->snext;
  4.1179 +}
  4.1180 +
  4.1181 +static void
  4.1182 +grabbuttons(Client *c, Bool focused) {
  4.1183 +	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  4.1184 +
  4.1185 +	if(focused) {
  4.1186 +		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
  4.1187 +				GrabModeAsync, GrabModeSync, None, None);
  4.1188 +		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
  4.1189 +				GrabModeAsync, GrabModeSync, None, None);
  4.1190 +		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  4.1191 +				GrabModeAsync, GrabModeSync, None, None);
  4.1192 +		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  4.1193 +				GrabModeAsync, GrabModeSync, None, None);
  4.1194 +
  4.1195 +		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
  4.1196 +				GrabModeAsync, GrabModeSync, None, None);
  4.1197 +		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
  4.1198 +				GrabModeAsync, GrabModeSync, None, None);
  4.1199 +		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  4.1200 +				GrabModeAsync, GrabModeSync, None, None);
  4.1201 +		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  4.1202 +				GrabModeAsync, GrabModeSync, None, None);
  4.1203 +
  4.1204 +		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
  4.1205 +				GrabModeAsync, GrabModeSync, None, None);
  4.1206 +		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
  4.1207 +				GrabModeAsync, GrabModeSync, None, None);
  4.1208 +		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  4.1209 +				GrabModeAsync, GrabModeSync, None, None);
  4.1210 +		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  4.1211 +				GrabModeAsync, GrabModeSync, None, None);
  4.1212 +	} else {
  4.1213 +		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
  4.1214 +				GrabModeAsync, GrabModeSync, None, None);
  4.1215 +	}
  4.1216 +}
  4.1217 +
  4.1218 +static void
  4.1219 +setclientstate(Client *c, long state) {
  4.1220 +	long data[] = {state, None};
  4.1221 +	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  4.1222 +			PropModeReplace, (unsigned char *)data, 2);
  4.1223 +}
  4.1224 +
  4.1225 +static int
  4.1226 +xerrordummy(Display *dsply, XErrorEvent *ee) {
  4.1227 +	return 0;
  4.1228 +}
  4.1229 +
  4.1230 +
  4.1231 +
  4.1232 +void
  4.1233 +configure(Client *c) {
  4.1234 +	XEvent synev;
  4.1235 +
  4.1236 +	synev.type = ConfigureNotify;
  4.1237 +	synev.xconfigure.display = dpy;
  4.1238 +	synev.xconfigure.event = c->win;
  4.1239 +	synev.xconfigure.window = c->win;
  4.1240 +	synev.xconfigure.x = c->x;
  4.1241 +	synev.xconfigure.y = c->y;
  4.1242 +	synev.xconfigure.width = c->w;
  4.1243 +	synev.xconfigure.height = c->h;
  4.1244 +	synev.xconfigure.border_width = c->border;
  4.1245 +	synev.xconfigure.above = None;
  4.1246 +	XSendEvent(dpy, c->win, True, NoEventMask, &synev);
  4.1247 +}
  4.1248 +
  4.1249 +void
  4.1250 +focus(Client *c) {
  4.1251 +	if(c && !isvisible(c))
  4.1252 +		return;
  4.1253 +	if(sel && sel != c) {
  4.1254 +		grabbuttons(sel, False);
  4.1255 +		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
  4.1256 +	}
  4.1257 +	if(c) {
  4.1258 +		detachstack(c);
  4.1259 +		c->snext = stack;
  4.1260 +		stack = c;
  4.1261 +		grabbuttons(c, True);
  4.1262 +	}
  4.1263 +	sel = c;
  4.1264 +	drawstatus();
  4.1265 +	if(!selscreen)
  4.1266 +		return;
  4.1267 +	if(c) {
  4.1268 +		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
  4.1269 +		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  4.1270 +	} else {
  4.1271 +		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
  4.1272 +	}
  4.1273 +}
  4.1274 +
  4.1275 +Client *
  4.1276 +getclient(Window w) {
  4.1277 +	Client *c;
  4.1278 +
  4.1279 +	for(c = clients; c; c = c->next) {
  4.1280 +		if(c->win == w) {
  4.1281 +			return c;
  4.1282 +		}
  4.1283 +	}
  4.1284 +	return NULL;
  4.1285 +}
  4.1286 +
  4.1287 +Bool
  4.1288 +isprotodel(Client *c) {
  4.1289 +	int i, n;
  4.1290 +	Atom *protocols;
  4.1291 +	Bool ret = False;
  4.1292 +
  4.1293 +	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
  4.1294 +		for(i = 0; !ret && i < n; i++)
  4.1295 +			if(protocols[i] == wmatom[WMDelete])
  4.1296 +				ret = True;
  4.1297 +		XFree(protocols);
  4.1298 +	}
  4.1299 +	return ret;
  4.1300 +}
  4.1301 +
  4.1302 +void
  4.1303 +killclient() {
  4.1304 +	if(!sel)
  4.1305 +		return;
  4.1306 +	if(isprotodel(sel))
  4.1307 +		sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
  4.1308 +	else
  4.1309 +		XKillClient(dpy, sel->win);
  4.1310 +}
  4.1311 +
  4.1312 +void
  4.1313 +manage(Window w, XWindowAttributes *wa) {
  4.1314 +	Client *c;
  4.1315 +	Window trans;
  4.1316 +
  4.1317 +	c = emallocz(sizeof(Client));
  4.1318 +	c->tag = True;
  4.1319 +	c->win = w;
  4.1320 +	c->x = wa->x;
  4.1321 +	c->y = wa->y;
  4.1322 +	c->w = wa->width;
  4.1323 +	c->h = wa->height;
  4.1324 +	if(c->w == sw && c->h == sh) {
  4.1325 +		c->border = 0;
  4.1326 +		c->x = sx;
  4.1327 +		c->y = sy;
  4.1328 +	} else {
  4.1329 +		c->border = BORDERPX;
  4.1330 +		if(c->x + c->w + 2 * c->border > wax + waw)
  4.1331 +			c->x = wax + waw - c->w - 2 * c->border;
  4.1332 +		if(c->y + c->h + 2 * c->border > way + wah)
  4.1333 +			c->y = way + wah - c->h - 2 * c->border;
  4.1334 +		if(c->x < wax)
  4.1335 +			c->x = wax;
  4.1336 +		if(c->y < way)
  4.1337 +			c->y = way;
  4.1338 +	}
  4.1339 +	updatesizehints(c);
  4.1340 +	XSelectInput(dpy, c->win,
  4.1341 +		StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  4.1342 +	XGetTransientForHint(dpy, c->win, &trans);
  4.1343 +	grabbuttons(c, False);
  4.1344 +	XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
  4.1345 +	updatetitle(c);
  4.1346 +	settags(c, getclient(trans));
  4.1347 +	if(!c->isfloat)
  4.1348 +		c->isfloat = trans || c->isfixed;
  4.1349 +	if(clients)
  4.1350 +		clients->prev = c;
  4.1351 +	c->next = clients;
  4.1352 +	c->snext = stack;
  4.1353 +	stack = clients = c;
  4.1354 +	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  4.1355 +	XMapWindow(dpy, c->win);
  4.1356 +	setclientstate(c, NormalState);
  4.1357 +	if(isvisible(c))
  4.1358 +		focus(c);
  4.1359 +	arrange();
  4.1360 +}
  4.1361 +
  4.1362 +void
  4.1363 +resize(Client *c, Bool sizehints) {
  4.1364 +	float actual, dx, dy, max, min;
  4.1365 +	XWindowChanges wc;
  4.1366 +
  4.1367 +	if(c->w <= 0 || c->h <= 0)
  4.1368 +		return;
  4.1369 +	if(sizehints) {
  4.1370 +		if(c->minw && c->w < c->minw)
  4.1371 +			c->w = c->minw;
  4.1372 +		if(c->minh && c->h < c->minh)
  4.1373 +			c->h = c->minh;
  4.1374 +		if(c->maxw && c->w > c->maxw)
  4.1375 +			c->w = c->maxw;
  4.1376 +		if(c->maxh && c->h > c->maxh)
  4.1377 +			c->h = c->maxh;
  4.1378 +		/* inspired by algorithm from fluxbox */
  4.1379 +		if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) {
  4.1380 +			dx = (float)(c->w - c->basew);
  4.1381 +			dy = (float)(c->h - c->baseh);
  4.1382 +			min = (float)(c->minax) / (float)(c->minay);
  4.1383 +			max = (float)(c->maxax) / (float)(c->maxay);
  4.1384 +			actual = dx / dy;
  4.1385 +			if(max > 0 && min > 0 && actual > 0) {
  4.1386 +				if(actual < min) {
  4.1387 +					dy = (dx * min + dy) / (min * min + 1);
  4.1388 +					dx = dy * min;
  4.1389 +					c->w = (int)dx + c->basew;
  4.1390 +					c->h = (int)dy + c->baseh;
  4.1391 +				}
  4.1392 +				else if(actual > max) {
  4.1393 +					dy = (dx * min + dy) / (max * max + 1);
  4.1394 +					dx = dy * min;
  4.1395 +					c->w = (int)dx + c->basew;
  4.1396 +					c->h = (int)dy + c->baseh;
  4.1397 +				}
  4.1398 +			}
  4.1399 +		}
  4.1400 +		if(c->incw)
  4.1401 +			c->w -= (c->w - c->basew) % c->incw;
  4.1402 +		if(c->inch)
  4.1403 +			c->h -= (c->h - c->baseh) % c->inch;
  4.1404 +	}
  4.1405 +	if(c->w == sw && c->h == sh)
  4.1406 +		c->border = 0;
  4.1407 +	else
  4.1408 +		c->border = BORDERPX;
  4.1409 +	/* offscreen appearance fixes */
  4.1410 +	if(c->x > sw)
  4.1411 +		c->x = sw - c->w - 2 * c->border;
  4.1412 +	if(c->y > sh)
  4.1413 +		c->y = sh - c->h - 2 * c->border;
  4.1414 +	if(c->x + c->w + 2 * c->border < sx)
  4.1415 +		c->x = sx;
  4.1416 +	if(c->y + c->h + 2 * c->border < sy)
  4.1417 +		c->y = sy;
  4.1418 +	wc.x = c->x;
  4.1419 +	wc.y = c->y;
  4.1420 +	wc.width = c->w;
  4.1421 +	wc.height = c->h;
  4.1422 +	wc.border_width = c->border;
  4.1423 +	XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
  4.1424 +	configure(c);
  4.1425 +	XSync(dpy, False);
  4.1426 +}
  4.1427 +
  4.1428 +void
  4.1429 +updatesizehints(Client *c) {
  4.1430 +	long msize;
  4.1431 +	XSizeHints size;
  4.1432 +
  4.1433 +	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  4.1434 +		size.flags = PSize;
  4.1435 +	c->flags = size.flags;
  4.1436 +	if(c->flags & PBaseSize) {
  4.1437 +		c->basew = size.base_width;
  4.1438 +		c->baseh = size.base_height;
  4.1439 +	} else {
  4.1440 +		c->basew = c->baseh = 0;
  4.1441 +	}
  4.1442 +	if(c->flags & PResizeInc) {
  4.1443 +		c->incw = size.width_inc;
  4.1444 +		c->inch = size.height_inc;
  4.1445 +	} else {
  4.1446 +		c->incw = c->inch = 0;
  4.1447 +	}
  4.1448 +	if(c->flags & PMaxSize) {
  4.1449 +		c->maxw = size.max_width;
  4.1450 +		c->maxh = size.max_height;
  4.1451 +	} else {
  4.1452 +		c->maxw = c->maxh = 0;
  4.1453 +	}
  4.1454 +	if(c->flags & PMinSize) {
  4.1455 +		c->minw = size.min_width;
  4.1456 +		c->minh = size.min_height;
  4.1457 +	} else {
  4.1458 +		c->minw = c->minh = 0;
  4.1459 +	}
  4.1460 +	if(c->flags & PAspect) {
  4.1461 +		c->minax = size.min_aspect.x;
  4.1462 +		c->minay = size.min_aspect.y;
  4.1463 +		c->maxax = size.max_aspect.x;
  4.1464 +		c->maxay = size.max_aspect.y;
  4.1465 +	} else {
  4.1466 +		c->minax = c->minay = c->maxax = c->maxay = 0;
  4.1467 +	}
  4.1468 +	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh &&
  4.1469 +				c->maxw == c->minw && c->maxh == c->minh);
  4.1470 +}
  4.1471 +
  4.1472 +void
  4.1473 +updatetitle(Client *c) {
  4.1474 +	char **list = NULL;
  4.1475 +	int n;
  4.1476 +	XTextProperty name;
  4.1477 +
  4.1478 +	name.nitems = 0;
  4.1479 +	c->name[0] = 0;
  4.1480 +	XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
  4.1481 +	if(!name.nitems)
  4.1482 +		XGetWMName(dpy, c->win, &name);
  4.1483 +	if(!name.nitems)
  4.1484 +		return;
  4.1485 +	if(name.encoding == XA_STRING)
  4.1486 +		strncpy(c->name, (char *)name.value, sizeof c->name);
  4.1487 +	else {
  4.1488 +		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
  4.1489 +			strncpy(c->name, *list, sizeof c->name);
  4.1490 +			XFreeStringList(list);
  4.1491 +		}
  4.1492 +	}
  4.1493 +	XFree(name.value);
  4.1494 +}
  4.1495 +
  4.1496 +void
  4.1497 +unmanage(Client *c) {
  4.1498 +	Client *nc;
  4.1499 +
  4.1500 +	/* The server grab construct avoids race conditions. */
  4.1501 +	XGrabServer(dpy);
  4.1502 +	XSetErrorHandler(xerrordummy);
  4.1503 +	detach(c);
  4.1504 +	detachstack(c);
  4.1505 +	if(sel == c) {
  4.1506 +		for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
  4.1507 +		focus(nc);
  4.1508 +	}
  4.1509 +	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  4.1510 +	setclientstate(c, WithdrawnState);
  4.1511 +	free(c);
  4.1512 +	XSync(dpy, False);
  4.1513 +	XSetErrorHandler(xerror);
  4.1514 +	XUngrabServer(dpy);
  4.1515 +	arrange();
  4.1516 +}
  4.1517 +
  4.1518 +
  4.1519 +
  4.1520 +
  4.1521 +
  4.1522 +
  4.1523 +
  4.1524 +
  4.1525 +
  4.1526 +
  4.1527 +
  4.1528 +
  4.1529 +
  4.1530 +
  4.1531 +
  4.1532 +
  4.1533 +
  4.1534 +
  4.1535 +
  4.1536 +/* static */
  4.1537 +
  4.1538 +
  4.1539 +static void
  4.1540 +cleanup(void) {
  4.1541 +	close(STDIN_FILENO);
  4.1542 +	while(stack) {
  4.1543 +		resize(stack, True);
  4.1544 +		unmanage(stack);
  4.1545 +	}
  4.1546 +	if(dc.font.set)
  4.1547 +		XFreeFontSet(dpy, dc.font.set);
  4.1548 +	else
  4.1549 +		XFreeFont(dpy, dc.font.xfont);
  4.1550 +	XUngrabKey(dpy, AnyKey, AnyModifier, root);
  4.1551 +	XFreePixmap(dpy, dc.drawable);
  4.1552 +	XFreeGC(dpy, dc.gc);
  4.1553 +	XDestroyWindow(dpy, barwin);
  4.1554 +	XFreeCursor(dpy, cursor[CurNormal]);
  4.1555 +	XFreeCursor(dpy, cursor[CurResize]);
  4.1556 +	XFreeCursor(dpy, cursor[CurMove]);
  4.1557 +	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  4.1558 +	XSync(dpy, False);
  4.1559 +}
  4.1560 +
  4.1561 +static void
  4.1562 +scan(void) {
  4.1563 +	unsigned int i, num;
  4.1564 +	Window *wins, d1, d2;
  4.1565 +	XWindowAttributes wa;
  4.1566 +
  4.1567 +	wins = NULL;
  4.1568 +	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
  4.1569 +		for(i = 0; i < num; i++) {
  4.1570 +			if(!XGetWindowAttributes(dpy, wins[i], &wa))
  4.1571 +				continue;
  4.1572 +			if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
  4.1573 +				continue;
  4.1574 +			if(wa.map_state == IsViewable)
  4.1575 +				manage(wins[i], &wa);
  4.1576 +		}
  4.1577 +	}
  4.1578 +	if(wins)
  4.1579 +		XFree(wins);
  4.1580 +}
  4.1581 +
  4.1582 +static void
  4.1583 +setup(void) {
  4.1584 +	int i, j;
  4.1585 +	unsigned int mask;
  4.1586 +	Window w;
  4.1587 +	XModifierKeymap *modmap;
  4.1588 +	XSetWindowAttributes wa;
  4.1589 +
  4.1590 +	/* init atoms */
  4.1591 +	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  4.1592 +	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  4.1593 +	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  4.1594 +	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  4.1595 +	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  4.1596 +	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  4.1597 +			PropModeReplace, (unsigned char *) netatom, NetLast);
  4.1598 +	/* init cursors */
  4.1599 +	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  4.1600 +	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  4.1601 +	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  4.1602 +	/* init modifier map */
  4.1603 +	numlockmask = 0;
  4.1604 +	modmap = XGetModifierMapping(dpy);
  4.1605 +	for (i = 0; i < 8; i++) {
  4.1606 +		for (j = 0; j < modmap->max_keypermod; j++) {
  4.1607 +			if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
  4.1608 +				numlockmask = (1 << i);
  4.1609 +		}
  4.1610 +	}
  4.1611 +	XFreeModifiermap(modmap);
  4.1612 +	/* select for events */
  4.1613 +	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
  4.1614 +		| EnterWindowMask | LeaveWindowMask;
  4.1615 +	wa.cursor = cursor[CurNormal];
  4.1616 +	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
  4.1617 +	grabkeys();
  4.1618 +	initrregs();
  4.1619 +	ntags = 2;
  4.1620 +	seltag = True;
  4.1621 +	/* style */
  4.1622 +	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  4.1623 +	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  4.1624 +	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  4.1625 +	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
  4.1626 +	dc.sel[ColBG] = getcolor(SELBGCOLOR);
  4.1627 +	dc.sel[ColFG] = getcolor(SELFGCOLOR);
  4.1628 +	setfont(FONT);
  4.1629 +	/* geometry */
  4.1630 +	sx = sy = 0;
  4.1631 +	sw = DisplayWidth(dpy, screen);
  4.1632 +	sh = DisplayHeight(dpy, screen);
  4.1633 +	nmaster = NMASTER;
  4.1634 +	bmw = 1;
  4.1635 +	/* bar */
  4.1636 +	dc.h = bh = dc.font.height + 2;
  4.1637 +	wa.override_redirect = 1;
  4.1638 +	wa.background_pixmap = ParentRelative;
  4.1639 +	wa.event_mask = ButtonPressMask | ExposureMask;
  4.1640 +	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
  4.1641 +			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
  4.1642 +			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  4.1643 +	XDefineCursor(dpy, barwin, cursor[CurNormal]);
  4.1644 +	XMapRaised(dpy, barwin);
  4.1645 +	strcpy(stext, "dwm-"VERSION);
  4.1646 +	/* windowarea */
  4.1647 +	wax = sx;
  4.1648 +	way = sy + bh;
  4.1649 +	wah = sh - bh;
  4.1650 +	waw = sw;
  4.1651 +	/* pixmap for everything */
  4.1652 +	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
  4.1653 +	dc.gc = XCreateGC(dpy, root, 0, 0);
  4.1654 +	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  4.1655 +	/* multihead support */
  4.1656 +	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
  4.1657 +}
  4.1658 +
  4.1659 +/*
  4.1660 + * Startup Error handler to check if another window manager
  4.1661 + * is already running.
  4.1662 + */
  4.1663 +static int
  4.1664 +xerrorstart(Display *dsply, XErrorEvent *ee) {
  4.1665 +	otherwm = True;
  4.1666 +	return -1;
  4.1667 +}
  4.1668 +
  4.1669 +
  4.1670 +
  4.1671 +void
  4.1672 +sendevent(Window w, Atom a, long value) {
  4.1673 +	XEvent e;
  4.1674 +
  4.1675 +	e.type = ClientMessage;
  4.1676 +	e.xclient.window = w;
  4.1677 +	e.xclient.message_type = a;
  4.1678 +	e.xclient.format = 32;
  4.1679 +	e.xclient.data.l[0] = value;
  4.1680 +	e.xclient.data.l[1] = CurrentTime;
  4.1681 +	XSendEvent(dpy, w, False, NoEventMask, &e);
  4.1682 +	XSync(dpy, False);
  4.1683 +}
  4.1684 +
  4.1685 +void
  4.1686 +quit() {
  4.1687 +	readin = running = False;
  4.1688 +}
  4.1689 +
  4.1690 +/* There's no way to check accesses to destroyed windows, thus those cases are
  4.1691 + * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
  4.1692 + * default error handler, which may call exit.
  4.1693 + */
  4.1694 +int
  4.1695 +xerror(Display *dpy, XErrorEvent *ee) {
  4.1696 +	if(ee->error_code == BadWindow
  4.1697 +	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
  4.1698 +	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
  4.1699 +	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
  4.1700 +	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
  4.1701 +	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
  4.1702 +	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
  4.1703 +	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
  4.1704 +		return 0;
  4.1705 +	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
  4.1706 +		ee->request_code, ee->error_code);
  4.1707 +	return xerrorxlib(dpy, ee); /* may call exit */
  4.1708 +}
  4.1709 +
  4.1710 +int
  4.1711 +main(int argc, char *argv[]) {
  4.1712 +	char *p;
  4.1713 +	int r, xfd;
  4.1714 +	fd_set rd;
  4.1715 +
  4.1716 +	if(argc == 2 && !strncmp("-v", argv[1], 3)) {
  4.1717 +		fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout);
  4.1718 +		exit(EXIT_SUCCESS);
  4.1719 +	} else if(argc != 1) {
  4.1720 +		eprint("usage: dwm [-v]\n");
  4.1721 +	}
  4.1722 +	setlocale(LC_CTYPE, "");
  4.1723 +	dpy = XOpenDisplay(0);
  4.1724 +	if(!dpy) {
  4.1725 +		eprint("dwm: cannot open display\n");
  4.1726 +	}
  4.1727 +	xfd = ConnectionNumber(dpy);
  4.1728 +	screen = DefaultScreen(dpy);
  4.1729 +	root = RootWindow(dpy, screen);
  4.1730 +	otherwm = False;
  4.1731 +	XSetErrorHandler(xerrorstart);
  4.1732 +	/* this causes an error if some other window manager is running */
  4.1733 +	XSelectInput(dpy, root, SubstructureRedirectMask);
  4.1734 +	XSync(dpy, False);
  4.1735 +	if(otherwm) {
  4.1736 +		eprint("dwm: another window manager is already running\n");
  4.1737 +	}
  4.1738 +
  4.1739 +	XSync(dpy, False);
  4.1740 +	XSetErrorHandler(NULL);
  4.1741 +	xerrorxlib = XSetErrorHandler(xerror);
  4.1742 +	XSync(dpy, False);
  4.1743 +	setup();
  4.1744 +	drawstatus();
  4.1745 +	scan();
  4.1746 +
  4.1747 +	/* main event loop, also reads status text from stdin */
  4.1748 +	XSync(dpy, False);
  4.1749 +	procevent();
  4.1750 +	readin = True;
  4.1751 +	while(running) {
  4.1752 +		FD_ZERO(&rd);
  4.1753 +		if(readin)
  4.1754 +			FD_SET(STDIN_FILENO, &rd);
  4.1755 +		FD_SET(xfd, &rd);
  4.1756 +		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
  4.1757 +			if(errno == EINTR)
  4.1758 +				continue;
  4.1759 +			eprint("select failed\n");
  4.1760 +		}
  4.1761 +		if(FD_ISSET(STDIN_FILENO, &rd)) {
  4.1762 +			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
  4.1763 +			case -1:
  4.1764 +				strncpy(stext, strerror(errno), sizeof stext - 1);
  4.1765 +				stext[sizeof stext - 1] = '\0';
  4.1766 +				readin = False;
  4.1767 +				break;
  4.1768 +			case 0:
  4.1769 +				strncpy(stext, "EOF", 4);
  4.1770 +				readin = False;
  4.1771 +				break;
  4.1772 +			default:
  4.1773 +				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
  4.1774 +				for(; p >= stext && *p != '\n'; --p);
  4.1775 +				if(p > stext)
  4.1776 +					strncpy(stext, p + 1, sizeof stext);
  4.1777 +			}
  4.1778 +			drawstatus();
  4.1779 +		}
  4.1780 +		if(FD_ISSET(xfd, &rd))
  4.1781 +			procevent();
  4.1782 +	}
  4.1783 +	cleanup();
  4.1784 +	XCloseDisplay(dpy);
  4.1785 +	return 0;
  4.1786 +}
     5.1 --- a/config.mk	Fri May 30 21:57:51 2008 +0200
     5.2 +++ b/config.mk	Fri May 30 22:18:18 2008 +0200
     5.3 @@ -1,5 +1,5 @@
     5.4 -# dwm version
     5.5 -VERSION = 4.4.1
     5.6 +# aewl version
     5.7 +VERSION = 0.1
     5.8  
     5.9  # Customize below to fit your system
    5.10  
    5.11 @@ -15,7 +15,8 @@
    5.12  LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
    5.13  
    5.14  # flags
    5.15 -CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\" -W -Wall -pedantic
    5.16 +DEBUG = -Wall -Wpointer-arith -Wstrict-prototypes -O2 -W -pedantic
    5.17 +CFLAGS =  ${INCS} -DVERSION=\"${VERSION}\" ${DEBUG}
    5.18  LDFLAGS = ${LIBS}
    5.19  #CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
    5.20  #LDFLAGS = -g ${LIBS}
     6.1 --- a/dwm.1	Fri May 30 21:57:51 2008 +0200
     6.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.3 @@ -1,149 +0,0 @@
     6.4 -.TH DWM 1 dwm-VERSION
     6.5 -.SH NAME
     6.6 -dwm \- dynamic window manager
     6.7 -.SH SYNOPSIS
     6.8 -.B dwm
     6.9 -.RB [ \-v ]
    6.10 -.SH DESCRIPTION
    6.11 -dwm is a dynamic window manager for X. It manages windows in tiling and
    6.12 -floating modes. Either mode can be applied dynamically, optimizing the
    6.13 -environment for the application in use and the task performed.
    6.14 -.P
    6.15 -In tiling mode windows are managed in a master and stacking area. The master
    6.16 -area contains the windows which currently need most attention, whereas the
    6.17 -stacking area contains all other windows. In floating mode windows can be
    6.18 -resized and moved freely. Dialog windows are always managed floating,
    6.19 -regardless of the mode applied.
    6.20 -.P
    6.21 -Windows are grouped by tags. Each window can be tagged with one or multiple
    6.22 -tags. Selecting certain tags displays all windows with these tags.
    6.23 -.P
    6.24 -dwm contains a small status bar which displays all available tags, the mode,
    6.25 -the title of the focused window, and the text read from standard input. The
    6.26 -selected tags are indicated with a different color. The tags of the focused
    6.27 -window are indicated with a filled square in the top left corner.  The tags
    6.28 -which are applied to one or more windows are indicated with an empty square in
    6.29 -the top left corner.
    6.30 -.P
    6.31 -dwm draws a small border around windows to indicate the focus state.
    6.32 -.SH OPTIONS
    6.33 -.TP
    6.34 -.B \-v
    6.35 -prints version information to standard output, then exits.
    6.36 -.SH USAGE
    6.37 -.SS Status bar
    6.38 -.TP
    6.39 -.B Standard input
    6.40 -is read and displayed in the status text area.
    6.41 -.TP
    6.42 -.B Button1
    6.43 -click on a tag label to display all windows with that tag, click on the mode
    6.44 -label toggles between tiling and floating mode.
    6.45 -.TP
    6.46 -.B Button3
    6.47 -click on a tag label adds/removes all windows with that tag to/from the view.
    6.48 -.TP
    6.49 -.B Button4
    6.50 -click on the mode label increases the number of windows in the master area (tiling mode only).
    6.51 -.TP
    6.52 -.B Button5
    6.53 -click on the mode label decreases the number of windows in the master area (tiling mode only).
    6.54 -.TP
    6.55 -.B Mod1-Button1
    6.56 -click on a tag label applies that tag to the focused window.
    6.57 -.TP
    6.58 -.B Mod1-Button3
    6.59 -click on a tag label adds/removes that tag to/from the focused window.
    6.60 -.SS Keyboard commands
    6.61 -.TP
    6.62 -.B Mod1-Shift-Return
    6.63 -Start
    6.64 -.BR xterm (1).
    6.65 -.TP
    6.66 -.B Mod1-Tab
    6.67 -Focus next window.
    6.68 -.TP
    6.69 -.B Mod1-Shift-Tab
    6.70 -Focus previous window.
    6.71 -.TP
    6.72 -.B Mod1-Return
    6.73 -Zooms/cycles current window to/from master area (tiling mode), toggles maximization current window (floating mode).
    6.74 -.TP
    6.75 -.B Mod1-g
    6.76 -Grow master area (tiling mode only).
    6.77 -.TP
    6.78 -.B Mod1-s
    6.79 -Shrink master area (tiling mode only).
    6.80 -.TP
    6.81 -.B Mod1-i
    6.82 -Increase the number of windows in the master area (tiling mode only).
    6.83 -.TP
    6.84 -.B Mod1-d
    6.85 -Decrease the number of windows in the master area (tiling mode only).
    6.86 -.TP
    6.87 -.B Mod1-Shift-[1..n]
    6.88 -Apply
    6.89 -.RB nth
    6.90 -tag to current window.
    6.91 -.TP
    6.92 -.B Mod1-Shift-0
    6.93 -Apply all tags to current window.
    6.94 -.TP
    6.95 -.B Mod1-Control-Shift-[1..n]
    6.96 -Add/remove
    6.97 -.B nth
    6.98 -tag to/from current window.
    6.99 -.TP
   6.100 -.B Mod1-Shift-c
   6.101 -Close focused window.
   6.102 -.TP
   6.103 -.B Mod1-space
   6.104 -Toggle between tiling and floating mode (affects all windows).
   6.105 -.TP
   6.106 -.B Mod1-Shift-space
   6.107 -Toggle focused window between floating and non-floating state (tiling mode only).
   6.108 -.TP
   6.109 -.B Mod1-[1..n]
   6.110 -View all windows with
   6.111 -.BR nth
   6.112 -tag.
   6.113 -.TP
   6.114 -.B Mod1-0
   6.115 -View all windows with any tag.
   6.116 -.TP
   6.117 -.B Mod1-Control-[1..n]
   6.118 -Add/remove all windows with
   6.119 -.BR nth
   6.120 -tag to/from the view.
   6.121 -.TP
   6.122 -.B Mod1-Shift-q
   6.123 -Quit dwm.
   6.124 -.SS Mouse commands
   6.125 -.TP
   6.126 -.B Mod1-Button1
   6.127 -Move current window while dragging (floating mode only).
   6.128 -.TP
   6.129 -.B Mod1-Button2
   6.130 -Zoom current window to the master area (tiling mode only).
   6.131 -.TP
   6.132 -.B Mod1-Button3
   6.133 -Resize current window while dragging (floating mode only).
   6.134 -.SH CUSTOMIZATION
   6.135 -dwm is customized by creating a custom config.h and (re)compiling the source
   6.136 -code. This keeps it fast, secure and simple.
   6.137 -.SH SEE ALSO
   6.138 -.BR dmenu (1)
   6.139 -.SH BUGS
   6.140 -The status bar may display
   6.141 -.BR "EOF"
   6.142 -when dwm has been started by an X session manager like
   6.143 -.BR xdm (1),
   6.144 -because those close standard output before executing dwm.
   6.145 -.P
   6.146 -Java applications which use the XToolkit/XAWT backend may draw grey windows
   6.147 -only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
   6.148 -JDK 1.6 versions, because it assumes a reparenting window manager. As a workaround
   6.149 -you can use JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or you
   6.150 -can set the following environment variable (to use the older Motif
   6.151 -backend instead):
   6.152 -.BR AWT_TOOLKIT=MToolkit .
     7.1 --- a/dwm.c	Fri May 30 21:57:51 2008 +0200
     7.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.3 @@ -1,1782 +0,0 @@
     7.4 -/* (C)opyright MMVI-MMVII Anselm R. Garbe <garbeam at gmail dot com>
     7.5 - * See LICENSE file for license details.
     7.6 - *
     7.7 - * dynamic window manager is designed like any other X client as well. It is
     7.8 - * driven through handling X events. In contrast to other X clients, a window
     7.9 - * manager selects for SubstructureRedirectMask on the root window, to receive
    7.10 - * events about window (dis-)appearance.  Only one X connection at a time is
    7.11 - * allowed to select for this event mask.
    7.12 - *
    7.13 - * Calls to fetch an X event from the event queue are blocking.  Due reading
    7.14 - * status text from standard input, a select()-driven main loop has been
    7.15 - * implemented which selects for reads on the X connection and STDIN_FILENO to
    7.16 - * handle all data smoothly. The event handlers of dwm are organized in an
    7.17 - * array which is accessed whenever a new event has been fetched. This allows
    7.18 - * event dispatching in O(1) time.
    7.19 - *
    7.20 - * Each child of the root window is called a client, except windows which have
    7.21 - * set the override_redirect flag.  Clients are organized in a global
    7.22 - * doubly-linked client list, the focus history is remembered through a global
    7.23 - * stack list. Each client contains an array of Bools of the same size as the
    7.24 - * global tags array to indicate the tags of a client.  For each client dwm
    7.25 - * creates a small title window, which is resized whenever the (_NET_)WM_NAME
    7.26 - * properties are updated or the client is moved/resized.
    7.27 - *
    7.28 - * Keys and tagging rules are organized as arrays and defined in the config.h
    7.29 - * file. These arrays are kept static in event.o and tag.o respectively,
    7.30 - * because no other part of dwm needs access to them.  The current mode is
    7.31 - * represented by the arrange() function pointer, which wether points to
    7.32 - * dofloat() or dotile().
    7.33 - *
    7.34 - * To understand everything else, start reading main.c:main().
    7.35 - */
    7.36 -
    7.37 -#include "config.h"
    7.38 -#include <errno.h>
    7.39 -#include <locale.h>
    7.40 -#include <regex.h>
    7.41 -#include <stdio.h>
    7.42 -#include <stdarg.h>
    7.43 -#include <stdlib.h>
    7.44 -#include <string.h>
    7.45 -#include <unistd.h>
    7.46 -#include <sys/select.h>
    7.47 -#include <sys/types.h>
    7.48 -#include <sys/wait.h>
    7.49 -#include <X11/cursorfont.h>
    7.50 -#include <X11/keysym.h>
    7.51 -#include <X11/Xatom.h>
    7.52 -#include <X11/Xlib.h>
    7.53 -#include <X11/Xproto.h>
    7.54 -#include <X11/Xutil.h>
    7.55 -
    7.56 -/* mask shorthands, used in event.c and client.c */
    7.57 -#define BUTTONMASK		(ButtonPressMask | ButtonReleaseMask)
    7.58 -
    7.59 -enum { NetSupported, NetWMName, NetLast };		/* EWMH atoms */
    7.60 -enum { WMProtocols, WMDelete, WMState, WMLast };	/* default atoms */
    7.61 -enum { CurNormal, CurResize, CurMove, CurLast };	/* cursor */
    7.62 -enum { ColBorder, ColFG, ColBG, ColLast };		/* color */
    7.63 -
    7.64 -typedef struct {
    7.65 -	int ascent;
    7.66 -	int descent;
    7.67 -	int height;
    7.68 -	XFontSet set;
    7.69 -	XFontStruct *xfont;
    7.70 -} Fnt;
    7.71 -
    7.72 -typedef struct {
    7.73 -	int x, y, w, h;
    7.74 -	unsigned long norm[ColLast];
    7.75 -	unsigned long sel[ColLast];
    7.76 -	Drawable drawable;
    7.77 -	Fnt font;
    7.78 -	GC gc;
    7.79 -} DC; /* draw context */
    7.80 -
    7.81 -typedef struct Client Client;
    7.82 -struct Client {
    7.83 -	char name[256];
    7.84 -	int x, y, w, h;
    7.85 -	int rx, ry, rw, rh; /* revert geometry */
    7.86 -	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
    7.87 -	int minax, minay, maxax, maxay;
    7.88 -	long flags;
    7.89 -	unsigned int border;
    7.90 -	Bool isfixed, isfloat, ismax;
    7.91 -	Bool tag;
    7.92 -	Client *next;
    7.93 -	Client *prev;
    7.94 -	Client *snext;
    7.95 -	Window win;
    7.96 -};
    7.97 -
    7.98 -typedef struct {
    7.99 -	const char *clpattern;
   7.100 -	int tag;
   7.101 -	Bool isfloat;
   7.102 -} Rule;
   7.103 -
   7.104 -typedef struct {
   7.105 -	regex_t *clregex;
   7.106 -} RReg;
   7.107 -
   7.108 -
   7.109 -typedef struct {
   7.110 -	unsigned long mod;
   7.111 -	KeySym keysym;
   7.112 -	void (*func)(const char* cmd);
   7.113 -	const char* cmd;
   7.114 -} Key;
   7.115 -
   7.116 -
   7.117 -#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
   7.118 -#define MOUSEMASK		(BUTTONMASK | PointerMotionMask)
   7.119 -
   7.120 -
   7.121 -
   7.122 -const char *tags[];			/* all tags */
   7.123 -char stext[256];				/* status text */
   7.124 -int bh, bmw;				/* bar height, bar mode label width */
   7.125 -int screen, sx, sy, sw, sh;		/* screen geometry */
   7.126 -int wax, way, wah, waw;			/* windowarea geometry */
   7.127 -unsigned int nmaster;		/* number of master clients */
   7.128 -unsigned int ntags, numlockmask;		/* number of tags, dynamic lock mask */
   7.129 -void (*handler[LASTEvent])(XEvent *);	/* event handler */
   7.130 -void (*arrange)(void);			/* arrange function, indicates mode  */
   7.131 -Atom wmatom[WMLast], netatom[NetLast];
   7.132 -Bool running, selscreen, seltag;	/* seltag is array of Bool */
   7.133 -Client *clients, *sel, *stack;		/* global client list and stack */
   7.134 -Cursor cursor[CurLast];
   7.135 -DC dc;					/* global draw context */
   7.136 -Display *dpy;
   7.137 -Window root, barwin;
   7.138 -
   7.139 -Bool running = True;
   7.140 -Bool selscreen = True;
   7.141 -Client *clients = NULL;
   7.142 -Client *sel = NULL;
   7.143 -Client *stack = NULL;
   7.144 -DC dc = {0};
   7.145 -
   7.146 -static int (*xerrorxlib)(Display *, XErrorEvent *);
   7.147 -static Bool otherwm, readin;
   7.148 -static RReg *rreg = NULL;
   7.149 -static unsigned int len = 0;
   7.150 -
   7.151 -
   7.152 -TAGS
   7.153 -RULES
   7.154 -
   7.155 -
   7.156 -/* client.c */
   7.157 -void configure(Client *c);		/* send synthetic configure event */
   7.158 -void focus(Client *c);			/* focus c, c may be NULL */
   7.159 -Client *getclient(Window w);		/* return client of w */
   7.160 -Bool isprotodel(Client *c);		/* returns True if c->win supports wmatom[WMDelete] */
   7.161 -void manage(Window w, XWindowAttributes *wa);	/* manage new client */
   7.162 -void resize(Client *c, Bool sizehints);	/* resize c*/
   7.163 -void updatesizehints(Client *c);		/* update the size hint variables of c */
   7.164 -void updatetitle(Client *c);		/* update the name of c */
   7.165 -void unmanage(Client *c);		/* destroy c */
   7.166 -
   7.167 -/* draw.c */
   7.168 -void drawstatus(void);			/* draw the bar */
   7.169 -unsigned long getcolor(const char *colstr);	/* return color of colstr */
   7.170 -void setfont(const char *fontstr);	/* set the font for DC */
   7.171 -unsigned int textw(const char *text);	/* return the width of text in px*/
   7.172 -
   7.173 -/* event.c */
   7.174 -void grabkeys(void);			/* grab all keys defined in config.h */
   7.175 -void procevent(void);			/* process pending X events */
   7.176 -
   7.177 -/* main.c */
   7.178 -void sendevent(Window w, Atom a, long value);	/* send synthetic event to w */
   7.179 -int xerror(Display *dsply, XErrorEvent *ee);	/* dwm's X error handler */
   7.180 -
   7.181 -/* tag.c */
   7.182 -void initrregs(void);			/* initialize regexps of rules defined in config.h */
   7.183 -Client *getnext(Client *c);		/* returns next visible client */
   7.184 -void settags(Client *c, Client *trans);	/* sets tags of c */
   7.185 -
   7.186 -/* util.c */
   7.187 -void *emallocz(unsigned int size);	/* allocates zero-initialized memory, exits on error */
   7.188 -void eprint(const char *errstr, ...);	/* prints errstr and exits with 1 */
   7.189 -
   7.190 -/* view.c */
   7.191 -void detach(Client *c);			/* detaches c from global client list */
   7.192 -void dofloat(void);			/* arranges all windows floating */
   7.193 -void dotile(void);			/* arranges all windows tiled */
   7.194 -void domax(void);            /* arranges all windows fullscreen */
   7.195 -Bool isvisible(Client *c);		/* returns True if client is visible */
   7.196 -void restack(void);			/* restores z layers of all clients */
   7.197 -
   7.198 -
   7.199 -void toggleview();			/* toggle the viewed tag */
   7.200 -void focusnext();		/* focuses next visible client  */
   7.201 -void zoom();			/* zooms the focused client to master area */
   7.202 -void killclient();		/* kill c nicely */
   7.203 -void quit();			/* quit dwm nicely */
   7.204 -void togglemode();		/* toggles global arrange function (dotile/dofloat) */
   7.205 -void togglefloat();		/* toggles focusesd client between floating/non-floating state */
   7.206 -void incnmaster();		/* increments nmaster */
   7.207 -void decnmaster();		/* decrements nmaster */
   7.208 -void toggletag();		/* toggles c tag */
   7.209 -void spawn(const char* cmd);			/* forks a new subprocess with cmd */
   7.210 -
   7.211 -
   7.212 -
   7.213 -
   7.214 -
   7.215 -
   7.216 -
   7.217 -
   7.218 -
   7.219 -
   7.220 -/* from view.c */
   7.221 -/* static */
   7.222 -
   7.223 -static Client *
   7.224 -nexttiled(Client *c) {
   7.225 -	for(c = getnext(c); c && c->isfloat; c = getnext(c->next));
   7.226 -	return c;
   7.227 -}
   7.228 -
   7.229 -static void
   7.230 -togglemax(Client *c) {
   7.231 -	XEvent ev;
   7.232 -		
   7.233 -	if(c->isfixed)
   7.234 -		return;
   7.235 -
   7.236 -	if((c->ismax = !c->ismax)) {
   7.237 -		c->rx = c->x; c->x = wax;
   7.238 -		c->ry = c->y; c->y = way;
   7.239 -		c->rw = c->w; c->w = waw - 2 * BORDERPX;
   7.240 -		c->rh = c->h; c->h = wah - 2 * BORDERPX;
   7.241 -	}
   7.242 -	else {
   7.243 -		c->x = c->rx;
   7.244 -		c->y = c->ry;
   7.245 -		c->w = c->rw;
   7.246 -		c->h = c->rh;
   7.247 -	}
   7.248 -	resize(c, True);
   7.249 -	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
   7.250 -}
   7.251 -
   7.252 -
   7.253 -
   7.254 -void (*arrange)(void) = DEFMODE;
   7.255 -
   7.256 -void
   7.257 -detach(Client *c) {
   7.258 -	if(c->prev)
   7.259 -		c->prev->next = c->next;
   7.260 -	if(c->next)
   7.261 -		c->next->prev = c->prev;
   7.262 -	if(c == clients)
   7.263 -		clients = c->next;
   7.264 -	c->next = c->prev = NULL;
   7.265 -}
   7.266 -
   7.267 -void
   7.268 -dofloat(void) {
   7.269 -	Client *c;
   7.270 -
   7.271 -	for(c = clients; c; c = c->next) {
   7.272 -		if(isvisible(c)) {
   7.273 -			resize(c, True);
   7.274 -		}
   7.275 -		else
   7.276 -			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   7.277 -	}
   7.278 -	if(!sel || !isvisible(sel)) {
   7.279 -		for(c = stack; c && !isvisible(c); c = c->snext);
   7.280 -		focus(c);
   7.281 -	}
   7.282 -	restack();
   7.283 -}
   7.284 -
   7.285 -void
   7.286 -dotile(void) {
   7.287 -	unsigned int i, n, mw, mh, tw, th;
   7.288 -	Client *c;
   7.289 -
   7.290 -	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
   7.291 -		n++;
   7.292 -	/* window geoms */
   7.293 -	mh = (n > nmaster) ? wah / nmaster : wah / (n > 0 ? n : 1);
   7.294 -	mw = (n > nmaster) ? waw / 2 : waw;
   7.295 -	th = (n > nmaster) ? wah / (n - nmaster) : 0;
   7.296 -	tw = waw - mw;
   7.297 -
   7.298 -	for(i = 0, c = clients; c; c = c->next)
   7.299 -		if(isvisible(c)) {
   7.300 -			if(c->isfloat) {
   7.301 -				resize(c, True);
   7.302 -				continue;
   7.303 -			}
   7.304 -			c->ismax = False;
   7.305 -			c->x = wax;
   7.306 -			c->y = way;
   7.307 -			if(i < nmaster) {
   7.308 -				c->y += i * mh;
   7.309 -				c->w = mw - 2 * BORDERPX;
   7.310 -				c->h = mh - 2 * BORDERPX;
   7.311 -			}
   7.312 -			else {  /* tile window */
   7.313 -				c->x += mw;
   7.314 -				c->w = tw - 2 * BORDERPX;
   7.315 -				if(th > 2 * BORDERPX) {
   7.316 -					c->y += (i - nmaster) * th;
   7.317 -					c->h = th - 2 * BORDERPX;
   7.318 -				}
   7.319 -				else /* fallback if th <= 2 * BORDERPX */
   7.320 -					c->h = wah - 2 * BORDERPX;
   7.321 -			}
   7.322 -			resize(c, False);
   7.323 -			i++;
   7.324 -		}
   7.325 -		else
   7.326 -			XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   7.327 -	if(!sel || !isvisible(sel)) {
   7.328 -		for(c = stack; c && !isvisible(c); c = c->snext);
   7.329 -		focus(c);
   7.330 -	}
   7.331 -	restack();
   7.332 -}
   7.333 -
   7.334 -/* begin code by mitch */
   7.335 -void
   7.336 -arrangemax(Client *c) {
   7.337 -  if(c == sel) {
   7.338 -    c->ismax = True;
   7.339 -    c->x = sx;
   7.340 -    c->y = bh;
   7.341 -    c->w = sw - 2 * BORDERPX;
   7.342 -    c->h = sh - bh - 2 * BORDERPX;
   7.343 -    XRaiseWindow(dpy, c->win);
   7.344 -  } else {
   7.345 -    c->ismax = False;
   7.346 -    XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   7.347 -    XLowerWindow(dpy, c->win);
   7.348 -  }
   7.349 -}
   7.350 -
   7.351 -void
   7.352 -domax(void) {
   7.353 -  Client *c;
   7.354 -
   7.355 -  for(c = clients; c; c = c->next) {
   7.356 -    if(isvisible(c)) {
   7.357 -      if(c->isfloat) {
   7.358 -        resize(c, True);
   7.359 -        continue;
   7.360 -      }
   7.361 -      arrangemax(c);
   7.362 -      resize(c, False);
   7.363 -    } else {
   7.364 -      XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   7.365 -    }
   7.366 -
   7.367 -  }
   7.368 -  if(!sel || !isvisible(sel)) {
   7.369 -    for(c = stack; c && !isvisible(c); c = c->snext);
   7.370 -    focus(c);
   7.371 -  }
   7.372 -  restack();
   7.373 -}
   7.374 -/* end code by mitch */
   7.375 -
   7.376 -void
   7.377 -focusnext() {
   7.378 -	Client *c;
   7.379 -
   7.380 -	if(!sel)
   7.381 -		return;
   7.382 -	if(!(c = getnext(sel->next)))
   7.383 -		c = getnext(clients);
   7.384 -	if(c) {
   7.385 -		focus(c);
   7.386 -		restack();
   7.387 -	}
   7.388 -}
   7.389 -
   7.390 -void
   7.391 -incnmaster() {
   7.392 -	if((arrange == dofloat) || (wah / (nmaster + 1) <= 2 * BORDERPX))
   7.393 -		return;
   7.394 -	nmaster++;
   7.395 -	if(sel)
   7.396 -		arrange();
   7.397 -	else
   7.398 -		drawstatus();
   7.399 -}
   7.400 -
   7.401 -void
   7.402 -decnmaster() {
   7.403 -	if((arrange == dofloat) || (nmaster <= 1))
   7.404 -		return;
   7.405 -	nmaster--;
   7.406 -	if(sel)
   7.407 -		arrange();
   7.408 -	else
   7.409 -		drawstatus();
   7.410 -}
   7.411 -
   7.412 -Bool
   7.413 -isvisible(Client *c) {
   7.414 -	if((c->tag && seltag) || (!c->tag && !seltag)) {
   7.415 -		return True;
   7.416 -	}
   7.417 -	return False;
   7.418 -}
   7.419 -
   7.420 -void
   7.421 -restack(void) {
   7.422 -	Client *c;
   7.423 -	XEvent ev;
   7.424 -
   7.425 -	drawstatus();
   7.426 -	if(!sel)
   7.427 -		return;
   7.428 -	if(sel->isfloat || arrange == dofloat)
   7.429 -		XRaiseWindow(dpy, sel->win);
   7.430 -
   7.431 -  /* begin code by mitch */
   7.432 -  if(arrange == domax) {
   7.433 -    for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
   7.434 -      arrangemax(c);
   7.435 -      resize(c, False);
   7.436 -    }
   7.437 -
   7.438 -  } else if (arrange == dotile) {
   7.439 -  /* end code by mitch */
   7.440 -
   7.441 -		if(!sel->isfloat)
   7.442 -			XLowerWindow(dpy, sel->win);
   7.443 -		for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
   7.444 -			if(c == sel)
   7.445 -				continue;
   7.446 -			XLowerWindow(dpy, c->win);
   7.447 -		}
   7.448 -	}
   7.449 -	XSync(dpy, False);
   7.450 -	while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
   7.451 -}
   7.452 -
   7.453 -void
   7.454 -togglefloat() {
   7.455 -	if (!sel || arrange == dofloat)
   7.456 -		return;
   7.457 -	sel->isfloat = !sel->isfloat;
   7.458 -	arrange();
   7.459 -}
   7.460 -
   7.461 -void
   7.462 -togglemode() {
   7.463 -  /* only toggle between tile and max - float is just available through togglefloat */
   7.464 -  arrange = (arrange == dotile) ? domax : dotile;
   7.465 -	if(sel)
   7.466 -		arrange();
   7.467 -	else
   7.468 -		drawstatus();
   7.469 -}
   7.470 -
   7.471 -void
   7.472 -toggleview() {
   7.473 -	seltag = !seltag;
   7.474 -	arrange();
   7.475 -}
   7.476 -
   7.477 -void
   7.478 -zoom() {
   7.479 -	unsigned int n;
   7.480 -	Client *c;
   7.481 -
   7.482 -	if(!sel)
   7.483 -		return;
   7.484 -	if(sel->isfloat || (arrange == dofloat)) {
   7.485 -		togglemax(sel);
   7.486 -		return;
   7.487 -	}
   7.488 -	for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next))
   7.489 -		n++;
   7.490 -
   7.491 -	if((c = sel) == nexttiled(clients))
   7.492 -		if(!(c = nexttiled(c->next)))
   7.493 -			return;
   7.494 -	detach(c);
   7.495 -	if(clients)
   7.496 -		clients->prev = c;
   7.497 -	c->next = clients;
   7.498 -	clients = c;
   7.499 -	focus(c);
   7.500 -	arrange();
   7.501 -}
   7.502 -
   7.503 -
   7.504 -
   7.505 -
   7.506 -
   7.507 -
   7.508 -
   7.509 -
   7.510 -
   7.511 -
   7.512 -
   7.513 -
   7.514 -
   7.515 -
   7.516 -
   7.517 -
   7.518 -/* from util.c */
   7.519 -
   7.520 -
   7.521 -void *
   7.522 -emallocz(unsigned int size) {
   7.523 -	void *res = calloc(1, size);
   7.524 -
   7.525 -	if(!res)
   7.526 -		eprint("fatal: could not malloc() %u bytes\n", size);
   7.527 -	return res;
   7.528 -}
   7.529 -
   7.530 -void
   7.531 -eprint(const char *errstr, ...) {
   7.532 -	va_list ap;
   7.533 -
   7.534 -	va_start(ap, errstr);
   7.535 -	vfprintf(stderr, errstr, ap);
   7.536 -	va_end(ap);
   7.537 -	exit(EXIT_FAILURE);
   7.538 -}
   7.539 -
   7.540 -void
   7.541 -spawn(const char* cmd) {
   7.542 -	static char *shell = NULL;
   7.543 -
   7.544 -	if(!shell && !(shell = getenv("SHELL")))
   7.545 -		shell = "/bin/sh";
   7.546 -	if(!cmd)
   7.547 -		return;
   7.548 -	/* The double-fork construct avoids zombie processes and keeps the code
   7.549 -	 * clean from stupid signal handlers. */
   7.550 -	if(fork() == 0) {
   7.551 -		if(fork() == 0) {
   7.552 -			if(dpy)
   7.553 -				close(ConnectionNumber(dpy));
   7.554 -			setsid();
   7.555 -			execl(shell, shell, "-c", cmd, (char *)NULL);
   7.556 -			fprintf(stderr, "dwm: execl '%s -c %s'", shell, cmd);
   7.557 -			perror(" failed");
   7.558 -		}
   7.559 -		exit(0);
   7.560 -	}
   7.561 -	wait(0);
   7.562 -}
   7.563 -
   7.564 -
   7.565 -
   7.566 -
   7.567 -
   7.568 -
   7.569 -
   7.570 -
   7.571 -
   7.572 -
   7.573 -
   7.574 -
   7.575 -
   7.576 -/* from tag.c */
   7.577 -
   7.578 -/* static */
   7.579 -
   7.580 -Client *
   7.581 -getnext(Client *c) {
   7.582 -	for(; c && !isvisible(c); c = c->next);
   7.583 -	return c;
   7.584 -}
   7.585 -
   7.586 -void
   7.587 -initrregs(void) {
   7.588 -	unsigned int i;
   7.589 -	regex_t *reg;
   7.590 -
   7.591 -	if(rreg)
   7.592 -		return;
   7.593 -	len = sizeof rule / sizeof rule[0];
   7.594 -	rreg = emallocz(len * sizeof(RReg));
   7.595 -	for(i = 0; i < len; i++) {
   7.596 -		if(rule[i].clpattern) {
   7.597 -			reg = emallocz(sizeof(regex_t));
   7.598 -			if(regcomp(reg, rule[i].clpattern, REG_EXTENDED))
   7.599 -				free(reg);
   7.600 -			else
   7.601 -				rreg[i].clregex = reg;
   7.602 -		}
   7.603 -	}
   7.604 -}
   7.605 -
   7.606 -void
   7.607 -settags(Client *c, Client *trans) {
   7.608 -	char prop[512];
   7.609 -	unsigned int i;
   7.610 -	regmatch_t tmp;
   7.611 -	Bool matched = trans != NULL;
   7.612 -	XClassHint ch = { 0 };
   7.613 -
   7.614 -	if(matched) {
   7.615 -		c->tag = trans->tag;
   7.616 -	} else {
   7.617 -		XGetClassHint(dpy, c->win, &ch);
   7.618 -		snprintf(prop, sizeof prop, "%s:%s:%s",
   7.619 -				ch.res_class ? ch.res_class : "",
   7.620 -				ch.res_name ? ch.res_name : "", c->name);
   7.621 -		for(i = 0; i < len; i++)
   7.622 -			if(rreg[i].clregex && !regexec(rreg[i].clregex, prop, 1, &tmp, 0)) {
   7.623 -				c->isfloat = rule[i].isfloat;
   7.624 -				if (rule[i].tag < 0) {
   7.625 -					c->tag = seltag;
   7.626 -				} else if (rule[i].tag == 0) {
   7.627 -					c->tag = True;
   7.628 -				} else {
   7.629 -					c->tag = False;
   7.630 -				}
   7.631 -				matched = True;
   7.632 -        break;  /* perform only the first rule matching */
   7.633 -			}
   7.634 -		if(ch.res_class)
   7.635 -			XFree(ch.res_class);
   7.636 -		if(ch.res_name)
   7.637 -			XFree(ch.res_name);
   7.638 -	}
   7.639 -	if(!matched) {
   7.640 -		c->tag = seltag;
   7.641 -	}
   7.642 -}
   7.643 -
   7.644 -void
   7.645 -toggletag() {
   7.646 -	if(!sel)
   7.647 -		return;
   7.648 -	sel->tag = !sel->tag;
   7.649 -	toggleview();
   7.650 -}
   7.651 -
   7.652 -
   7.653 -
   7.654 -
   7.655 -
   7.656 -
   7.657 -
   7.658 -
   7.659 -
   7.660 -
   7.661 -
   7.662 -
   7.663 -
   7.664 -
   7.665 -
   7.666 -
   7.667 -
   7.668 -/* from event.c */
   7.669 -/* static */
   7.670 -
   7.671 -KEYS
   7.672 -
   7.673 -
   7.674 -
   7.675 -static void
   7.676 -movemouse(Client *c) {
   7.677 -	int x1, y1, ocx, ocy, di;
   7.678 -	unsigned int dui;
   7.679 -	Window dummy;
   7.680 -	XEvent ev;
   7.681 -
   7.682 -	ocx = c->x;
   7.683 -	ocy = c->y;
   7.684 -	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
   7.685 -			None, cursor[CurMove], CurrentTime) != GrabSuccess)
   7.686 -		return;
   7.687 -	c->ismax = False;
   7.688 -	XQueryPointer(dpy, root, &dummy, &dummy, &x1, &y1, &di, &di, &dui);
   7.689 -	for(;;) {
   7.690 -		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev);
   7.691 -		switch (ev.type) {
   7.692 -		case ButtonRelease:
   7.693 -			resize(c, True);
   7.694 -			XUngrabPointer(dpy, CurrentTime);
   7.695 -			return;
   7.696 -		case ConfigureRequest:
   7.697 -		case Expose:
   7.698 -		case MapRequest:
   7.699 -			handler[ev.type](&ev);
   7.700 -			break;
   7.701 -		case MotionNotify:
   7.702 -			XSync(dpy, False);
   7.703 -			c->x = ocx + (ev.xmotion.x - x1);
   7.704 -			c->y = ocy + (ev.xmotion.y - y1);
   7.705 -			if(abs(wax + c->x) < SNAP)
   7.706 -				c->x = wax;
   7.707 -			else if(abs((wax + waw) - (c->x + c->w + 2 * c->border)) < SNAP)
   7.708 -				c->x = wax + waw - c->w - 2 * c->border;
   7.709 -			if(abs(way - c->y) < SNAP)
   7.710 -				c->y = way;
   7.711 -			else if(abs((way + wah) - (c->y + c->h + 2 * c->border)) < SNAP)
   7.712 -				c->y = way + wah - c->h - 2 * c->border;
   7.713 -			resize(c, False);
   7.714 -			break;
   7.715 -		}
   7.716 -	}
   7.717 -}
   7.718 -
   7.719 -static void
   7.720 -resizemouse(Client *c) {
   7.721 -	int ocx, ocy;
   7.722 -	int nw, nh;
   7.723 -	XEvent ev;
   7.724 -
   7.725 -	ocx = c->x;
   7.726 -	ocy = c->y;
   7.727 -	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
   7.728 -			None, cursor[CurResize], CurrentTime) != GrabSuccess)
   7.729 -		return;
   7.730 -	c->ismax = False;
   7.731 -	XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->border - 1, c->h + c->border - 1);
   7.732 -	for(;;) {
   7.733 -		XMaskEvent(dpy, MOUSEMASK | ExposureMask | SubstructureRedirectMask , &ev);
   7.734 -		switch(ev.type) {
   7.735 -		case ButtonRelease:
   7.736 -			resize(c, True);
   7.737 -			XUngrabPointer(dpy, CurrentTime);
   7.738 -			return;
   7.739 -		case ConfigureRequest:
   7.740 -		case Expose:
   7.741 -		case MapRequest:
   7.742 -			handler[ev.type](&ev);
   7.743 -			break;
   7.744 -		case MotionNotify:
   7.745 -			XSync(dpy, False);
   7.746 -			nw = ev.xmotion.x - ocx - 2 * c->border + 1;
   7.747 -			c->w = nw > 0 ? nw : 1;
   7.748 -			nh = ev.xmotion.y - ocy - 2 * c->border + 1;
   7.749 -			c->h = nh > 0 ? nh : 1;
   7.750 -			resize(c, True);
   7.751 -			break;
   7.752 -		}
   7.753 -	}
   7.754 -}
   7.755 -
   7.756 -static void
   7.757 -buttonpress(XEvent *e) {
   7.758 -	int x;
   7.759 -	int i;
   7.760 -	Client *c;
   7.761 -	XButtonPressedEvent *ev = &e->xbutton;
   7.762 -
   7.763 -	if(barwin == ev->window) {
   7.764 -		if(ev->button == Button1) {
   7.765 -			toggleview();
   7.766 -		}
   7.767 -		return;
   7.768 -	} else if((c = getclient(ev->window))) {
   7.769 -		focus(c);
   7.770 -		if(CLEANMASK(ev->state) != MODKEY)
   7.771 -			return;
   7.772 -		if(ev->button == Button1 && (arrange == dofloat || c->isfloat)) {
   7.773 -			restack();
   7.774 -			movemouse(c);
   7.775 -		} else if(ev->button == Button3 && (arrange == dofloat || c->isfloat) && !c->isfixed) {
   7.776 -			restack();
   7.777 -			resizemouse(c);
   7.778 -		}
   7.779 -	}
   7.780 -}
   7.781 -
   7.782 -static void
   7.783 -configurerequest(XEvent *e) {
   7.784 -	unsigned long newmask;
   7.785 -	Client *c;
   7.786 -	XConfigureRequestEvent *ev = &e->xconfigurerequest;
   7.787 -	XWindowChanges wc;
   7.788 -
   7.789 -	if((c = getclient(ev->window))) {
   7.790 -		c->ismax = False;
   7.791 -		if(ev->value_mask & CWX)
   7.792 -			c->x = ev->x;
   7.793 -		if(ev->value_mask & CWY)
   7.794 -			c->y = ev->y;
   7.795 -		if(ev->value_mask & CWWidth)
   7.796 -			c->w = ev->width;
   7.797 -		if(ev->value_mask & CWHeight)
   7.798 -			c->h = ev->height;
   7.799 -		if(ev->value_mask & CWBorderWidth)
   7.800 -			c->border = ev->border_width;
   7.801 -		wc.x = c->x;
   7.802 -		wc.y = c->y;
   7.803 -		wc.width = c->w;
   7.804 -		wc.height = c->h;
   7.805 -		newmask = ev->value_mask & (~(CWSibling | CWStackMode | CWBorderWidth));
   7.806 -		if(newmask)
   7.807 -			XConfigureWindow(dpy, c->win, newmask, &wc);
   7.808 -		else
   7.809 -			configure(c);
   7.810 -		XSync(dpy, False);
   7.811 -		if(c->isfloat) {
   7.812 -			resize(c, False);
   7.813 -			if(!isvisible(c))
   7.814 -				XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
   7.815 -		}
   7.816 -		else
   7.817 -			arrange();
   7.818 -	} else {
   7.819 -		wc.x = ev->x;
   7.820 -		wc.y = ev->y;
   7.821 -		wc.width = ev->width;
   7.822 -		wc.height = ev->height;
   7.823 -		wc.border_width = ev->border_width;
   7.824 -		wc.sibling = ev->above;
   7.825 -		wc.stack_mode = ev->detail;
   7.826 -		XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
   7.827 -		XSync(dpy, False);
   7.828 -	}
   7.829 -}
   7.830 -
   7.831 -static void
   7.832 -destroynotify(XEvent *e) {
   7.833 -	Client *c;
   7.834 -	XDestroyWindowEvent *ev = &e->xdestroywindow;
   7.835 -
   7.836 -	if((c = getclient(ev->window)))
   7.837 -		unmanage(c);
   7.838 -}
   7.839 -
   7.840 -static void
   7.841 -enternotify(XEvent *e) {
   7.842 -	Client *c;
   7.843 -	XCrossingEvent *ev = &e->xcrossing;
   7.844 -
   7.845 -	if(ev->mode != NotifyNormal || ev->detail == NotifyInferior)
   7.846 -		return;
   7.847 -	if((c = getclient(ev->window)) && isvisible(c))
   7.848 -		focus(c);
   7.849 -	else if(ev->window == root) {
   7.850 -		selscreen = True;
   7.851 -		for(c = stack; c && !isvisible(c); c = c->snext);
   7.852 -		focus(c);
   7.853 -	}
   7.854 -}
   7.855 -
   7.856 -static void
   7.857 -expose(XEvent *e) {
   7.858 -	XExposeEvent *ev = &e->xexpose;
   7.859 -
   7.860 -	if(ev->count == 0) {
   7.861 -		if(barwin == ev->window)
   7.862 -			drawstatus();
   7.863 -	}
   7.864 -}
   7.865 -
   7.866 -static void
   7.867 -keypress(XEvent *e) {
   7.868 -	static unsigned int len = sizeof key / sizeof key[0];
   7.869 -	unsigned int i;
   7.870 -	KeySym keysym;
   7.871 -	XKeyEvent *ev = &e->xkey;
   7.872 -
   7.873 -	keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
   7.874 -	for(i = 0; i < len; i++) {
   7.875 -		if(keysym == key[i].keysym && CLEANMASK(key[i].mod) == CLEANMASK(ev->state)) {
   7.876 -			if(key[i].func)
   7.877 -				key[i].func(key[i].cmd);
   7.878 -		}
   7.879 -	}
   7.880 -}
   7.881 -
   7.882 -static void
   7.883 -leavenotify(XEvent *e) {
   7.884 -	XCrossingEvent *ev = &e->xcrossing;
   7.885 -
   7.886 -	if((ev->window == root) && !ev->same_screen) {
   7.887 -		selscreen = False;
   7.888 -		focus(NULL);
   7.889 -	}
   7.890 -}
   7.891 -
   7.892 -static void
   7.893 -mappingnotify(XEvent *e) {
   7.894 -	XMappingEvent *ev = &e->xmapping;
   7.895 -
   7.896 -	XRefreshKeyboardMapping(ev);
   7.897 -	if(ev->request == MappingKeyboard)
   7.898 -		grabkeys();
   7.899 -}
   7.900 -
   7.901 -static void
   7.902 -maprequest(XEvent *e) {
   7.903 -	static XWindowAttributes wa;
   7.904 -	XMapRequestEvent *ev = &e->xmaprequest;
   7.905 -
   7.906 -	if(!XGetWindowAttributes(dpy, ev->window, &wa))
   7.907 -		return;
   7.908 -	if(wa.override_redirect) {
   7.909 -		XSelectInput(dpy, ev->window,
   7.910 -				(StructureNotifyMask | PropertyChangeMask));
   7.911 -		return;
   7.912 -	}
   7.913 -	if(!getclient(ev->window))
   7.914 -		manage(ev->window, &wa);
   7.915 -}
   7.916 -
   7.917 -static void
   7.918 -propertynotify(XEvent *e) {
   7.919 -	Client *c;
   7.920 -	Window trans;
   7.921 -	XPropertyEvent *ev = &e->xproperty;
   7.922 -
   7.923 -	if(ev->state == PropertyDelete)
   7.924 -		return; /* ignore */
   7.925 -	if((c = getclient(ev->window))) {
   7.926 -		switch (ev->atom) {
   7.927 -			default: break;
   7.928 -			case XA_WM_TRANSIENT_FOR:
   7.929 -				XGetTransientForHint(dpy, c->win, &trans);
   7.930 -				if(!c->isfloat && (c->isfloat = (trans != 0)))
   7.931 -					arrange();
   7.932 -				break;
   7.933 -			case XA_WM_NORMAL_HINTS:
   7.934 -				updatesizehints(c);
   7.935 -				break;
   7.936 -		}
   7.937 -		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
   7.938 -			updatetitle(c);
   7.939 -			if(c == sel)
   7.940 -				drawstatus();
   7.941 -		}
   7.942 -	}
   7.943 -}
   7.944 -
   7.945 -static void
   7.946 -unmapnotify(XEvent *e) {
   7.947 -	Client *c;
   7.948 -	XUnmapEvent *ev = &e->xunmap;
   7.949 -
   7.950 -	if((c = getclient(ev->window)))
   7.951 -		unmanage(c);
   7.952 -}
   7.953 -
   7.954 -
   7.955 -
   7.956 -void (*handler[LASTEvent]) (XEvent *) = {
   7.957 -	[ButtonPress] = buttonpress,
   7.958 -	[ConfigureRequest] = configurerequest,
   7.959 -	[DestroyNotify] = destroynotify,
   7.960 -	[EnterNotify] = enternotify,
   7.961 -	[LeaveNotify] = leavenotify,
   7.962 -	[Expose] = expose,
   7.963 -	[KeyPress] = keypress,
   7.964 -	[MappingNotify] = mappingnotify,
   7.965 -	[MapRequest] = maprequest,
   7.966 -	[PropertyNotify] = propertynotify,
   7.967 -	[UnmapNotify] = unmapnotify
   7.968 -};
   7.969 -
   7.970 -void
   7.971 -grabkeys(void) {
   7.972 -	static unsigned int len = sizeof key / sizeof key[0];
   7.973 -	unsigned int i;
   7.974 -	KeyCode code;
   7.975 -
   7.976 -	XUngrabKey(dpy, AnyKey, AnyModifier, root);
   7.977 -	for(i = 0; i < len; i++) {
   7.978 -		code = XKeysymToKeycode(dpy, key[i].keysym);
   7.979 -		XGrabKey(dpy, code, key[i].mod, root, True,
   7.980 -				GrabModeAsync, GrabModeAsync);
   7.981 -		XGrabKey(dpy, code, key[i].mod | LockMask, root, True,
   7.982 -				GrabModeAsync, GrabModeAsync);
   7.983 -		XGrabKey(dpy, code, key[i].mod | numlockmask, root, True,
   7.984 -				GrabModeAsync, GrabModeAsync);
   7.985 -		XGrabKey(dpy, code, key[i].mod | numlockmask | LockMask, root, True,
   7.986 -				GrabModeAsync, GrabModeAsync);
   7.987 -	}
   7.988 -}
   7.989 -
   7.990 -void
   7.991 -procevent(void) {
   7.992 -	XEvent ev;
   7.993 -
   7.994 -	while(XPending(dpy)) {
   7.995 -		XNextEvent(dpy, &ev);
   7.996 -		if(handler[ev.type])
   7.997 -			(handler[ev.type])(&ev); /* call handler */
   7.998 -	}
   7.999 -}
  7.1000 -
  7.1001 -
  7.1002 -
  7.1003 -
  7.1004 -
  7.1005 -
  7.1006 -
  7.1007 -
  7.1008 -
  7.1009 -
  7.1010 -
  7.1011 -
  7.1012 -
  7.1013 -
  7.1014 -
  7.1015 -/* from draw.c */
  7.1016 -/* static */
  7.1017 -
  7.1018 -static unsigned int
  7.1019 -textnw(const char *text, unsigned int len) {
  7.1020 -	XRectangle r;
  7.1021 -
  7.1022 -	if(dc.font.set) {
  7.1023 -		XmbTextExtents(dc.font.set, text, len, NULL, &r);
  7.1024 -		return r.width;
  7.1025 -	}
  7.1026 -	return XTextWidth(dc.font.xfont, text, len);
  7.1027 -}
  7.1028 -
  7.1029 -static void
  7.1030 -drawtext(const char *text, unsigned long col[ColLast]) {
  7.1031 -	int x, y, w, h;
  7.1032 -	static char buf[256];
  7.1033 -	unsigned int len, olen;
  7.1034 -	XGCValues gcv;
  7.1035 -	XRectangle r = { dc.x, dc.y, dc.w, dc.h };
  7.1036 -
  7.1037 -	XSetForeground(dpy, dc.gc, col[ColBG]);
  7.1038 -	XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
  7.1039 -	if(!text)
  7.1040 -		return;
  7.1041 -	w = 0;
  7.1042 -	olen = len = strlen(text);
  7.1043 -	if(len >= sizeof buf)
  7.1044 -		len = sizeof buf - 1;
  7.1045 -	memcpy(buf, text, len);
  7.1046 -	buf[len] = 0;
  7.1047 -	h = dc.font.ascent + dc.font.descent;
  7.1048 -	y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
  7.1049 -	x = dc.x + (h / 2);
  7.1050 -	/* shorten text if necessary */
  7.1051 -	while(len && (w = textnw(buf, len)) > dc.w - h)
  7.1052 -		buf[--len] = 0;
  7.1053 -	if(len < olen) {
  7.1054 -		if(len > 1)
  7.1055 -			buf[len - 1] = '.';
  7.1056 -		if(len > 2)
  7.1057 -			buf[len - 2] = '.';
  7.1058 -		if(len > 3)
  7.1059 -			buf[len - 3] = '.';
  7.1060 -	}
  7.1061 -	if(w > dc.w)
  7.1062 -		return; /* too long */
  7.1063 -	gcv.foreground = col[ColFG];
  7.1064 -	if(dc.font.set) {
  7.1065 -		XChangeGC(dpy, dc.gc, GCForeground, &gcv);
  7.1066 -		XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
  7.1067 -	} else {
  7.1068 -		gcv.font = dc.font.xfont->fid;
  7.1069 -		XChangeGC(dpy, dc.gc, GCForeground | GCFont, &gcv);
  7.1070 -		XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
  7.1071 -	}
  7.1072 -}
  7.1073 -
  7.1074 -
  7.1075 -
  7.1076 -void
  7.1077 -drawstatus(void) {
  7.1078 -	int x;
  7.1079 -	unsigned int i;
  7.1080 -
  7.1081 -	dc.x = dc.y = 0;
  7.1082 -	for(i = 0; i < ntags; i++) {
  7.1083 -		dc.w = textw(tags[i]);
  7.1084 -		drawtext(tags[i], ( ((i == 0 && seltag) || (i == 1 && !seltag)) ? dc.sel : dc.norm));
  7.1085 -		dc.x += dc.w + 1;
  7.1086 -	}
  7.1087 -	dc.w = bmw;
  7.1088 -	drawtext("", dc.norm);
  7.1089 -	x = dc.x + dc.w;
  7.1090 -	dc.w = textw(stext);
  7.1091 -	dc.x = sw - dc.w;
  7.1092 -	if(dc.x < x) {
  7.1093 -		dc.x = x;
  7.1094 -		dc.w = sw - x;
  7.1095 -	}
  7.1096 -	drawtext(stext, dc.norm);
  7.1097 -	if((dc.w = dc.x - x) > bh) {
  7.1098 -		dc.x = x;
  7.1099 -		drawtext(sel ? sel->name : NULL, dc.norm);
  7.1100 -	}
  7.1101 -	XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, sw, bh, 0, 0);
  7.1102 -	XSync(dpy, False);
  7.1103 -}
  7.1104 -
  7.1105 -unsigned long
  7.1106 -getcolor(const char *colstr) {
  7.1107 -	Colormap cmap = DefaultColormap(dpy, screen);
  7.1108 -	XColor color;
  7.1109 -
  7.1110 -	if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
  7.1111 -		eprint("error, cannot allocate color '%s'\n", colstr);
  7.1112 -	return color.pixel;
  7.1113 -}
  7.1114 -
  7.1115 -void
  7.1116 -setfont(const char *fontstr) {
  7.1117 -	char *def, **missing;
  7.1118 -	int i, n;
  7.1119 -
  7.1120 -	missing = NULL;
  7.1121 -	if(dc.font.set)
  7.1122 -		XFreeFontSet(dpy, dc.font.set);
  7.1123 -	dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
  7.1124 -	if(missing) {
  7.1125 -		while(n--)
  7.1126 -			fprintf(stderr, "missing fontset: %s\n", missing[n]);
  7.1127 -		XFreeStringList(missing);
  7.1128 -	}
  7.1129 -	if(dc.font.set) {
  7.1130 -		XFontSetExtents *font_extents;
  7.1131 -		XFontStruct **xfonts;
  7.1132 -		char **font_names;
  7.1133 -		dc.font.ascent = dc.font.descent = 0;
  7.1134 -		font_extents = XExtentsOfFontSet(dc.font.set);
  7.1135 -		n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
  7.1136 -		for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
  7.1137 -			if(dc.font.ascent < (*xfonts)->ascent)
  7.1138 -				dc.font.ascent = (*xfonts)->ascent;
  7.1139 -			if(dc.font.descent < (*xfonts)->descent)
  7.1140 -				dc.font.descent = (*xfonts)->descent;
  7.1141 -			xfonts++;
  7.1142 -		}
  7.1143 -	} else {
  7.1144 -		if(dc.font.xfont)
  7.1145 -			XFreeFont(dpy, dc.font.xfont);
  7.1146 -		dc.font.xfont = NULL;
  7.1147 -		if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
  7.1148 -			eprint("error, cannot load font: '%s'\n", fontstr);
  7.1149 -		dc.font.ascent = dc.font.xfont->ascent;
  7.1150 -		dc.font.descent = dc.font.xfont->descent;
  7.1151 -	}
  7.1152 -	dc.font.height = dc.font.ascent + dc.font.descent;
  7.1153 -}
  7.1154 -
  7.1155 -unsigned int
  7.1156 -textw(const char *text) {
  7.1157 -	return textnw(text, strlen(text)) + dc.font.height;
  7.1158 -}
  7.1159 -
  7.1160 -
  7.1161 -
  7.1162 -
  7.1163 -
  7.1164 -
  7.1165 -
  7.1166 -
  7.1167 -
  7.1168 -
  7.1169 -
  7.1170 -/* from client.c */
  7.1171 -/* static */
  7.1172 -
  7.1173 -static void
  7.1174 -detachstack(Client *c) {
  7.1175 -	Client **tc;
  7.1176 -	for(tc=&stack; *tc && *tc != c; tc=&(*tc)->snext);
  7.1177 -	*tc = c->snext;
  7.1178 -}
  7.1179 -
  7.1180 -static void
  7.1181 -grabbuttons(Client *c, Bool focused) {
  7.1182 -	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  7.1183 -
  7.1184 -	if(focused) {
  7.1185 -		XGrabButton(dpy, Button1, MODKEY, c->win, False, BUTTONMASK,
  7.1186 -				GrabModeAsync, GrabModeSync, None, None);
  7.1187 -		XGrabButton(dpy, Button1, MODKEY | LockMask, c->win, False, BUTTONMASK,
  7.1188 -				GrabModeAsync, GrabModeSync, None, None);
  7.1189 -		XGrabButton(dpy, Button1, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  7.1190 -				GrabModeAsync, GrabModeSync, None, None);
  7.1191 -		XGrabButton(dpy, Button1, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  7.1192 -				GrabModeAsync, GrabModeSync, None, None);
  7.1193 -
  7.1194 -		XGrabButton(dpy, Button2, MODKEY, c->win, False, BUTTONMASK,
  7.1195 -				GrabModeAsync, GrabModeSync, None, None);
  7.1196 -		XGrabButton(dpy, Button2, MODKEY | LockMask, c->win, False, BUTTONMASK,
  7.1197 -				GrabModeAsync, GrabModeSync, None, None);
  7.1198 -		XGrabButton(dpy, Button2, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  7.1199 -				GrabModeAsync, GrabModeSync, None, None);
  7.1200 -		XGrabButton(dpy, Button2, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  7.1201 -				GrabModeAsync, GrabModeSync, None, None);
  7.1202 -
  7.1203 -		XGrabButton(dpy, Button3, MODKEY, c->win, False, BUTTONMASK,
  7.1204 -				GrabModeAsync, GrabModeSync, None, None);
  7.1205 -		XGrabButton(dpy, Button3, MODKEY | LockMask, c->win, False, BUTTONMASK,
  7.1206 -				GrabModeAsync, GrabModeSync, None, None);
  7.1207 -		XGrabButton(dpy, Button3, MODKEY | numlockmask, c->win, False, BUTTONMASK,
  7.1208 -				GrabModeAsync, GrabModeSync, None, None);
  7.1209 -		XGrabButton(dpy, Button3, MODKEY | numlockmask | LockMask, c->win, False, BUTTONMASK,
  7.1210 -				GrabModeAsync, GrabModeSync, None, None);
  7.1211 -	} else {
  7.1212 -		XGrabButton(dpy, AnyButton, AnyModifier, c->win, False, BUTTONMASK,
  7.1213 -				GrabModeAsync, GrabModeSync, None, None);
  7.1214 -	}
  7.1215 -}
  7.1216 -
  7.1217 -static void
  7.1218 -setclientstate(Client *c, long state) {
  7.1219 -	long data[] = {state, None};
  7.1220 -	XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
  7.1221 -			PropModeReplace, (unsigned char *)data, 2);
  7.1222 -}
  7.1223 -
  7.1224 -static int
  7.1225 -xerrordummy(Display *dsply, XErrorEvent *ee) {
  7.1226 -	return 0;
  7.1227 -}
  7.1228 -
  7.1229 -
  7.1230 -
  7.1231 -void
  7.1232 -configure(Client *c) {
  7.1233 -	XEvent synev;
  7.1234 -
  7.1235 -	synev.type = ConfigureNotify;
  7.1236 -	synev.xconfigure.display = dpy;
  7.1237 -	synev.xconfigure.event = c->win;
  7.1238 -	synev.xconfigure.window = c->win;
  7.1239 -	synev.xconfigure.x = c->x;
  7.1240 -	synev.xconfigure.y = c->y;
  7.1241 -	synev.xconfigure.width = c->w;
  7.1242 -	synev.xconfigure.height = c->h;
  7.1243 -	synev.xconfigure.border_width = c->border;
  7.1244 -	synev.xconfigure.above = None;
  7.1245 -	XSendEvent(dpy, c->win, True, NoEventMask, &synev);
  7.1246 -}
  7.1247 -
  7.1248 -void
  7.1249 -focus(Client *c) {
  7.1250 -	if(c && !isvisible(c))
  7.1251 -		return;
  7.1252 -	if(sel && sel != c) {
  7.1253 -		grabbuttons(sel, False);
  7.1254 -		XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
  7.1255 -	}
  7.1256 -	if(c) {
  7.1257 -		detachstack(c);
  7.1258 -		c->snext = stack;
  7.1259 -		stack = c;
  7.1260 -		grabbuttons(c, True);
  7.1261 -	}
  7.1262 -	sel = c;
  7.1263 -	drawstatus();
  7.1264 -	if(!selscreen)
  7.1265 -		return;
  7.1266 -	if(c) {
  7.1267 -		XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
  7.1268 -		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
  7.1269 -	} else {
  7.1270 -		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
  7.1271 -	}
  7.1272 -}
  7.1273 -
  7.1274 -Client *
  7.1275 -getclient(Window w) {
  7.1276 -	Client *c;
  7.1277 -
  7.1278 -	for(c = clients; c; c = c->next) {
  7.1279 -		if(c->win == w) {
  7.1280 -			return c;
  7.1281 -		}
  7.1282 -	}
  7.1283 -	return NULL;
  7.1284 -}
  7.1285 -
  7.1286 -Bool
  7.1287 -isprotodel(Client *c) {
  7.1288 -	int i, n;
  7.1289 -	Atom *protocols;
  7.1290 -	Bool ret = False;
  7.1291 -
  7.1292 -	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
  7.1293 -		for(i = 0; !ret && i < n; i++)
  7.1294 -			if(protocols[i] == wmatom[WMDelete])
  7.1295 -				ret = True;
  7.1296 -		XFree(protocols);
  7.1297 -	}
  7.1298 -	return ret;
  7.1299 -}
  7.1300 -
  7.1301 -void
  7.1302 -killclient() {
  7.1303 -	if(!sel)
  7.1304 -		return;
  7.1305 -	if(isprotodel(sel))
  7.1306 -		sendevent(sel->win, wmatom[WMProtocols], wmatom[WMDelete]);
  7.1307 -	else
  7.1308 -		XKillClient(dpy, sel->win);
  7.1309 -}
  7.1310 -
  7.1311 -void
  7.1312 -manage(Window w, XWindowAttributes *wa) {
  7.1313 -	Client *c;
  7.1314 -	Window trans;
  7.1315 -
  7.1316 -	c = emallocz(sizeof(Client));
  7.1317 -	c->tag = True;
  7.1318 -	c->win = w;
  7.1319 -	c->x = wa->x;
  7.1320 -	c->y = wa->y;
  7.1321 -	c->w = wa->width;
  7.1322 -	c->h = wa->height;
  7.1323 -	if(c->w == sw && c->h == sh) {
  7.1324 -		c->border = 0;
  7.1325 -		c->x = sx;
  7.1326 -		c->y = sy;
  7.1327 -	} else {
  7.1328 -		c->border = BORDERPX;
  7.1329 -		if(c->x + c->w + 2 * c->border > wax + waw)
  7.1330 -			c->x = wax + waw - c->w - 2 * c->border;
  7.1331 -		if(c->y + c->h + 2 * c->border > way + wah)
  7.1332 -			c->y = way + wah - c->h - 2 * c->border;
  7.1333 -		if(c->x < wax)
  7.1334 -			c->x = wax;
  7.1335 -		if(c->y < way)
  7.1336 -			c->y = way;
  7.1337 -	}
  7.1338 -	updatesizehints(c);
  7.1339 -	XSelectInput(dpy, c->win,
  7.1340 -		StructureNotifyMask | PropertyChangeMask | EnterWindowMask);
  7.1341 -	XGetTransientForHint(dpy, c->win, &trans);
  7.1342 -	grabbuttons(c, False);
  7.1343 -	XSetWindowBorder(dpy, c->win, dc.norm[ColBorder]);
  7.1344 -	updatetitle(c);
  7.1345 -	settags(c, getclient(trans));
  7.1346 -	if(!c->isfloat)
  7.1347 -		c->isfloat = trans || c->isfixed;
  7.1348 -	if(clients)
  7.1349 -		clients->prev = c;
  7.1350 -	c->next = clients;
  7.1351 -	c->snext = stack;
  7.1352 -	stack = clients = c;
  7.1353 -	XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
  7.1354 -	XMapWindow(dpy, c->win);
  7.1355 -	setclientstate(c, NormalState);
  7.1356 -	if(isvisible(c))
  7.1357 -		focus(c);
  7.1358 -	arrange();
  7.1359 -}
  7.1360 -
  7.1361 -void
  7.1362 -resize(Client *c, Bool sizehints) {
  7.1363 -	float actual, dx, dy, max, min;
  7.1364 -	XWindowChanges wc;
  7.1365 -
  7.1366 -	if(c->w <= 0 || c->h <= 0)
  7.1367 -		return;
  7.1368 -	if(sizehints) {
  7.1369 -		if(c->minw && c->w < c->minw)
  7.1370 -			c->w = c->minw;
  7.1371 -		if(c->minh && c->h < c->minh)
  7.1372 -			c->h = c->minh;
  7.1373 -		if(c->maxw && c->w > c->maxw)
  7.1374 -			c->w = c->maxw;
  7.1375 -		if(c->maxh && c->h > c->maxh)
  7.1376 -			c->h = c->maxh;
  7.1377 -		/* inspired by algorithm from fluxbox */
  7.1378 -		if(c->minay > 0 && c->maxay && (c->h - c->baseh) > 0) {
  7.1379 -			dx = (float)(c->w - c->basew);
  7.1380 -			dy = (float)(c->h - c->baseh);
  7.1381 -			min = (float)(c->minax) / (float)(c->minay);
  7.1382 -			max = (float)(c->maxax) / (float)(c->maxay);
  7.1383 -			actual = dx / dy;
  7.1384 -			if(max > 0 && min > 0 && actual > 0) {
  7.1385 -				if(actual < min) {
  7.1386 -					dy = (dx * min + dy) / (min * min + 1);
  7.1387 -					dx = dy * min;
  7.1388 -					c->w = (int)dx + c->basew;
  7.1389 -					c->h = (int)dy + c->baseh;
  7.1390 -				}
  7.1391 -				else if(actual > max) {
  7.1392 -					dy = (dx * min + dy) / (max * max + 1);
  7.1393 -					dx = dy * min;
  7.1394 -					c->w = (int)dx + c->basew;
  7.1395 -					c->h = (int)dy + c->baseh;
  7.1396 -				}
  7.1397 -			}
  7.1398 -		}
  7.1399 -		if(c->incw)
  7.1400 -			c->w -= (c->w - c->basew) % c->incw;
  7.1401 -		if(c->inch)
  7.1402 -			c->h -= (c->h - c->baseh) % c->inch;
  7.1403 -	}
  7.1404 -	if(c->w == sw && c->h == sh)
  7.1405 -		c->border = 0;
  7.1406 -	else
  7.1407 -		c->border = BORDERPX;
  7.1408 -	/* offscreen appearance fixes */
  7.1409 -	if(c->x > sw)
  7.1410 -		c->x = sw - c->w - 2 * c->border;
  7.1411 -	if(c->y > sh)
  7.1412 -		c->y = sh - c->h - 2 * c->border;
  7.1413 -	if(c->x + c->w + 2 * c->border < sx)
  7.1414 -		c->x = sx;
  7.1415 -	if(c->y + c->h + 2 * c->border < sy)
  7.1416 -		c->y = sy;
  7.1417 -	wc.x = c->x;
  7.1418 -	wc.y = c->y;
  7.1419 -	wc.width = c->w;
  7.1420 -	wc.height = c->h;
  7.1421 -	wc.border_width = c->border;
  7.1422 -	XConfigureWindow(dpy, c->win, CWX | CWY | CWWidth | CWHeight | CWBorderWidth, &wc);
  7.1423 -	configure(c);
  7.1424 -	XSync(dpy, False);
  7.1425 -}
  7.1426 -
  7.1427 -void
  7.1428 -updatesizehints(Client *c) {
  7.1429 -	long msize;
  7.1430 -	XSizeHints size;
  7.1431 -
  7.1432 -	if(!XGetWMNormalHints(dpy, c->win, &size, &msize) || !size.flags)
  7.1433 -		size.flags = PSize;
  7.1434 -	c->flags = size.flags;
  7.1435 -	if(c->flags & PBaseSize) {
  7.1436 -		c->basew = size.base_width;
  7.1437 -		c->baseh = size.base_height;
  7.1438 -	} else {
  7.1439 -		c->basew = c->baseh = 0;
  7.1440 -	}
  7.1441 -	if(c->flags & PResizeInc) {
  7.1442 -		c->incw = size.width_inc;
  7.1443 -		c->inch = size.height_inc;
  7.1444 -	} else {
  7.1445 -		c->incw = c->inch = 0;
  7.1446 -	}
  7.1447 -	if(c->flags & PMaxSize) {
  7.1448 -		c->maxw = size.max_width;
  7.1449 -		c->maxh = size.max_height;
  7.1450 -	} else {
  7.1451 -		c->maxw = c->maxh = 0;
  7.1452 -	}
  7.1453 -	if(c->flags & PMinSize) {
  7.1454 -		c->minw = size.min_width;
  7.1455 -		c->minh = size.min_height;
  7.1456 -	} else {
  7.1457 -		c->minw = c->minh = 0;
  7.1458 -	}
  7.1459 -	if(c->flags & PAspect) {
  7.1460 -		c->minax = size.min_aspect.x;
  7.1461 -		c->minay = size.min_aspect.y;
  7.1462 -		c->maxax = size.max_aspect.x;
  7.1463 -		c->maxay = size.max_aspect.y;
  7.1464 -	} else {
  7.1465 -		c->minax = c->minay = c->maxax = c->maxay = 0;
  7.1466 -	}
  7.1467 -	c->isfixed = (c->maxw && c->minw && c->maxh && c->minh &&
  7.1468 -				c->maxw == c->minw && c->maxh == c->minh);
  7.1469 -}
  7.1470 -
  7.1471 -void
  7.1472 -updatetitle(Client *c) {
  7.1473 -	char **list = NULL;
  7.1474 -	int n;
  7.1475 -	XTextProperty name;
  7.1476 -
  7.1477 -	name.nitems = 0;
  7.1478 -	c->name[0] = 0;
  7.1479 -	XGetTextProperty(dpy, c->win, &name, netatom[NetWMName]);
  7.1480 -	if(!name.nitems)
  7.1481 -		XGetWMName(dpy, c->win, &name);
  7.1482 -	if(!name.nitems)
  7.1483 -		return;
  7.1484 -	if(name.encoding == XA_STRING)
  7.1485 -		strncpy(c->name, (char *)name.value, sizeof c->name);
  7.1486 -	else {
  7.1487 -		if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success && n > 0 && *list) {
  7.1488 -			strncpy(c->name, *list, sizeof c->name);
  7.1489 -			XFreeStringList(list);
  7.1490 -		}
  7.1491 -	}
  7.1492 -	XFree(name.value);
  7.1493 -}
  7.1494 -
  7.1495 -void
  7.1496 -unmanage(Client *c) {
  7.1497 -	Client *nc;
  7.1498 -
  7.1499 -	/* The server grab construct avoids race conditions. */
  7.1500 -	XGrabServer(dpy);
  7.1501 -	XSetErrorHandler(xerrordummy);
  7.1502 -	detach(c);
  7.1503 -	detachstack(c);
  7.1504 -	if(sel == c) {
  7.1505 -		for(nc = stack; nc && !isvisible(nc); nc = nc->snext);
  7.1506 -		focus(nc);
  7.1507 -	}
  7.1508 -	XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
  7.1509 -	setclientstate(c, WithdrawnState);
  7.1510 -	free(c);
  7.1511 -	XSync(dpy, False);
  7.1512 -	XSetErrorHandler(xerror);
  7.1513 -	XUngrabServer(dpy);
  7.1514 -	arrange();
  7.1515 -}
  7.1516 -
  7.1517 -
  7.1518 -
  7.1519 -
  7.1520 -
  7.1521 -
  7.1522 -
  7.1523 -
  7.1524 -
  7.1525 -
  7.1526 -
  7.1527 -
  7.1528 -
  7.1529 -
  7.1530 -
  7.1531 -
  7.1532 -
  7.1533 -
  7.1534 -
  7.1535 -/* static */
  7.1536 -
  7.1537 -
  7.1538 -static void
  7.1539 -cleanup(void) {
  7.1540 -	close(STDIN_FILENO);
  7.1541 -	while(stack) {
  7.1542 -		resize(stack, True);
  7.1543 -		unmanage(stack);
  7.1544 -	}
  7.1545 -	if(dc.font.set)
  7.1546 -		XFreeFontSet(dpy, dc.font.set);
  7.1547 -	else
  7.1548 -		XFreeFont(dpy, dc.font.xfont);
  7.1549 -	XUngrabKey(dpy, AnyKey, AnyModifier, root);
  7.1550 -	XFreePixmap(dpy, dc.drawable);
  7.1551 -	XFreeGC(dpy, dc.gc);
  7.1552 -	XDestroyWindow(dpy, barwin);
  7.1553 -	XFreeCursor(dpy, cursor[CurNormal]);
  7.1554 -	XFreeCursor(dpy, cursor[CurResize]);
  7.1555 -	XFreeCursor(dpy, cursor[CurMove]);
  7.1556 -	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
  7.1557 -	XSync(dpy, False);
  7.1558 -}
  7.1559 -
  7.1560 -static void
  7.1561 -scan(void) {
  7.1562 -	unsigned int i, num;
  7.1563 -	Window *wins, d1, d2;
  7.1564 -	XWindowAttributes wa;
  7.1565 -
  7.1566 -	wins = NULL;
  7.1567 -	if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
  7.1568 -		for(i = 0; i < num; i++) {
  7.1569 -			if(!XGetWindowAttributes(dpy, wins[i], &wa))
  7.1570 -				continue;
  7.1571 -			if(wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
  7.1572 -				continue;
  7.1573 -			if(wa.map_state == IsViewable)
  7.1574 -				manage(wins[i], &wa);
  7.1575 -		}
  7.1576 -	}
  7.1577 -	if(wins)
  7.1578 -		XFree(wins);
  7.1579 -}
  7.1580 -
  7.1581 -static void
  7.1582 -setup(void) {
  7.1583 -	int i, j;
  7.1584 -	unsigned int mask;
  7.1585 -	Window w;
  7.1586 -	XModifierKeymap *modmap;
  7.1587 -	XSetWindowAttributes wa;
  7.1588 -
  7.1589 -	/* init atoms */
  7.1590 -	wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
  7.1591 -	wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  7.1592 -	wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
  7.1593 -	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
  7.1594 -	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
  7.1595 -	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
  7.1596 -			PropModeReplace, (unsigned char *) netatom, NetLast);
  7.1597 -	/* init cursors */
  7.1598 -	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
  7.1599 -	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
  7.1600 -	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
  7.1601 -	/* init modifier map */
  7.1602 -	numlockmask = 0;
  7.1603 -	modmap = XGetModifierMapping(dpy);
  7.1604 -	for (i = 0; i < 8; i++) {
  7.1605 -		for (j = 0; j < modmap->max_keypermod; j++) {
  7.1606 -			if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
  7.1607 -				numlockmask = (1 << i);
  7.1608 -		}
  7.1609 -	}
  7.1610 -	XFreeModifiermap(modmap);
  7.1611 -	/* select for events */
  7.1612 -	wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
  7.1613 -		| EnterWindowMask | LeaveWindowMask;
  7.1614 -	wa.cursor = cursor[CurNormal];
  7.1615 -	XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
  7.1616 -	grabkeys();
  7.1617 -	initrregs();
  7.1618 -	ntags = 2;
  7.1619 -	seltag = True;
  7.1620 -	/* style */
  7.1621 -	dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
  7.1622 -	dc.norm[ColBG] = getcolor(NORMBGCOLOR);
  7.1623 -	dc.norm[ColFG] = getcolor(NORMFGCOLOR);
  7.1624 -	dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
  7.1625 -	dc.sel[ColBG] = getcolor(SELBGCOLOR);
  7.1626 -	dc.sel[ColFG] = getcolor(SELFGCOLOR);
  7.1627 -	setfont(FONT);
  7.1628 -	/* geometry */
  7.1629 -	sx = sy = 0;
  7.1630 -	sw = DisplayWidth(dpy, screen);
  7.1631 -	sh = DisplayHeight(dpy, screen);
  7.1632 -	nmaster = NMASTER;
  7.1633 -	bmw = 1;
  7.1634 -	/* bar */
  7.1635 -	dc.h = bh = dc.font.height + 2;
  7.1636 -	wa.override_redirect = 1;
  7.1637 -	wa.background_pixmap = ParentRelative;
  7.1638 -	wa.event_mask = ButtonPressMask | ExposureMask;
  7.1639 -	barwin = XCreateWindow(dpy, root, sx, sy, sw, bh, 0,
  7.1640 -			DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
  7.1641 -			CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
  7.1642 -	XDefineCursor(dpy, barwin, cursor[CurNormal]);
  7.1643 -	XMapRaised(dpy, barwin);
  7.1644 -	strcpy(stext, "dwm-"VERSION);
  7.1645 -	/* windowarea */
  7.1646 -	wax = sx;
  7.1647 -	way = sy + bh;
  7.1648 -	wah = sh - bh;
  7.1649 -	waw = sw;
  7.1650 -	/* pixmap for everything */
  7.1651 -	dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
  7.1652 -	dc.gc = XCreateGC(dpy, root, 0, 0);
  7.1653 -	XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
  7.1654 -	/* multihead support */
  7.1655 -	selscreen = XQueryPointer(dpy, root, &w, &w, &i, &i, &i, &i, &mask);
  7.1656 -}
  7.1657 -
  7.1658 -/*
  7.1659 - * Startup Error handler to check if another window manager
  7.1660 - * is already running.
  7.1661 - */
  7.1662 -static int
  7.1663 -xerrorstart(Display *dsply, XErrorEvent *ee) {
  7.1664 -	otherwm = True;
  7.1665 -	return -1;
  7.1666 -}
  7.1667 -
  7.1668 -
  7.1669 -
  7.1670 -void
  7.1671 -sendevent(Window w, Atom a, long value) {
  7.1672 -	XEvent e;
  7.1673 -
  7.1674 -	e.type = ClientMessage;
  7.1675 -	e.xclient.window = w;
  7.1676 -	e.xclient.message_type = a;
  7.1677 -	e.xclient.format = 32;
  7.1678 -	e.xclient.data.l[0] = value;
  7.1679 -	e.xclient.data.l[1] = CurrentTime;
  7.1680 -	XSendEvent(dpy, w, False, NoEventMask, &e);
  7.1681 -	XSync(dpy, False);
  7.1682 -}
  7.1683 -
  7.1684 -void
  7.1685 -quit() {
  7.1686 -	readin = running = False;
  7.1687 -}
  7.1688 -
  7.1689 -/* There's no way to check accesses to destroyed windows, thus those cases are
  7.1690 - * ignored (especially on UnmapNotify's).  Other types of errors call Xlibs
  7.1691 - * default error handler, which may call exit.
  7.1692 - */
  7.1693 -int
  7.1694 -xerror(Display *dpy, XErrorEvent *ee) {
  7.1695 -	if(ee->error_code == BadWindow
  7.1696 -	|| (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
  7.1697 -	|| (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
  7.1698 -	|| (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
  7.1699 -	|| (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
  7.1700 -	|| (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
  7.1701 -	|| (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
  7.1702 -	|| (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
  7.1703 -		return 0;
  7.1704 -	fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
  7.1705 -		ee->request_code, ee->error_code);
  7.1706 -	return xerrorxlib(dpy, ee); /* may call exit */
  7.1707 -}
  7.1708 -
  7.1709 -int
  7.1710 -main(int argc, char *argv[]) {
  7.1711 -	char *p;
  7.1712 -	int r, xfd;
  7.1713 -	fd_set rd;
  7.1714 -
  7.1715 -	if(argc == 2 && !strncmp("-v", argv[1], 3)) {
  7.1716 -		fputs("dwm-"VERSION", (C)opyright MMVI-MMVII Anselm R. Garbe\n", stdout);
  7.1717 -		exit(EXIT_SUCCESS);
  7.1718 -	} else if(argc != 1) {
  7.1719 -		eprint("usage: dwm [-v]\n");
  7.1720 -	}
  7.1721 -	setlocale(LC_CTYPE, "");
  7.1722 -	dpy = XOpenDisplay(0);
  7.1723 -	if(!dpy) {
  7.1724 -		eprint("dwm: cannot open display\n");
  7.1725 -	}
  7.1726 -	xfd = ConnectionNumber(dpy);
  7.1727 -	screen = DefaultScreen(dpy);
  7.1728 -	root = RootWindow(dpy, screen);
  7.1729 -	otherwm = False;
  7.1730 -	XSetErrorHandler(xerrorstart);
  7.1731 -	/* this causes an error if some other window manager is running */
  7.1732 -	XSelectInput(dpy, root, SubstructureRedirectMask);
  7.1733 -	XSync(dpy, False);
  7.1734 -	if(otherwm) {
  7.1735 -		eprint("dwm: another window manager is already running\n");
  7.1736 -	}
  7.1737 -
  7.1738 -	XSync(dpy, False);
  7.1739 -	XSetErrorHandler(NULL);
  7.1740 -	xerrorxlib = XSetErrorHandler(xerror);
  7.1741 -	XSync(dpy, False);
  7.1742 -	setup();
  7.1743 -	drawstatus();
  7.1744 -	scan();
  7.1745 -
  7.1746 -	/* main event loop, also reads status text from stdin */
  7.1747 -	XSync(dpy, False);
  7.1748 -	procevent();
  7.1749 -	readin = True;
  7.1750 -	while(running) {
  7.1751 -		FD_ZERO(&rd);
  7.1752 -		if(readin)
  7.1753 -			FD_SET(STDIN_FILENO, &rd);
  7.1754 -		FD_SET(xfd, &rd);
  7.1755 -		if(select(xfd + 1, &rd, NULL, NULL, NULL) == -1) {
  7.1756 -			if(errno == EINTR)
  7.1757 -				continue;
  7.1758 -			eprint("select failed\n");
  7.1759 -		}
  7.1760 -		if(FD_ISSET(STDIN_FILENO, &rd)) {
  7.1761 -			switch(r = read(STDIN_FILENO, stext, sizeof stext - 1)) {
  7.1762 -			case -1:
  7.1763 -				strncpy(stext, strerror(errno), sizeof stext - 1);
  7.1764 -				stext[sizeof stext - 1] = '\0';
  7.1765 -				readin = False;
  7.1766 -				break;
  7.1767 -			case 0:
  7.1768 -				strncpy(stext, "EOF", 4);
  7.1769 -				readin = False;
  7.1770 -				break;
  7.1771 -			default:
  7.1772 -				for(stext[r] = '\0', p = stext + strlen(stext) - 1; p >= stext && *p == '\n'; *p-- = '\0');
  7.1773 -				for(; p >= stext && *p != '\n'; --p);
  7.1774 -				if(p > stext)
  7.1775 -					strncpy(stext, p + 1, sizeof stext);
  7.1776 -			}
  7.1777 -			drawstatus();
  7.1778 -		}
  7.1779 -		if(FD_ISSET(xfd, &rd))
  7.1780 -			procevent();
  7.1781 -	}
  7.1782 -	cleanup();
  7.1783 -	XCloseDisplay(dpy);
  7.1784 -	return 0;
  7.1785 -}