VOOZH about

URL: https://bbs.archlinux.org/viewtopic.php?id=74599

โ‡ฑ Show off your Dwm configuration! / Artwork and Screenshots / Arch Linux Forums


Arch Linux

You are not logged in.

#1 2009-06-23 10:41:13

zowki
Member
๐Ÿ‘ Image
From: Trapped in The Matrix
Registered: 2008-11-27
Posts: 582
Website

Show off your Dwm configuration!

Welcome all dwm users! Post a screenshot of your desktop and optionally along with your configuration files.

Heres mine:

Clean desktop
๐Ÿ‘ thumb2.png

Busy desktop
๐Ÿ‘ thumb1.png

I combine the work and play workspaces to prevent myself from doing both! ๐Ÿ‘ wink

Running programs: vim, w3m, urxvt, conky
Font: Terminus

.conkyrc

own_window yes
own_window_type override
own_window_colour 000000
own_window_transparent no
own_window_hints undecorated below sticky skip_taskbar skip_pager
double_buffer yes
cpu_avg_samples 2
net_avg_samples 2
use_xft no
xftfont Terminus:size=8
update_interval 0.1
minimum_size 1280 10
maximum_width 1280
border_margin 4
border_width 1
draw_outline no
default_color white
alignment bottom_left
use_spacer right
no_buffers yes
uppercase no

TEXT
${alignc}$nodename ${color #0100ff}Uptime:${color white} $uptime ${color #0077ff}| CPU:${color #0077ff} ${color white}${cpu}%${color #0077ff} | FS: ${color lightgrey}${fs_used /}/${fs_size /}${color #0077ff} | /home: ${color lightgrey}${fs_used /home}/${fs_size /home}${color #0077ff} | RAM: ${color white}$mem ${color #0077ff}| Network:${color white} ${wireless_essid eth0} ${color #0077ff}| Down: ${color white}${downspeed eth0} ${color #0077ff}| Up: ${color white}${upspeed eth0} ${color #0077ff}| Battery: ${color white}${battery BAT1} ${battery_time BAT1} ${color #0077ff}| Volume:${color white} ${exec amixer get Master | egrep -o "[0-9]+%" | head -1 | egrep -o "[0-9]*"}%

config.h (BOTTOM_BAR_HEIGHT is for the gap for my conkybar)

/* See LICENSE file for copyright and license details. */

/* appearance */
#define BOTTOM_BAR_HEIGHT 13
static const char font[] = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
static const char normbordercolor[] = "#333333";
static const char normbgcolor[] = "#051121";
static const char normfgcolor[] = "#FFFFFF";
static const char selbordercolor[] = "#1793D1";
static const char selbgcolor[] = "#1793D1";
static const char selfgcolor[] = "#FFFFFF";
static unsigned int borderpx = 1; /* border pixel of windows */
static unsigned int snap = 32; /* snap pixel */
static Bool showbar = True; /* False means no bar */
static Bool topbar = True; /* False means bottom bar */

/* tagging */
static const char tags[][MAXTAGLEN] = { "web", "term/chat", "work/play", "vbox", "misc" };
static unsigned int tagset[] = {1, 1}; /* after start, first tag is selected */

static Rule rules[] = {
 /* class instance title tags mask isfloating */
 { "Gimp", NULL, NULL, NULL, True },
 { "MPlayer", NULL, NULL, NULL, True },
};

/* layout(s) */
static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static Bool resizehints = True; /* False means respect size hints in tiled resizals */

static Layout layouts[] = {
 /* symbol arrange function */
 { "[T]", tile }, /* first entry is default */
 { "[F]", NULL }, /* no layout function means floating behavior */
 { "[M]", monocle },
};

/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
 { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
 { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
 { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
 { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "urxvt", NULL };
static const char *volup[] = {"volup", NULL};
static const char *voldwn[] = {"voldwn", NULL};
static const char *volmute[] = {"volmute", NULL};

static Key keys[] = {
 /* modifier key function argument */
 { MODKEY, XK_p, spawn, {.v = dmenucmd } },
 { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
 { MODKEY, XK_i, spawn, {.v = voldwn } },
 { MODKEY, XK_o, spawn, {.v = volup } },
 { MODKEY, XK_u, spawn, {.v = volmute } },
 { MODKEY, XK_b, togglebar, {0} },
 { MODKEY, XK_j, focusstack, {.i = +1 } },
 { MODKEY, XK_k, focusstack, {.i = -1 } },
 { MODKEY, XK_h, setmfact, {.f = -0.05} },
 { MODKEY, XK_l, setmfact, {.f = +0.05} },
 { MODKEY, XK_Return, zoom, {0} },
 { MODKEY, XK_Tab, view, {0} },
 { MODKEY|ShiftMask, XK_c, killclient, {0} },
 { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
 { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
 { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
 { MODKEY, XK_space, setlayout, {0} },
 { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
 { MODKEY, XK_0, view, {.ui = ~0 } },
 { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
 TAGKEYS( XK_1, 0)
 TAGKEYS( XK_2, 1)
 TAGKEYS( XK_3, 2)
 TAGKEYS( XK_4, 3)
 TAGKEYS( XK_5, 4)
 TAGKEYS( XK_6, 5)
 TAGKEYS( XK_7, 6)
 TAGKEYS( XK_8, 7)
 TAGKEYS( XK_9, 8)
 { MODKEY|ShiftMask, XK_q, quit, {0} },
};

/* button definitions */
/* click can be a tag number (starting at 0),
 * ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
 /* click event mask button function argument */
 { ClkLtSymbol, 0, Button1, setlayout, {0} },
 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
 { ClkWinTitle, 0, Button2, zoom, {0} },
 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
 { ClkClientWin, MODKEY, Button1, movemouse, {0} },
 { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
 { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
 { ClkTagBar, 0, Button1, view, {0} },
 { ClkTagBar, 0, Button3, toggleview, {0} },
 { ClkTagBar, MODKEY, Button1, tag, {0} },
 { ClkTagBar, MODKEY, Button3, toggletag, {0} },
};

dwm.c (I edited it to give a gap for my conky bar at the bottom, see the updategeom(void) function for how I did it)

/* See LICENSE file for copyright and license details.
 *
 * dynamic window manager is designed like any other X client as well. It is
 * driven through handling X events. In contrast to other X clients, a window
 * manager selects for SubstructureRedirectMask on the root window, to receive
 * events about window (dis-)appearance. Only one X connection at a time is
 * allowed to select for this event mask.
 *
 * The event handlers of dwm are organized in an array which is accessed
 * whenever a new event has been fetched. This allows event dispatching
 * in O(1) time.
 *
 * Each child of the root window is called a client, except windows which have
 * set the override_redirect flag. Clients are organized in a global
 * linked client list, the focus history is remembered through a global
 * stack list. Each client contains a bit array to indicate the tags of a
 * client.
 *
 * Keys and tagging rules are organized as arrays and defined in config.h.
 *
 * To understand everything else, start reading main().
 */
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
#define ISVISIBLE(x) (x->tags & tagset[seltags])
#define LENGTH(x) (sizeof x / sizeof x[0])
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAXTAGLEN 16
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(x) ((x)->w + 2 * (x)->bw)
#define HEIGHT(x) ((x)->h + 2 * (x)->bw)
#define TAGMASK ((int)((1LL << LENGTH(tags)) - 1))
#define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height)

/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */

typedef union {
 int i;
 unsigned int ui;
 float f;
 void *v;
} Arg;

typedef struct {
 unsigned int click;
 unsigned int mask;
 unsigned int button;
 void (*func)(const Arg *arg);
 const Arg arg;
} Button;

typedef struct Client Client;
struct Client {
 char name[256];
 float mina, maxa;
 int x, y, w, h;
 int basew, baseh, incw, inch, maxw, maxh, minw, minh;
 int bw, oldbw;
 unsigned int tags;
 Bool isfixed, isfloating, isurgent;
 Client *next;
 Client *snext;
 Window win;
};

typedef struct {
 int x, y, w, h;
 unsigned long norm[ColLast];
 unsigned long sel[ColLast];
 Drawable drawable;
 GC gc;
 struct {
 int ascent;
 int descent;
 int height;
 XFontSet set;
 XFontStruct *xfont;
 } font;
} DC; /* draw context */

typedef struct {
 unsigned int mod;
 KeySym keysym;
 void (*func)(const Arg *);
 const Arg arg;
} Key;

typedef struct {
 const char *symbol;
 void (*arrange)(void);
} Layout;

typedef struct {
 const char *class;
 const char *instance;
 const char *title;
 unsigned int tags;
 Bool isfloating;
} Rule;

/* function declarations */
static void applyrules(Client *c);
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h);
static void arrange(void);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void clearurgent(Client *c);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static void die(const char *errstr, ...);
static void drawbar(void);
static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusstack(const Arg *arg);
static Client *getclient(Window w);
static unsigned long getcolor(const char *colstr);
static long getstate(Window w);
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, Bool focused);
static void grabkeys(void);
static void initfont(const char *fontstr);
static Bool isprotodel(Client *c);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(void);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(void);
static void run(void);
static void scan(void);
static void setclientstate(Client *c, long state);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void showhide(Client *c);
static void sigchld(int signal);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void tile(void);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unmanage(Client *c);
static void unmapnotify(XEvent *e);
static void updatebar(void);
static void updategeom(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);

/* variables */
static char stext[256];
static int screen;
static int sx, sy, sw, sh; /* X display screen geometry x, y, width, height */ 
static int by, bh, blw; /* bar geometry y, height and layout symbol width */
static int wx, wy, ww, wh; /* window area geometry x, y, width, height, bar excluded */
static unsigned int seltags = 0, sellt = 0;
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
 [ButtonPress] = buttonpress,
 [ConfigureRequest] = configurerequest,
 [ConfigureNotify] = configurenotify,
 [DestroyNotify] = destroynotify,
 [EnterNotify] = enternotify,
 [Expose] = expose,
 [FocusIn] = focusin,
 [KeyPress] = keypress,
 [MappingNotify] = mappingnotify,
 [MapRequest] = maprequest,
 [PropertyNotify] = propertynotify,
 [UnmapNotify] = unmapnotify
};
static Atom wmatom[WMLast], netatom[NetLast];
static Bool otherwm;
static Bool running = True;
static Client *clients = NULL;
static Client *sel = NULL;
static Client *stack = NULL;
static Cursor cursor[CurLast];
static Display *dpy;
static DC dc;
static Layout *lt[] = { NULL, NULL };
static Window root, barwin;
/* configuration, allows nested code to access above variables */
#include "config.h"

/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[sizeof(unsigned int) * 8 < LENGTH(tags) ? -1 : 1]; };

/* function implementations */
void
applyrules(Client *c) {
 unsigned int i;
 Rule *r;
 XClassHint ch = { 0 };

 /* rule matching */
 c->isfloating = c->tags = 0;
 if(XGetClassHint(dpy, c->win, &ch)) {
 for(i = 0; i < LENGTH(rules); i++) {
 r = &rules[i];
 if((!r->title || strstr(c->name, r->title))
 && (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
 && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
 c->isfloating = r->isfloating;
 c->tags |= r->tags; 
 }
 }
 if(ch.res_class)
 XFree(ch.res_class);
 if(ch.res_name)
 XFree(ch.res_name);
 }
 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : tagset[seltags];
}

Bool
applysizehints(Client *c, int *x, int *y, int *w, int *h) {
 Bool baseismin;

 /* set minimum possible */
 *w = MAX(1, *w);
 *h = MAX(1, *h);

 if(*x > sx + sw)
 *x = sw - WIDTH(c);
 if(*y > sy + sh)
 *y = sh - HEIGHT(c);
 if(*x + *w + 2 * c->bw < sx)
 *x = sx;
 if(*y + *h + 2 * c->bw < sy)
 *y = sy;
 if(*h < bh)
 *h = bh;
 if(*w < bh)
 *w = bh;

 if(resizehints || c->isfloating) {
 /* see last two sentences in ICCCM 4.1.2.3 */
 baseismin = c->basew == c->minw && c->baseh == c->minh;

 if(!baseismin) { /* temporarily remove base dimensions */
 *w -= c->basew;
 *h -= c->baseh;
 }

 /* adjust for aspect limits */
 if(c->mina > 0 && c->maxa > 0) {
 if(c->maxa < (float)*w / *h)
 *w = *h * c->maxa;
 else if(c->mina < (float)*h / *w)
 *h = *w * c->mina;
 }

 if(baseismin) { /* increment calculation requires this */
 *w -= c->basew;
 *h -= c->baseh;
 }

 /* adjust for increment value */
 if(c->incw)
 *w -= *w % c->incw;
 if(c->inch)
 *h -= *h % c->inch;

 /* restore base dimensions */
 *w += c->basew;
 *h += c->baseh;

 *w = MAX(*w, c->minw);
 *h = MAX(*h, c->minh);

 if(c->maxw)
 *w = MIN(*w, c->maxw);

 if(c->maxh)
 *h = MIN(*h, c->maxh);
 }
 return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
}

void
arrange(void) {
 showhide(stack);
 focus(NULL);
 if(lt[sellt]->arrange)
 lt[sellt]->arrange();
 restack();
}

void
attach(Client *c) {
 c->next = clients;
 clients = c;
}

void
attachstack(Client *c) {
 c->snext = stack;
 stack = c;
}

void
buttonpress(XEvent *e) {
 unsigned int i, x, click;
 Arg arg = {0};
 Client *c;
 XButtonPressedEvent *ev = &e->xbutton;

 click = ClkRootWin;
 if(ev->window == barwin) {
 i = x = 0;
 do x += TEXTW(tags[i]); while(ev->x >= x && ++i < LENGTH(tags));
 if(i < LENGTH(tags)) {
 click = ClkTagBar;
 arg.ui = 1 << i;
 }
 else if(ev->x < x + blw)
 click = ClkLtSymbol;
 else if(ev->x > wx + ww - TEXTW(stext))
 click = ClkStatusText;
 else
 click = ClkWinTitle;
 }
 else if((c = getclient(ev->window))) {
 focus(c);
 click = ClkClientWin;
 }

 for(i = 0; i < LENGTH(buttons); i++)
 if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
 buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}

void
checkotherwm(void) {
 otherwm = False;
 xerrorxlib = XSetErrorHandler(xerrorstart);

 /* this causes an error if some other window manager is running */
 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
 XSync(dpy, False);
 if(otherwm)
 die("dwm: another window manager is already running\n");
 XSetErrorHandler(xerror);
 XSync(dpy, False);
}

void
cleanup(void) {
 Arg a = {.ui = ~0};
 Layout foo = { "", NULL };

 view(&a);
 lt[sellt] = &foo;
 while(stack)
 unmanage(stack);
 if(dc.font.set)
 XFreeFontSet(dpy, dc.font.set);
 else
 XFreeFont(dpy, dc.font.xfont);
 XUngrabKey(dpy, AnyKey, AnyModifier, root);
 XFreePixmap(dpy, dc.drawable);
 XFreeGC(dpy, dc.gc);
 XFreeCursor(dpy, cursor[CurNormal]);
 XFreeCursor(dpy, cursor[CurResize]);
 XFreeCursor(dpy, cursor[CurMove]);
 XDestroyWindow(dpy, barwin);
 XSync(dpy, False);
 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}

void
clearurgent(Client *c) {
 XWMHints *wmh;

 c->isurgent = False;
 if(!(wmh = XGetWMHints(dpy, c->win)))
 return;
 wmh->flags &= ~XUrgencyHint;
 XSetWMHints(dpy, c->win, wmh);
 XFree(wmh);
}

void
configure(Client *c) {
 XConfigureEvent ce;

 ce.type = ConfigureNotify;
 ce.display = dpy;
 ce.event = c->win;
 ce.window = c->win;
 ce.x = c->x;
 ce.y = c->y;
 ce.width = c->w;
 ce.height = c->h;
 ce.border_width = c->bw;
 ce.above = None;
 ce.override_redirect = False;
 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}

void
configurenotify(XEvent *e) {
 XConfigureEvent *ev = &e->xconfigure;

 if(ev->window == root && (ev->width != sw || ev->height != sh)) {
 sw = ev->width;
 sh = ev->height;
 updategeom();
 updatebar();
 arrange();
 }
}

void
configurerequest(XEvent *e) {
 Client *c;
 XConfigureRequestEvent *ev = &e->xconfigurerequest;
 XWindowChanges wc;

 if((c = getclient(ev->window))) {
 if(ev->value_mask & CWBorderWidth)
 c->bw = ev->border_width;
 else if(c->isfloating || !lt[sellt]->arrange) {
 if(ev->value_mask & CWX)
 c->x = sx + ev->x;
 if(ev->value_mask & CWY)
 c->y = sy + ev->y;
 if(ev->value_mask & CWWidth)
 c->w = ev->width;
 if(ev->value_mask & CWHeight)
 c->h = ev->height;
 if((c->x - sx + c->w) > sw && c->isfloating)
 c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */
 if((c->y - sy + c->h) > sh && c->isfloating)
 c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
 configure(c);
 if(ISVISIBLE(c))
 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
 }
 else
 configure(c);
 }
 else {
 wc.x = ev->x;
 wc.y = ev->y;
 wc.width = ev->width;
 wc.height = ev->height;
 wc.border_width = ev->border_width;
 wc.sibling = ev->above;
 wc.stack_mode = ev->detail;
 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
 }
 XSync(dpy, False);
}

void
destroynotify(XEvent *e) {
 Client *c;
 XDestroyWindowEvent *ev = &e->xdestroywindow;

 if((c = getclient(ev->window)))
 unmanage(c);
}

void
detach(Client *c) {
 Client **tc;

 for(tc = &clients; *tc && *tc != c; tc = &(*tc)->next);
 *tc = c->next;
}

void
detachstack(Client *c) {
 Client **tc;

 for(tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
 *tc = c->snext;
}

void
die(const char *errstr, ...) {
 va_list ap;

 va_start(ap, errstr);
 vfprintf(stderr, errstr, ap);
 va_end(ap);
 exit(EXIT_FAILURE);
}

void
drawbar(void) {
 int x;
 unsigned int i, occ = 0, urg = 0;
 unsigned long *col;
 Client *c;

 for(c = clients; c; c = c->next) {
 occ |= c->tags;
 if(c->isurgent)
 urg |= c->tags;
 }

 dc.x = 0;
 for(i = 0; i < LENGTH(tags); i++) {
 dc.w = TEXTW(tags[i]);
 col = tagset[seltags] & 1 << i ? dc.sel : dc.norm;
 drawtext(tags[i], col, urg & 1 << i);
 drawsquare(sel && sel->tags & 1 << i, occ & 1 << i, urg & 1 << i, col);
 dc.x += dc.w;
 }
 if(blw > 0) {
 dc.w = blw;
 drawtext(lt[sellt]->symbol, dc.norm, False);
 x = dc.x + dc.w;
 }
 else
 x = dc.x;
 dc.w = TEXTW(stext);
 dc.x = ww - dc.w;
 if(dc.x < x) {
 dc.x = x;
 dc.w = ww - x;
 }
 drawtext(stext, dc.norm, False);
 if((dc.w = dc.x - x) > bh) {
 dc.x = x;
 if(sel) {
 drawtext(sel->name, dc.sel, False);
 drawsquare(sel->isfixed, sel->isfloating, False, dc.sel);
 }
 else
 drawtext(NULL, dc.norm, False);
 }
 XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, ww, bh, 0, 0);
 XSync(dpy, False);
}

void
drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
 int x;
 XGCValues gcv;
 XRectangle r = { dc.x, dc.y, dc.w, dc.h };

 gcv.foreground = col[invert ? ColBG : ColFG];
 XChangeGC(dpy, dc.gc, GCForeground, &gcv);
 x = (dc.font.ascent + dc.font.descent + 2) / 4;
 r.x = dc.x + 1;
 r.y = dc.y + 1;
 if(filled) {
 r.width = r.height = x + 1;
 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 }
 else if(empty) {
 r.width = r.height = x;
 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 }
}

void
drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
 char buf[256];
 int i, x, y, h, len, olen;
 XRectangle r = { dc.x, dc.y, dc.w, dc.h };

 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 if(!text)
 return;
 olen = strlen(text);
 h = dc.font.ascent + dc.font.descent;
 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
 x = dc.x + (h / 2);
 /* shorten text if necessary */
 for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
 if(!len)
 return;
 memcpy(buf, text, len);
 if(len < olen)
 for(i = len; i && i > len - 3; buf[--i] = '.');
 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
 if(dc.font.set)
 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
 else
 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}

void
enternotify(XEvent *e) {
 Client *c;
 XCrossingEvent *ev = &e->xcrossing;

 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
 return;
 if((c = getclient(ev->window)))
 focus(c);
 else
 focus(NULL);
}

void
expose(XEvent *e) {
 XExposeEvent *ev = &e->xexpose;

 if(ev->count == 0 && (ev->window == barwin))
 drawbar();
}

void
focus(Client *c) {
 if(!c || !ISVISIBLE(c))
 for(c = stack; c && !ISVISIBLE(c); c = c->snext);
 if(sel && sel != c) {
 grabbuttons(sel, False);
 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
 }
 if(c) {
 if(c->isurgent)
 clearurgent(c);
 detachstack(c);
 attachstack(c);
 grabbuttons(c, True);
 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
 }
 else
 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
 sel = c;
 drawbar();
}

void
focusin(XEvent *e) { /* there are some broken focus acquiring clients */
 XFocusChangeEvent *ev = &e->xfocus;

 if(sel && ev->window != sel->win)
 XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
}

void
focusstack(const Arg *arg) {
 Client *c = NULL, *i;

 if(!sel)
 return;
 if (arg->i > 0) {
 for(c = sel->next; c && !ISVISIBLE(c); c = c->next);
 if(!c)
 for(c = clients; c && !ISVISIBLE(c); c = c->next);
 }
 else {
 for(i = clients; i != sel; i = i->next)
 if(ISVISIBLE(i))
 c = i;
 if(!c)
 for(; i; i = i->next)
 if(ISVISIBLE(i))
 c = i;
 }
 if(c) {
 focus(c);
 restack();
 }
}

Client *
getclient(Window w) {
 Client *c;

 for(c = clients; c && c->win != w; c = c->next);
 return c;
}

unsigned long
getcolor(const char *colstr) {
 Colormap cmap = DefaultColormap(dpy, screen);
 XColor color;

 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 die("error, cannot allocate color '%s'\n", colstr);
 return color.pixel;
}

long
getstate(Window w) {
 int format, status;
 long result = -1;
 unsigned char *p = NULL;
 unsigned long n, extra;
 Atom real;

 status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
 &real, &format, &n, &extra, (unsigned char **)&p);
 if(status != Success)
 return -1;
 if(n != 0)
 result = *p;
 XFree(p);
 return result;
}

Bool
gettextprop(Window w, Atom atom, char *text, unsigned int size) {
 char **list = NULL;
 int n;
 XTextProperty name;

 if(!text || size == 0)
 return False;
 text[0] = '\0';
 XGetTextProperty(dpy, w, &name, atom);
 if(!name.nitems)
 return False;
 if(name.encoding == XA_STRING)
 strncpy(text, (char *)name.value, size - 1);
 else {
 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
 && n > 0 && *list) {
 strncpy(text, *list, size - 1);
 XFreeStringList(list);
 }
 }
 text[size - 1] = '\0';
 XFree(name.value);
 return True;
}

void
grabbuttons(Client *c, Bool focused) {
 updatenumlockmask();
 {
 unsigned int i, j;
 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 if(focused) {
 for(i = 0; i < LENGTH(buttons); i++)
 if(buttons[i].click == ClkClientWin)
 for(j = 0; j < LENGTH(modifiers); j++)
 XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
 } else
 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
 BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
 }
}

void
grabkeys(void) {
 updatenumlockmask();
 { /* grab keys */
 unsigned int i, j;
 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
 KeyCode code;

 XUngrabKey(dpy, AnyKey, AnyModifier, root);
 for(i = 0; i < LENGTH(keys); i++) {
 if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
 for(j = 0; j < LENGTH(modifiers); j++)
 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
 True, GrabModeAsync, GrabModeAsync);
 }
 }
}

void
initfont(const char *fontstr) {
 char *def, **missing;
 int i, n;

 missing = NULL;
 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 if(missing) {
 while(n--)
 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
 XFreeStringList(missing);
 }
 if(dc.font.set) {
 XFontSetExtents *font_extents;
 XFontStruct **xfonts;
 char **font_names;
 dc.font.ascent = dc.font.descent = 0;
 font_extents = XExtentsOfFontSet(dc.font.set);
 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
 dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
 dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent);
 xfonts++;
 }
 }
 else {
 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
 die("error, cannot load font: '%s'\n", fontstr);
 dc.font.ascent = dc.font.xfont->ascent;
 dc.font.descent = dc.font.xfont->descent;
 }
 dc.font.height = dc.font.ascent + dc.font.descent;
}

Bool
isprotodel(Client *c) {
 int i, n;
 Atom *protocols;
 Bool ret = False;

 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
 for(i = 0; !ret && i < n; i++)
 if(protocols[i] == wmatom[WMDelete])
 ret = True;
 XFree(protocols);
 }
 return ret;
}

void
keypress(XEvent *e) {
 unsigned int i;
 KeySym keysym;
 XKeyEvent *ev;

 ev = &e->xkey;
 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
 for(i = 0; i < LENGTH(keys); i++)
 if(keysym == keys[i].keysym
 && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
 && keys[i].func)
 keys[i].func(&(keys[i].arg));
}

void
killclient(const Arg *arg) {
 XEvent ev;

 if(!sel)
 return;
 if(isprotodel(sel)) {
 ev.type = ClientMessage;
 ev.xclient.window = sel->win;
 ev.xclient.message_type = wmatom[WMProtocols];
 ev.xclient.format = 32;
 ev.xclient.data.l[0] = wmatom[WMDelete];
 ev.xclient.data.l[1] = CurrentTime;
 XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
 }
 else
 XKillClient(dpy, sel->win);
}

void
manage(Window w, XWindowAttributes *wa) {
 static Client cz;
 Client *c, *t = NULL;
 Window trans = None;
 XWindowChanges wc;

 if(!(c = malloc(sizeof(Client))))
 die("fatal: could not malloc() %u bytes\n", sizeof(Client));
 *c = cz;
 c->win = w;

 /* geometry */
 c->x = wa->x;
 c->y = wa->y;
 c->w = wa->width;
 c->h = wa->height;
 c->oldbw = wa->border_width;
 if(c->w == sw && c->h == sh) {
 c->x = sx;
 c->y = sy;
 c->bw = 0;
 }
 else {
 if(c->x + WIDTH(c) > sx + sw)
 c->x = sx + sw - WIDTH(c);
 if(c->y + HEIGHT(c) > sy + sh)
 c->y = sy + sh - HEIGHT(c);
 c->x = MAX(c->x, sx);
 /* only fix client y-offset, if the client center might cover the bar */
 c->y = MAX(c->y, ((by == 0) && (c->x + (c->w / 2) >= wx) && (c->x + (c->w / 2) < wx + ww)) ? bh : sy);
 c->bw = borderpx;
 }

 wc.border_width = c->bw;
 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
 XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
 configure(c); /* propagates border_width, if size doesn't change */
 updatesizehints(c);
 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
 grabbuttons(c, False);
 updatetitle(c);
 if(XGetTransientForHint(dpy, w, &trans))
 t = getclient(trans);
 if(t)
 c->tags = t->tags;
 else
 applyrules(c);
 if(!c->isfloating)
 c->isfloating = trans != None || c->isfixed;
 if(c->isfloating)
 XRaiseWindow(dpy, c->win);
 attach(c);
 attachstack(c);
 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
 XMapWindow(dpy, c->win);
 setclientstate(c, NormalState);
 arrange();
}

void
mappingnotify(XEvent *e) {
 XMappingEvent *ev = &e->xmapping;

 XRefreshKeyboardMapping(ev);
 if(ev->request == MappingKeyboard)
 grabkeys();
}

void
maprequest(XEvent *e) {
 static XWindowAttributes wa;
 XMapRequestEvent *ev = &e->xmaprequest;

 if(!XGetWindowAttributes(dpy, ev->window, &wa))
 return;
 if(wa.override_redirect)
 return;
 if(!getclient(ev->window))
 manage(ev->window, &wa);
}

void
monocle(void) {
 Client *c;

 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
 resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw);
 }
}

void
movemouse(const Arg *arg) {
 int x, y, ocx, ocy, di, nx, ny;
 unsigned int dui;
 Client *c;
 Window dummy;
 XEvent ev;

 if(!(c = sel))
 return;
 restack();
 ocx = c->x;
 ocy = c->y;
 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 None, cursor[CurMove], CurrentTime) != GrabSuccess)
 return;
 XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui);
 do {
 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
 switch (ev.type) {
 case ConfigureRequest:
 case Expose:
 case MapRequest:
 handler[ev.type](&ev);
 break;
 case MotionNotify:
 nx = ocx + (ev.xmotion.x - x);
 ny = ocy + (ev.xmotion.y - y);
 if(snap && nx >= wx && nx <= wx + ww
 && ny >= wy && ny <= wy + wh) {
 if(abs(wx - nx) < snap)
 nx = wx;
 else if(abs((wx + ww) - (nx + WIDTH(c))) < snap)
 nx = wx + ww - WIDTH(c);
 if(abs(wy - ny) < snap)
 ny = wy;
 else if(abs((wy + wh) - (ny + HEIGHT(c))) < snap)
 ny = wy + wh - HEIGHT(c);
 if(!c->isfloating && lt[sellt]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
 togglefloating(NULL);
 }
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, nx, ny, c->w, c->h);
 break;
 }
 }
 while(ev.type != ButtonRelease);
 XUngrabPointer(dpy, CurrentTime);
}

Client *
nexttiled(Client *c) {
 for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
 return c;
}

void
propertynotify(XEvent *e) {
 Client *c;
 Window trans;
 XPropertyEvent *ev = &e->xproperty;

 if((ev->window == root) && (ev->atom == XA_WM_NAME))
 updatestatus();
 else if(ev->state == PropertyDelete)
 return; /* ignore */
 else if((c = getclient(ev->window))) {
 switch (ev->atom) {
 default: break;
 case XA_WM_TRANSIENT_FOR:
 XGetTransientForHint(dpy, c->win, &trans);
 if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
 arrange();
 break;
 case XA_WM_NORMAL_HINTS:
 updatesizehints(c);
 break;
 case XA_WM_HINTS:
 updatewmhints(c);
 drawbar();
 break;
 }
 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
 updatetitle(c);
 if(c == sel)
 drawbar();
 }
 }
}

void
quit(const Arg *arg) {
 running = False;
}

void
resize(Client *c, int x, int y, int w, int h) {
 XWindowChanges wc;

 if(applysizehints(c, &x, &y, &w, &h)) {
 c->x = wc.x = x;
 c->y = wc.y = y;
 c->w = wc.width = w;
 c->h = wc.height = h;
 wc.border_width = c->bw;
 XConfigureWindow(dpy, c->win,
 CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
 configure(c);
 XSync(dpy, False);
 }
}

void
resizemouse(const Arg *arg) {
 int ocx, ocy;
 int nw, nh;
 Client *c;
 XEvent ev;

 if(!(c = sel))
 return;
 restack();
 ocx = c->x;
 ocy = c->y;
 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 None, cursor[CurResize], CurrentTime) != GrabSuccess)
 return;
 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
 do {
 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
 switch(ev.type) {
 case ConfigureRequest:
 case Expose:
 case MapRequest:
 handler[ev.type](&ev);
 break;
 case MotionNotify:
 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);

 if(snap && nw >= wx && nw <= wx + ww
 && nh >= wy && nh <= wy + wh) {
 if(!c->isfloating && lt[sellt]->arrange
 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
 togglefloating(NULL);
 }
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, c->x, c->y, nw, nh);
 break;
 }
 }
 while(ev.type != ButtonRelease);
 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
 XUngrabPointer(dpy, CurrentTime);
 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
restack(void) {
 Client *c;
 XEvent ev;
 XWindowChanges wc;

 drawbar();
 if(!sel)
 return;
 if(sel->isfloating || !lt[sellt]->arrange)
 XRaiseWindow(dpy, sel->win);
 if(lt[sellt]->arrange) {
 wc.stack_mode = Below;
 wc.sibling = barwin;
 for(c = stack; c; c = c->snext)
 if(!c->isfloating && ISVISIBLE(c)) {
 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
 wc.sibling = c->win;
 }
 }
 XSync(dpy, False);
 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
run(void) {
 XEvent ev;

 /* main event loop */
 XSync(dpy, False);
 while(running && !XNextEvent(dpy, &ev)) {
 if(handler[ev.type])
 (handler[ev.type])(&ev); /* call handler */
 }
}

void
scan(void) {
 unsigned int i, num;
 Window d1, d2, *wins = NULL;
 XWindowAttributes wa;

 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
 for(i = 0; i < num; i++) {
 if(!XGetWindowAttributes(dpy, wins[i], &wa)
 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
 continue;
 if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
 manage(wins[i], &wa);
 }
 for(i = 0; i < num; i++) { /* now the transients */
 if(!XGetWindowAttributes(dpy, wins[i], &wa))
 continue;
 if(XGetTransientForHint(dpy, wins[i], &d1)
 && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
 manage(wins[i], &wa);
 }
 if(wins)
 XFree(wins);
 }
}

void
setclientstate(Client *c, long state) {
 long data[] = {state, None};

 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
 PropModeReplace, (unsigned char *)data, 2);
}

void
setlayout(const Arg *arg) {
 if(!arg || !arg->v || arg->v != lt[sellt])
 sellt ^= 1;
 if(arg && arg->v)
 lt[sellt] = (Layout *)arg->v;
 if(sel)
 arrange();
 else
 drawbar();
}

/* arg > 1.0 will set mfact absolutly */
void
setmfact(const Arg *arg) {
 float f;

 if(!arg || !lt[sellt]->arrange)
 return;
 f = arg->f < 1.0 ? arg->f + mfact : arg->f - 1.0;
 if(f < 0.1 || f > 0.9)
 return;
 mfact = f;
 arrange();
}

void
setup(void) {
 unsigned int i;
 int w;
 XSetWindowAttributes wa;

 /* init screen */
 screen = DefaultScreen(dpy);
 root = RootWindow(dpy, screen);
 initfont(font);
 sx = 0;
 sy = 0;
 sw = DisplayWidth(dpy, screen);
 sh = DisplayHeight(dpy, screen);
 bh = dc.h = dc.font.height + 2;
 lt[0] = &layouts[0];
 lt[1] = &layouts[1 % LENGTH(layouts)];
 updategeom();

 /* init atoms */
 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);

 /* init cursors */
 wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);

 /* init appearance */
 dc.norm[ColBorder] = getcolor(normbordercolor);
 dc.norm[ColBG] = getcolor(normbgcolor);
 dc.norm[ColFG] = getcolor(normfgcolor);
 dc.sel[ColBorder] = getcolor(selbordercolor);
 dc.sel[ColBG] = getcolor(selbgcolor);
 dc.sel[ColFG] = getcolor(selfgcolor);
 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
 dc.gc = XCreateGC(dpy, root, 0, NULL);
 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
 if(!dc.font.set)
 XSetFont(dpy, dc.gc, dc.font.xfont->fid);

 /* init bar */
 for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
 w = TEXTW(layouts[i].symbol);
 blw = MAX(blw, w);
 }

 wa.override_redirect = True;
 wa.background_pixmap = ParentRelative;
 wa.event_mask = ButtonPressMask|ExposureMask;

 barwin = XCreateWindow(dpy, root, wx, by, ww, bh, 0, DefaultDepth(dpy, screen),
 CopyFromParent, DefaultVisual(dpy, screen),
 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
 XDefineCursor(dpy, barwin, cursor[CurNormal]);
 XMapRaised(dpy, barwin);
 updatestatus();

 /* EWMH support per view */
 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
 PropModeReplace, (unsigned char *) netatom, NetLast);

 /* select for events */
 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
 |PropertyChangeMask;
 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
 XSelectInput(dpy, root, wa.event_mask);

 grabkeys();
}

void
showhide(Client *c) {
 if(!c)
 return;
 if(ISVISIBLE(c)) { /* show clients top down */
 XMoveWindow(dpy, c->win, c->x, c->y);
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, c->x, c->y, c->w, c->h);
 showhide(c->snext);
 }
 else { /* hide clients bottom up */
 showhide(c->snext);
 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
 }
}


void
sigchld(int signal) {
 while(0 < waitpid(-1, NULL, WNOHANG));
}

void
spawn(const Arg *arg) {
 signal(SIGCHLD, sigchld);
 if(fork() == 0) {
 if(dpy)
 close(ConnectionNumber(dpy));
 setsid();
 execvp(((char **)arg->v)[0], (char **)arg->v);
 fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
 perror(" failed");
 exit(0);
 }
}

void
tag(const Arg *arg) {
 if(sel && arg->ui & TAGMASK) {
 sel->tags = arg->ui & TAGMASK;
 arrange();
 }
}

int
textnw(const char *text, unsigned int len) {
 XRectangle r;

 if(dc.font.set) {
 XmbTextExtents(dc.font.set, text, len, NULL, &r);
 return r.width;
 }
 return XTextWidth(dc.font.xfont, text, len);
}

void
tile(void) {
 int x, y, h, w, mw;
 unsigned int i, n;
 Client *c;

 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next), n++);
 if(n == 0)
 return;

 /* master */
 c = nexttiled(clients);
 mw = mfact * ww;
 resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw);

 if(--n == 0)
 return;

 /* tile stack */
 x = (wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : wx + mw;
 y = wy;
 w = (wx + mw > c->x + c->w) ? wx + ww - x : ww - mw;
 h = wh / n;
 if(h < bh)
 h = wh;

 for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
 resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
 ? wy + wh - y - 2 * c->bw : h - 2 * c->bw));
 if(h != wh)
 y = c->y + HEIGHT(c);
 }
}

void
togglebar(const Arg *arg) {
 showbar = !showbar;
 updategeom();
 updatebar();
 arrange();
}

void
togglefloating(const Arg *arg) {
 if(!sel)
 return;
 sel->isfloating = !sel->isfloating || sel->isfixed;
 if(sel->isfloating)
 resize(sel, sel->x, sel->y, sel->w, sel->h);
 arrange();
}

void
toggletag(const Arg *arg) {
 unsigned int mask;

 if (!sel)
 return;
 
 mask = sel->tags ^ (arg->ui & TAGMASK);
 if(mask) {
 sel->tags = mask;
 arrange();
 }
}

void
toggleview(const Arg *arg) {
 unsigned int mask = tagset[seltags] ^ (arg->ui & TAGMASK);

 if(mask) {
 tagset[seltags] = mask;
 arrange();
 }
}

void
unmanage(Client *c) {
 XWindowChanges wc;

 wc.border_width = c->oldbw;
 /* The server grab construct avoids race conditions. */
 XGrabServer(dpy);
 XSetErrorHandler(xerrordummy);
 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
 detach(c);
 detachstack(c);
 if(sel == c)
 focus(NULL);
 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 setclientstate(c, WithdrawnState);
 free(c);
 XSync(dpy, False);
 XSetErrorHandler(xerror);
 XUngrabServer(dpy);
 arrange();
}

void
unmapnotify(XEvent *e) {
 Client *c;
 XUnmapEvent *ev = &e->xunmap;

 if((c = getclient(ev->window)))
 unmanage(c);
}

void
updatebar(void) {
 if(dc.drawable != 0)
 XFreePixmap(dpy, dc.drawable);
 dc.drawable = XCreatePixmap(dpy, root, ww, bh, DefaultDepth(dpy, screen));
 XMoveResizeWindow(dpy, barwin, wx, by, ww, bh);
}

void
updategeom(void) {
#ifdef XINERAMA
 int n, i = 0;
 XineramaScreenInfo *info = NULL;

 /* window area geometry */
 if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { 
 if(n > 1) {
 int di, x, y;
 unsigned int dui;
 Window dummy;
 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
 for(i = 0; i < n; i++)
 if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
 break;
 }
 wx = info[i].x_org;
 wy = showbar && topbar ? info[i].y_org + bh : info[i].y_org;
 ww = info[i].width;
 wh = showbar ? info[i].height - bh - BOTTOM_BAR_HEIGHT : info[i].height;
 XFree(info);
 }
 else
#endif
 {
 wx = sx;
 wy = showbar && topbar ? sy + bh : sy;
 ww = sw;
 wh = showbar ? sh - bh : sh;
 }

 /* bar position */
 by = showbar ? (topbar ? wy - bh : wy + wh) : -bh;
}

void
updatenumlockmask(void) {
 unsigned int i, j;
 XModifierKeymap *modmap;

 numlockmask = 0;
 modmap = XGetModifierMapping(dpy);
 for(i = 0; i < 8; i++)
 for(j = 0; j < modmap->max_keypermod; j++)
 if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
 numlockmask = (1 << i);
 XFreeModifiermap(modmap);
}

void
updatesizehints(Client *c) {
 long msize;
 XSizeHints size;

 if(!XGetWMNormalHints(dpy, c->win, &size, &msize))
 /* size is uninitialized, ensure that size.flags aren't used */
 size.flags = PSize; 
 if(size.flags & PBaseSize) {
 c->basew = size.base_width;
 c->baseh = size.base_height;
 }
 else if(size.flags & PMinSize) {
 c->basew = size.min_width;
 c->baseh = size.min_height;
 }
 else
 c->basew = c->baseh = 0;
 if(size.flags & PResizeInc) {
 c->incw = size.width_inc;
 c->inch = size.height_inc;
 }
 else
 c->incw = c->inch = 0;
 if(size.flags & PMaxSize) {
 c->maxw = size.max_width;
 c->maxh = size.max_height;
 }
 else
 c->maxw = c->maxh = 0;
 if(size.flags & PMinSize) {
 c->minw = size.min_width;
 c->minh = size.min_height;
 }
 else if(size.flags & PBaseSize) {
 c->minw = size.base_width;
 c->minh = size.base_height;
 }
 else
 c->minw = c->minh = 0;
 if(size.flags & PAspect) {
 c->mina = (float)size.min_aspect.y / (float)size.min_aspect.x;
 c->maxa = (float)size.max_aspect.x / (float)size.max_aspect.y;
 }
 else
 c->maxa = c->mina = 0.0;
 c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
 && c->maxw == c->minw && c->maxh == c->minh);
}

void
updatetitle(Client *c) {
 if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
}

void
updatestatus() {
 if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
 strcpy(stext, "dwm-"VERSION);
 drawbar();
}

void
updatewmhints(Client *c) {
 XWMHints *wmh;

 if((wmh = XGetWMHints(dpy, c->win))) {
 if(c == sel && wmh->flags & XUrgencyHint) {
 wmh->flags &= ~XUrgencyHint;
 XSetWMHints(dpy, c->win, wmh);
 }
 else
 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;

 XFree(wmh);
 }
}

void
view(const Arg *arg) {
 if((arg->ui & TAGMASK) == tagset[seltags])
 return;
 seltags ^= 1; /* toggle sel tagset */
 if(arg->ui & TAGMASK)
 tagset[seltags] = arg->ui & TAGMASK;
 arrange();
}

/* There's no way to check accesses to destroyed windows, thus those cases are
 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
 * default error handler, which may call exit. */
int
xerror(Display *dpy, XErrorEvent *ee) {
 if(ee->error_code == BadWindow
 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
 || (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
 return 0;
 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
 ee->request_code, ee->error_code);
 return xerrorxlib(dpy, ee); /* may call exit */
}

int
xerrordummy(Display *dpy, XErrorEvent *ee) {
 return 0;
}

/* Startup Error handler to check if another window manager
 * is already running. */
int
xerrorstart(Display *dpy, XErrorEvent *ee) {
 otherwm = True;
 return -1;
}

void
zoom(const Arg *arg) {
 Client *c = sel;

 if(!lt[sellt]->arrange || lt[sellt]->arrange == monocle || (sel && sel->isfloating))
 return;
 if(c == nexttiled(clients))
 if(!c || !(c = nexttiled(c->next)))
 return;
 detach(c);
 attach(c);
 focus(c);
 arrange();
}

int
main(int argc, char *argv[]) {
 if(argc == 2 && !strcmp("-v", argv[1]))
 die("dwm-"VERSION", ยฉ 2006-2009 dwm engineers, see LICENSE for details\n");
 else if(argc != 1)
 die("usage: dwm [-v]\n");

 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 fputs("warning: no locale support\n", stderr);

 if(!(dpy = XOpenDisplay(NULL)))
 die("dwm: cannot open display\n");

 checkotherwm();
 setup();
 scan();
 run();
 cleanup();

 XCloseDisplay(dpy);
 return 0;
}

.xinitrc

#! /bin/sh
setxkbmap -option terminate:ctrl_alt_bksp
feh --bg-scale /home/shaun/img/arch.png
conky -x 0 -y 0 -d
while true 
do
 xsetroot -name "$(date +"%a %b %d %r")"
 sleep 1s
done &
exec dwm

Last edited by zowki (2009-06-24 04:17:57)


How's my programming? Call 1-800-DEV-NULL

Offline

#2 2009-06-23 12:19:34

iphitus
Forum Fellow
From: Melbourne, Australia
Registered: 2004-10-09
Posts: 4,927

Re: Show off your Dwm configuration!

I think we've reached a new point of customisation... where people post not only their WM themes and screenshots on the forum, but the code for the WM itself...

Offline

#3 2009-06-23 12:43:49

zowki
Member
๐Ÿ‘ Image
From: Trapped in The Matrix
Registered: 2008-11-27
Posts: 582
Website

Re: Show off your Dwm configuration!

Dwm is customizable by editing it's source and recompiling it, so yeah...

PS: How do I use thumbnails in my post?

Last edited by zowki (2009-06-23 12:45:44)


How's my programming? Call 1-800-DEV-NULL

Offline

#4 2009-06-23 12:51:45

Allan
Pacman
๐Ÿ‘ Image
From: Brisbane, AU
Registered: 2007-06-09
Posts: 11,672
Website

Re: Show off your Dwm configuration!

zowki wrote:

PS: How do I use thumbnails in my post?

Look at the start of the monthly screenshot threads for instructions.

Offline

#5 2009-06-23 12:53:03

Gigamo
Member
Registered: 2008-01-19
Posts: 394

Re: Show off your Dwm configuration!

zowki wrote:

Dwm is customizable by editing it's source and recompiling it, so yeah...

PS: How do I use thumbnails in my post?

[url=http://path/to/big/image][img]http://path/to/thumbnail[/img][/url]

Offline

#6 2009-06-23 15:57:43

SpeedVin
Member
๐Ÿ‘ Image
From: Poland
Registered: 2009-04-29
Posts: 955

Re: Show off your Dwm configuration!

zowki wrote:

Welcome all dwm users! Post a screenshot of your desktop and optionally along with your configuration files.

Heres mine:

Edit: No big screenshots.  Use thumbnails instead - Allan
Clean desktop
http://shaunsite.googlepages.com/2009-0 โ€ฆ _scrot.png

Busy desktop
http://shaunsite.googlepages.com/2009-0 โ€ฆ _scrot.png

I combine the work and play workspaces to prevent myself from doing both! ๐Ÿ‘ wink

Running programs: vim, w3m, urxvt, conky
Font: Terminus

.conkyrc

own_window yes
own_window_type override
own_window_colour 000000
own_window_transparent no
own_window_hints undecorated below sticky skip_taskbar skip_pager
double_buffer yes
cpu_avg_samples 2
net_avg_samples 2
use_xft no
xftfont Terminus:size=8
update_interval 0.1
minimum_size 1280 10
maximum_width 1280
border_margin 4
border_width 1
draw_outline no
default_color white
alignment bottom_left
use_spacer right
no_buffers yes
uppercase no

TEXT
${alignc}$nodename ${color #0100ff}Uptime:${color white} $uptime ${color #0077ff}| CPU:${color #0077ff} ${color white}${cpu}%${color #0077ff} | FS: ${color lightgrey}${fs_used /}/${fs_size /}${color #0077ff} | /home: ${color lightgrey}${fs_used /home}/${fs_size /home}${color #0077ff} | RAM: ${color white}$mem ${color #0077ff}| Network:${color white} ${wireless_essid eth0} ${color #0077ff}| Down: ${color white}${downspeed eth0} ${color #0077ff}| Up: ${color white}${upspeed eth0} ${color #0077ff}| Battery: ${color white}${battery BAT1} ${battery_time BAT1} ${color #0077ff}| Volume:${color white} ${exec amixer get Master | egrep -o "[0-9]+%" | head -1 | egrep -o "[0-9]*"}%

config.h

/* See LICENSE file for copyright and license details. */

/* appearance */
#define BOTTOM_BAR_HEIGHT 13
static const char font[] = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
static const char normbordercolor[] = "#333333";
static const char normbgcolor[] = "#051121";
static const char normfgcolor[] = "#FFFFFF";
static const char selbordercolor[] = "#1793D1";
static const char selbgcolor[] = "#1793D1";
static const char selfgcolor[] = "#FFFFFF";
static unsigned int borderpx = 1; /* border pixel of windows */
static unsigned int snap = 32; /* snap pixel */
static Bool showbar = True; /* False means no bar */
static Bool topbar = True; /* False means bottom bar */

/* tagging */
static const char tags[][MAXTAGLEN] = { "web", "term/chat", "work/play", "vbox", "misc" };
static unsigned int tagset[] = {1, 1}; /* after start, first tag is selected */

static Rule rules[] = {
 /* class instance title tags mask isfloating */
 { "Gimp", NULL, NULL, NULL, True },
 { "MPlayer", NULL, NULL, NULL, True },
};

/* layout(s) */
static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
static Bool resizehints = True; /* False means respect size hints in tiled resizals */

static Layout layouts[] = {
 /* symbol arrange function */
 { "[T]", tile }, /* first entry is default */
 { "[F]", NULL }, /* no layout function means floating behavior */
 { "[M]", monocle },
};

/* key definitions */
#define MODKEY Mod1Mask
#define TAGKEYS(KEY,TAG) \
 { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
 { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
 { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
 { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "urxvt", NULL };
static const char *volup[] = {"volup", NULL};
static const char *voldwn[] = {"voldwn", NULL};
static const char *volmute[] = {"volmute", NULL};

static Key keys[] = {
 /* modifier key function argument */
 { MODKEY, XK_p, spawn, {.v = dmenucmd } },
 { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
 { MODKEY, XK_i, spawn, {.v = voldwn } },
 { MODKEY, XK_o, spawn, {.v = volup } },
 { MODKEY, XK_u, spawn, {.v = volmute } },
 { MODKEY, XK_b, togglebar, {0} },
 { MODKEY, XK_j, focusstack, {.i = +1 } },
 { MODKEY, XK_k, focusstack, {.i = -1 } },
 { MODKEY, XK_h, setmfact, {.f = -0.05} },
 { MODKEY, XK_l, setmfact, {.f = +0.05} },
 { MODKEY, XK_Return, zoom, {0} },
 { MODKEY, XK_Tab, view, {0} },
 { MODKEY|ShiftMask, XK_c, killclient, {0} },
 { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
 { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
 { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
 { MODKEY, XK_space, setlayout, {0} },
 { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
 { MODKEY, XK_0, view, {.ui = ~0 } },
 { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
 TAGKEYS( XK_1, 0)
 TAGKEYS( XK_2, 1)
 TAGKEYS( XK_3, 2)
 TAGKEYS( XK_4, 3)
 TAGKEYS( XK_5, 4)
 TAGKEYS( XK_6, 5)
 TAGKEYS( XK_7, 6)
 TAGKEYS( XK_8, 7)
 TAGKEYS( XK_9, 8)
 { MODKEY|ShiftMask, XK_q, quit, {0} },
};

/* button definitions */
/* click can be a tag number (starting at 0),
 * ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
 /* click event mask button function argument */
 { ClkLtSymbol, 0, Button1, setlayout, {0} },
 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
 { ClkWinTitle, 0, Button2, zoom, {0} },
 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
 { ClkClientWin, MODKEY, Button1, movemouse, {0} },
 { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
 { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
 { ClkTagBar, 0, Button1, view, {0} },
 { ClkTagBar, 0, Button3, toggleview, {0} },
 { ClkTagBar, MODKEY, Button1, tag, {0} },
 { ClkTagBar, MODKEY, Button3, toggletag, {0} },
};

dwm.c

/* See LICENSE file for copyright and license details.
 *
 * dynamic window manager is designed like any other X client as well. It is
 * driven through handling X events. In contrast to other X clients, a window
 * manager selects for SubstructureRedirectMask on the root window, to receive
 * events about window (dis-)appearance. Only one X connection at a time is
 * allowed to select for this event mask.
 *
 * The event handlers of dwm are organized in an array which is accessed
 * whenever a new event has been fetched. This allows event dispatching
 * in O(1) time.
 *
 * Each child of the root window is called a client, except windows which have
 * set the override_redirect flag. Clients are organized in a global
 * linked client list, the focus history is remembered through a global
 * stack list. Each client contains a bit array to indicate the tags of a
 * client.
 *
 * Keys and tagging rules are organized as arrays and defined in config.h.
 *
 * To understand everything else, start reading main().
 */
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <X11/cursorfont.h>
#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif

/* macros */
#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask))
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
#define ISVISIBLE(x) (x->tags & tagset[seltags])
#define LENGTH(x) (sizeof x / sizeof x[0])
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAXTAGLEN 16
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
#define WIDTH(x) ((x)->w + 2 * (x)->bw)
#define HEIGHT(x) ((x)->h + 2 * (x)->bw)
#define TAGMASK ((int)((1LL << LENGTH(tags)) - 1))
#define TEXTW(x) (textnw(x, strlen(x)) + dc.font.height)

/* enums */
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
enum { ColBorder, ColFG, ColBG, ColLast }; /* color */
enum { NetSupported, NetWMName, NetLast }; /* EWMH atoms */
enum { WMProtocols, WMDelete, WMState, WMLast }; /* default atoms */
enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
 ClkClientWin, ClkRootWin, ClkLast }; /* clicks */

typedef union {
 int i;
 unsigned int ui;
 float f;
 void *v;
} Arg;

typedef struct {
 unsigned int click;
 unsigned int mask;
 unsigned int button;
 void (*func)(const Arg *arg);
 const Arg arg;
} Button;

typedef struct Client Client;
struct Client {
 char name[256];
 float mina, maxa;
 int x, y, w, h;
 int basew, baseh, incw, inch, maxw, maxh, minw, minh;
 int bw, oldbw;
 unsigned int tags;
 Bool isfixed, isfloating, isurgent;
 Client *next;
 Client *snext;
 Window win;
};

typedef struct {
 int x, y, w, h;
 unsigned long norm[ColLast];
 unsigned long sel[ColLast];
 Drawable drawable;
 GC gc;
 struct {
 int ascent;
 int descent;
 int height;
 XFontSet set;
 XFontStruct *xfont;
 } font;
} DC; /* draw context */

typedef struct {
 unsigned int mod;
 KeySym keysym;
 void (*func)(const Arg *);
 const Arg arg;
} Key;

typedef struct {
 const char *symbol;
 void (*arrange)(void);
} Layout;

typedef struct {
 const char *class;
 const char *instance;
 const char *title;
 unsigned int tags;
 Bool isfloating;
} Rule;

/* function declarations */
static void applyrules(Client *c);
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h);
static void arrange(void);
static void attach(Client *c);
static void attachstack(Client *c);
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void clearurgent(Client *c);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static void die(const char *errstr, ...);
static void drawbar(void);
static void drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]);
static void drawtext(const char *text, unsigned long col[ColLast], Bool invert);
static void enternotify(XEvent *e);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusstack(const Arg *arg);
static Client *getclient(Window w);
static unsigned long getcolor(const char *colstr);
static long getstate(Window w);
static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
static void grabbuttons(Client *c, Bool focused);
static void grabkeys(void);
static void initfont(const char *fontstr);
static Bool isprotodel(Client *c);
static void keypress(XEvent *e);
static void killclient(const Arg *arg);
static void manage(Window w, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(void);
static void movemouse(const Arg *arg);
static Client *nexttiled(Client *c);
static void propertynotify(XEvent *e);
static void quit(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(void);
static void run(void);
static void scan(void);
static void setclientstate(Client *c, long state);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static void showhide(Client *c);
static void sigchld(int signal);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void tile(void);
static void togglebar(const Arg *arg);
static void togglefloating(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unmanage(Client *c);
static void unmapnotify(XEvent *e);
static void updatebar(void);
static void updategeom(void);
static void updatenumlockmask(void);
static void updatesizehints(Client *c);
static void updatestatus(void);
static void updatetitle(Client *c);
static void updatewmhints(Client *c);
static void view(const Arg *arg);
static int xerror(Display *dpy, XErrorEvent *ee);
static int xerrordummy(Display *dpy, XErrorEvent *ee);
static int xerrorstart(Display *dpy, XErrorEvent *ee);
static void zoom(const Arg *arg);

/* variables */
static char stext[256];
static int screen;
static int sx, sy, sw, sh; /* X display screen geometry x, y, width, height */ 
static int by, bh, blw; /* bar geometry y, height and layout symbol width */
static int wx, wy, ww, wh; /* window area geometry x, y, width, height, bar excluded */
static unsigned int seltags = 0, sellt = 0;
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
 [ButtonPress] = buttonpress,
 [ConfigureRequest] = configurerequest,
 [ConfigureNotify] = configurenotify,
 [DestroyNotify] = destroynotify,
 [EnterNotify] = enternotify,
 [Expose] = expose,
 [FocusIn] = focusin,
 [KeyPress] = keypress,
 [MappingNotify] = mappingnotify,
 [MapRequest] = maprequest,
 [PropertyNotify] = propertynotify,
 [UnmapNotify] = unmapnotify
};
static Atom wmatom[WMLast], netatom[NetLast];
static Bool otherwm;
static Bool running = True;
static Client *clients = NULL;
static Client *sel = NULL;
static Client *stack = NULL;
static Cursor cursor[CurLast];
static Display *dpy;
static DC dc;
static Layout *lt[] = { NULL, NULL };
static Window root, barwin;
/* configuration, allows nested code to access above variables */
#include "config.h"

/* compile-time check if all tags fit into an unsigned int bit array. */
struct NumTags { char limitexceeded[sizeof(unsigned int) * 8 < LENGTH(tags) ? -1 : 1]; };

/* function implementations */
void
applyrules(Client *c) {
 unsigned int i;
 Rule *r;
 XClassHint ch = { 0 };

 /* rule matching */
 c->isfloating = c->tags = 0;
 if(XGetClassHint(dpy, c->win, &ch)) {
 for(i = 0; i < LENGTH(rules); i++) {
 r = &rules[i];
 if((!r->title || strstr(c->name, r->title))
 && (!r->class || (ch.res_class && strstr(ch.res_class, r->class)))
 && (!r->instance || (ch.res_name && strstr(ch.res_name, r->instance)))) {
 c->isfloating = r->isfloating;
 c->tags |= r->tags; 
 }
 }
 if(ch.res_class)
 XFree(ch.res_class);
 if(ch.res_name)
 XFree(ch.res_name);
 }
 c->tags = c->tags & TAGMASK ? c->tags & TAGMASK : tagset[seltags];
}

Bool
applysizehints(Client *c, int *x, int *y, int *w, int *h) {
 Bool baseismin;

 /* set minimum possible */
 *w = MAX(1, *w);
 *h = MAX(1, *h);

 if(*x > sx + sw)
 *x = sw - WIDTH(c);
 if(*y > sy + sh)
 *y = sh - HEIGHT(c);
 if(*x + *w + 2 * c->bw < sx)
 *x = sx;
 if(*y + *h + 2 * c->bw < sy)
 *y = sy;
 if(*h < bh)
 *h = bh;
 if(*w < bh)
 *w = bh;

 if(resizehints || c->isfloating) {
 /* see last two sentences in ICCCM 4.1.2.3 */
 baseismin = c->basew == c->minw && c->baseh == c->minh;

 if(!baseismin) { /* temporarily remove base dimensions */
 *w -= c->basew;
 *h -= c->baseh;
 }

 /* adjust for aspect limits */
 if(c->mina > 0 && c->maxa > 0) {
 if(c->maxa < (float)*w / *h)
 *w = *h * c->maxa;
 else if(c->mina < (float)*h / *w)
 *h = *w * c->mina;
 }

 if(baseismin) { /* increment calculation requires this */
 *w -= c->basew;
 *h -= c->baseh;
 }

 /* adjust for increment value */
 if(c->incw)
 *w -= *w % c->incw;
 if(c->inch)
 *h -= *h % c->inch;

 /* restore base dimensions */
 *w += c->basew;
 *h += c->baseh;

 *w = MAX(*w, c->minw);
 *h = MAX(*h, c->minh);

 if(c->maxw)
 *w = MIN(*w, c->maxw);

 if(c->maxh)
 *h = MIN(*h, c->maxh);
 }
 return *x != c->x || *y != c->y || *w != c->w || *h != c->h;
}

void
arrange(void) {
 showhide(stack);
 focus(NULL);
 if(lt[sellt]->arrange)
 lt[sellt]->arrange();
 restack();
}

void
attach(Client *c) {
 c->next = clients;
 clients = c;
}

void
attachstack(Client *c) {
 c->snext = stack;
 stack = c;
}

void
buttonpress(XEvent *e) {
 unsigned int i, x, click;
 Arg arg = {0};
 Client *c;
 XButtonPressedEvent *ev = &e->xbutton;

 click = ClkRootWin;
 if(ev->window == barwin) {
 i = x = 0;
 do x += TEXTW(tags[i]); while(ev->x >= x && ++i < LENGTH(tags));
 if(i < LENGTH(tags)) {
 click = ClkTagBar;
 arg.ui = 1 << i;
 }
 else if(ev->x < x + blw)
 click = ClkLtSymbol;
 else if(ev->x > wx + ww - TEXTW(stext))
 click = ClkStatusText;
 else
 click = ClkWinTitle;
 }
 else if((c = getclient(ev->window))) {
 focus(c);
 click = ClkClientWin;
 }

 for(i = 0; i < LENGTH(buttons); i++)
 if(click == buttons[i].click && buttons[i].func && buttons[i].button == ev->button
 && CLEANMASK(buttons[i].mask) == CLEANMASK(ev->state))
 buttons[i].func(click == ClkTagBar && buttons[i].arg.i == 0 ? &arg : &buttons[i].arg);
}

void
checkotherwm(void) {
 otherwm = False;
 xerrorxlib = XSetErrorHandler(xerrorstart);

 /* this causes an error if some other window manager is running */
 XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
 XSync(dpy, False);
 if(otherwm)
 die("dwm: another window manager is already running\n");
 XSetErrorHandler(xerror);
 XSync(dpy, False);
}

void
cleanup(void) {
 Arg a = {.ui = ~0};
 Layout foo = { "", NULL };

 view(&a);
 lt[sellt] = &foo;
 while(stack)
 unmanage(stack);
 if(dc.font.set)
 XFreeFontSet(dpy, dc.font.set);
 else
 XFreeFont(dpy, dc.font.xfont);
 XUngrabKey(dpy, AnyKey, AnyModifier, root);
 XFreePixmap(dpy, dc.drawable);
 XFreeGC(dpy, dc.gc);
 XFreeCursor(dpy, cursor[CurNormal]);
 XFreeCursor(dpy, cursor[CurResize]);
 XFreeCursor(dpy, cursor[CurMove]);
 XDestroyWindow(dpy, barwin);
 XSync(dpy, False);
 XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}

void
clearurgent(Client *c) {
 XWMHints *wmh;

 c->isurgent = False;
 if(!(wmh = XGetWMHints(dpy, c->win)))
 return;
 wmh->flags &= ~XUrgencyHint;
 XSetWMHints(dpy, c->win, wmh);
 XFree(wmh);
}

void
configure(Client *c) {
 XConfigureEvent ce;

 ce.type = ConfigureNotify;
 ce.display = dpy;
 ce.event = c->win;
 ce.window = c->win;
 ce.x = c->x;
 ce.y = c->y;
 ce.width = c->w;
 ce.height = c->h;
 ce.border_width = c->bw;
 ce.above = None;
 ce.override_redirect = False;
 XSendEvent(dpy, c->win, False, StructureNotifyMask, (XEvent *)&ce);
}

void
configurenotify(XEvent *e) {
 XConfigureEvent *ev = &e->xconfigure;

 if(ev->window == root && (ev->width != sw || ev->height != sh)) {
 sw = ev->width;
 sh = ev->height;
 updategeom();
 updatebar();
 arrange();
 }
}

void
configurerequest(XEvent *e) {
 Client *c;
 XConfigureRequestEvent *ev = &e->xconfigurerequest;
 XWindowChanges wc;

 if((c = getclient(ev->window))) {
 if(ev->value_mask & CWBorderWidth)
 c->bw = ev->border_width;
 else if(c->isfloating || !lt[sellt]->arrange) {
 if(ev->value_mask & CWX)
 c->x = sx + ev->x;
 if(ev->value_mask & CWY)
 c->y = sy + ev->y;
 if(ev->value_mask & CWWidth)
 c->w = ev->width;
 if(ev->value_mask & CWHeight)
 c->h = ev->height;
 if((c->x - sx + c->w) > sw && c->isfloating)
 c->x = sx + (sw / 2 - c->w / 2); /* center in x direction */
 if((c->y - sy + c->h) > sh && c->isfloating)
 c->y = sy + (sh / 2 - c->h / 2); /* center in y direction */
 if((ev->value_mask & (CWX|CWY)) && !(ev->value_mask & (CWWidth|CWHeight)))
 configure(c);
 if(ISVISIBLE(c))
 XMoveResizeWindow(dpy, c->win, c->x, c->y, c->w, c->h);
 }
 else
 configure(c);
 }
 else {
 wc.x = ev->x;
 wc.y = ev->y;
 wc.width = ev->width;
 wc.height = ev->height;
 wc.border_width = ev->border_width;
 wc.sibling = ev->above;
 wc.stack_mode = ev->detail;
 XConfigureWindow(dpy, ev->window, ev->value_mask, &wc);
 }
 XSync(dpy, False);
}

void
destroynotify(XEvent *e) {
 Client *c;
 XDestroyWindowEvent *ev = &e->xdestroywindow;

 if((c = getclient(ev->window)))
 unmanage(c);
}

void
detach(Client *c) {
 Client **tc;

 for(tc = &clients; *tc && *tc != c; tc = &(*tc)->next);
 *tc = c->next;
}

void
detachstack(Client *c) {
 Client **tc;

 for(tc = &stack; *tc && *tc != c; tc = &(*tc)->snext);
 *tc = c->snext;
}

void
die(const char *errstr, ...) {
 va_list ap;

 va_start(ap, errstr);
 vfprintf(stderr, errstr, ap);
 va_end(ap);
 exit(EXIT_FAILURE);
}

void
drawbar(void) {
 int x;
 unsigned int i, occ = 0, urg = 0;
 unsigned long *col;
 Client *c;

 for(c = clients; c; c = c->next) {
 occ |= c->tags;
 if(c->isurgent)
 urg |= c->tags;
 }

 dc.x = 0;
 for(i = 0; i < LENGTH(tags); i++) {
 dc.w = TEXTW(tags[i]);
 col = tagset[seltags] & 1 << i ? dc.sel : dc.norm;
 drawtext(tags[i], col, urg & 1 << i);
 drawsquare(sel && sel->tags & 1 << i, occ & 1 << i, urg & 1 << i, col);
 dc.x += dc.w;
 }
 if(blw > 0) {
 dc.w = blw;
 drawtext(lt[sellt]->symbol, dc.norm, False);
 x = dc.x + dc.w;
 }
 else
 x = dc.x;
 dc.w = TEXTW(stext);
 dc.x = ww - dc.w;
 if(dc.x < x) {
 dc.x = x;
 dc.w = ww - x;
 }
 drawtext(stext, dc.norm, False);
 if((dc.w = dc.x - x) > bh) {
 dc.x = x;
 if(sel) {
 drawtext(sel->name, dc.sel, False);
 drawsquare(sel->isfixed, sel->isfloating, False, dc.sel);
 }
 else
 drawtext(NULL, dc.norm, False);
 }
 XCopyArea(dpy, dc.drawable, barwin, dc.gc, 0, 0, ww, bh, 0, 0);
 XSync(dpy, False);
}

void
drawsquare(Bool filled, Bool empty, Bool invert, unsigned long col[ColLast]) {
 int x;
 XGCValues gcv;
 XRectangle r = { dc.x, dc.y, dc.w, dc.h };

 gcv.foreground = col[invert ? ColBG : ColFG];
 XChangeGC(dpy, dc.gc, GCForeground, &gcv);
 x = (dc.font.ascent + dc.font.descent + 2) / 4;
 r.x = dc.x + 1;
 r.y = dc.y + 1;
 if(filled) {
 r.width = r.height = x + 1;
 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 }
 else if(empty) {
 r.width = r.height = x;
 XDrawRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 }
}

void
drawtext(const char *text, unsigned long col[ColLast], Bool invert) {
 char buf[256];
 int i, x, y, h, len, olen;
 XRectangle r = { dc.x, dc.y, dc.w, dc.h };

 XSetForeground(dpy, dc.gc, col[invert ? ColFG : ColBG]);
 XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
 if(!text)
 return;
 olen = strlen(text);
 h = dc.font.ascent + dc.font.descent;
 y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
 x = dc.x + (h / 2);
 /* shorten text if necessary */
 for(len = MIN(olen, sizeof buf); len && textnw(text, len) > dc.w - h; len--);
 if(!len)
 return;
 memcpy(buf, text, len);
 if(len < olen)
 for(i = len; i && i > len - 3; buf[--i] = '.');
 XSetForeground(dpy, dc.gc, col[invert ? ColBG : ColFG]);
 if(dc.font.set)
 XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
 else
 XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}

void
enternotify(XEvent *e) {
 Client *c;
 XCrossingEvent *ev = &e->xcrossing;

 if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
 return;
 if((c = getclient(ev->window)))
 focus(c);
 else
 focus(NULL);
}

void
expose(XEvent *e) {
 XExposeEvent *ev = &e->xexpose;

 if(ev->count == 0 && (ev->window == barwin))
 drawbar();
}

void
focus(Client *c) {
 if(!c || !ISVISIBLE(c))
 for(c = stack; c && !ISVISIBLE(c); c = c->snext);
 if(sel && sel != c) {
 grabbuttons(sel, False);
 XSetWindowBorder(dpy, sel->win, dc.norm[ColBorder]);
 }
 if(c) {
 if(c->isurgent)
 clearurgent(c);
 detachstack(c);
 attachstack(c);
 grabbuttons(c, True);
 XSetWindowBorder(dpy, c->win, dc.sel[ColBorder]);
 XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
 }
 else
 XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
 sel = c;
 drawbar();
}

void
focusin(XEvent *e) { /* there are some broken focus acquiring clients */
 XFocusChangeEvent *ev = &e->xfocus;

 if(sel && ev->window != sel->win)
 XSetInputFocus(dpy, sel->win, RevertToPointerRoot, CurrentTime);
}

void
focusstack(const Arg *arg) {
 Client *c = NULL, *i;

 if(!sel)
 return;
 if (arg->i > 0) {
 for(c = sel->next; c && !ISVISIBLE(c); c = c->next);
 if(!c)
 for(c = clients; c && !ISVISIBLE(c); c = c->next);
 }
 else {
 for(i = clients; i != sel; i = i->next)
 if(ISVISIBLE(i))
 c = i;
 if(!c)
 for(; i; i = i->next)
 if(ISVISIBLE(i))
 c = i;
 }
 if(c) {
 focus(c);
 restack();
 }
}

Client *
getclient(Window w) {
 Client *c;

 for(c = clients; c && c->win != w; c = c->next);
 return c;
}

unsigned long
getcolor(const char *colstr) {
 Colormap cmap = DefaultColormap(dpy, screen);
 XColor color;

 if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
 die("error, cannot allocate color '%s'\n", colstr);
 return color.pixel;
}

long
getstate(Window w) {
 int format, status;
 long result = -1;
 unsigned char *p = NULL;
 unsigned long n, extra;
 Atom real;

 status = XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
 &real, &format, &n, &extra, (unsigned char **)&p);
 if(status != Success)
 return -1;
 if(n != 0)
 result = *p;
 XFree(p);
 return result;
}

Bool
gettextprop(Window w, Atom atom, char *text, unsigned int size) {
 char **list = NULL;
 int n;
 XTextProperty name;

 if(!text || size == 0)
 return False;
 text[0] = '\0';
 XGetTextProperty(dpy, w, &name, atom);
 if(!name.nitems)
 return False;
 if(name.encoding == XA_STRING)
 strncpy(text, (char *)name.value, size - 1);
 else {
 if(XmbTextPropertyToTextList(dpy, &name, &list, &n) >= Success
 && n > 0 && *list) {
 strncpy(text, *list, size - 1);
 XFreeStringList(list);
 }
 }
 text[size - 1] = '\0';
 XFree(name.value);
 return True;
}

void
grabbuttons(Client *c, Bool focused) {
 updatenumlockmask();
 {
 unsigned int i, j;
 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 if(focused) {
 for(i = 0; i < LENGTH(buttons); i++)
 if(buttons[i].click == ClkClientWin)
 for(j = 0; j < LENGTH(modifiers); j++)
 XGrabButton(dpy, buttons[i].button, buttons[i].mask | modifiers[j], c->win, False, BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
 } else
 XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
 BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
 }
}

void
grabkeys(void) {
 updatenumlockmask();
 { /* grab keys */
 unsigned int i, j;
 unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
 KeyCode code;

 XUngrabKey(dpy, AnyKey, AnyModifier, root);
 for(i = 0; i < LENGTH(keys); i++) {
 if((code = XKeysymToKeycode(dpy, keys[i].keysym)))
 for(j = 0; j < LENGTH(modifiers); j++)
 XGrabKey(dpy, code, keys[i].mod | modifiers[j], root,
 True, GrabModeAsync, GrabModeAsync);
 }
 }
}

void
initfont(const char *fontstr) {
 char *def, **missing;
 int i, n;

 missing = NULL;
 dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
 if(missing) {
 while(n--)
 fprintf(stderr, "dwm: missing fontset: %s\n", missing[n]);
 XFreeStringList(missing);
 }
 if(dc.font.set) {
 XFontSetExtents *font_extents;
 XFontStruct **xfonts;
 char **font_names;
 dc.font.ascent = dc.font.descent = 0;
 font_extents = XExtentsOfFontSet(dc.font.set);
 n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
 for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
 dc.font.ascent = MAX(dc.font.ascent, (*xfonts)->ascent);
 dc.font.descent = MAX(dc.font.descent,(*xfonts)->descent);
 xfonts++;
 }
 }
 else {
 if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr))
 && !(dc.font.xfont = XLoadQueryFont(dpy, "fixed")))
 die("error, cannot load font: '%s'\n", fontstr);
 dc.font.ascent = dc.font.xfont->ascent;
 dc.font.descent = dc.font.xfont->descent;
 }
 dc.font.height = dc.font.ascent + dc.font.descent;
}

Bool
isprotodel(Client *c) {
 int i, n;
 Atom *protocols;
 Bool ret = False;

 if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
 for(i = 0; !ret && i < n; i++)
 if(protocols[i] == wmatom[WMDelete])
 ret = True;
 XFree(protocols);
 }
 return ret;
}

void
keypress(XEvent *e) {
 unsigned int i;
 KeySym keysym;
 XKeyEvent *ev;

 ev = &e->xkey;
 keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
 for(i = 0; i < LENGTH(keys); i++)
 if(keysym == keys[i].keysym
 && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
 && keys[i].func)
 keys[i].func(&(keys[i].arg));
}

void
killclient(const Arg *arg) {
 XEvent ev;

 if(!sel)
 return;
 if(isprotodel(sel)) {
 ev.type = ClientMessage;
 ev.xclient.window = sel->win;
 ev.xclient.message_type = wmatom[WMProtocols];
 ev.xclient.format = 32;
 ev.xclient.data.l[0] = wmatom[WMDelete];
 ev.xclient.data.l[1] = CurrentTime;
 XSendEvent(dpy, sel->win, False, NoEventMask, &ev);
 }
 else
 XKillClient(dpy, sel->win);
}

void
manage(Window w, XWindowAttributes *wa) {
 static Client cz;
 Client *c, *t = NULL;
 Window trans = None;
 XWindowChanges wc;

 if(!(c = malloc(sizeof(Client))))
 die("fatal: could not malloc() %u bytes\n", sizeof(Client));
 *c = cz;
 c->win = w;

 /* geometry */
 c->x = wa->x;
 c->y = wa->y;
 c->w = wa->width;
 c->h = wa->height;
 c->oldbw = wa->border_width;
 if(c->w == sw && c->h == sh) {
 c->x = sx;
 c->y = sy;
 c->bw = 0;
 }
 else {
 if(c->x + WIDTH(c) > sx + sw)
 c->x = sx + sw - WIDTH(c);
 if(c->y + HEIGHT(c) > sy + sh)
 c->y = sy + sh - HEIGHT(c);
 c->x = MAX(c->x, sx);
 /* only fix client y-offset, if the client center might cover the bar */
 c->y = MAX(c->y, ((by == 0) && (c->x + (c->w / 2) >= wx) && (c->x + (c->w / 2) < wx + ww)) ? bh : sy);
 c->bw = borderpx;
 }

 wc.border_width = c->bw;
 XConfigureWindow(dpy, w, CWBorderWidth, &wc);
 XSetWindowBorder(dpy, w, dc.norm[ColBorder]);
 configure(c); /* propagates border_width, if size doesn't change */
 updatesizehints(c);
 XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
 grabbuttons(c, False);
 updatetitle(c);
 if(XGetTransientForHint(dpy, w, &trans))
 t = getclient(trans);
 if(t)
 c->tags = t->tags;
 else
 applyrules(c);
 if(!c->isfloating)
 c->isfloating = trans != None || c->isfixed;
 if(c->isfloating)
 XRaiseWindow(dpy, c->win);
 attach(c);
 attachstack(c);
 XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
 XMapWindow(dpy, c->win);
 setclientstate(c, NormalState);
 arrange();
}

void
mappingnotify(XEvent *e) {
 XMappingEvent *ev = &e->xmapping;

 XRefreshKeyboardMapping(ev);
 if(ev->request == MappingKeyboard)
 grabkeys();
}

void
maprequest(XEvent *e) {
 static XWindowAttributes wa;
 XMapRequestEvent *ev = &e->xmaprequest;

 if(!XGetWindowAttributes(dpy, ev->window, &wa))
 return;
 if(wa.override_redirect)
 return;
 if(!getclient(ev->window))
 manage(ev->window, &wa);
}

void
monocle(void) {
 Client *c;

 for(c = nexttiled(clients); c; c = nexttiled(c->next)) {
 resize(c, wx, wy, ww - 2 * c->bw, wh - 2 * c->bw);
 }
}

void
movemouse(const Arg *arg) {
 int x, y, ocx, ocy, di, nx, ny;
 unsigned int dui;
 Client *c;
 Window dummy;
 XEvent ev;

 if(!(c = sel))
 return;
 restack();
 ocx = c->x;
 ocy = c->y;
 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 None, cursor[CurMove], CurrentTime) != GrabSuccess)
 return;
 XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui);
 do {
 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
 switch (ev.type) {
 case ConfigureRequest:
 case Expose:
 case MapRequest:
 handler[ev.type](&ev);
 break;
 case MotionNotify:
 nx = ocx + (ev.xmotion.x - x);
 ny = ocy + (ev.xmotion.y - y);
 if(snap && nx >= wx && nx <= wx + ww
 && ny >= wy && ny <= wy + wh) {
 if(abs(wx - nx) < snap)
 nx = wx;
 else if(abs((wx + ww) - (nx + WIDTH(c))) < snap)
 nx = wx + ww - WIDTH(c);
 if(abs(wy - ny) < snap)
 ny = wy;
 else if(abs((wy + wh) - (ny + HEIGHT(c))) < snap)
 ny = wy + wh - HEIGHT(c);
 if(!c->isfloating && lt[sellt]->arrange && (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
 togglefloating(NULL);
 }
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, nx, ny, c->w, c->h);
 break;
 }
 }
 while(ev.type != ButtonRelease);
 XUngrabPointer(dpy, CurrentTime);
}

Client *
nexttiled(Client *c) {
 for(; c && (c->isfloating || !ISVISIBLE(c)); c = c->next);
 return c;
}

void
propertynotify(XEvent *e) {
 Client *c;
 Window trans;
 XPropertyEvent *ev = &e->xproperty;

 if((ev->window == root) && (ev->atom == XA_WM_NAME))
 updatestatus();
 else if(ev->state == PropertyDelete)
 return; /* ignore */
 else if((c = getclient(ev->window))) {
 switch (ev->atom) {
 default: break;
 case XA_WM_TRANSIENT_FOR:
 XGetTransientForHint(dpy, c->win, &trans);
 if(!c->isfloating && (c->isfloating = (getclient(trans) != NULL)))
 arrange();
 break;
 case XA_WM_NORMAL_HINTS:
 updatesizehints(c);
 break;
 case XA_WM_HINTS:
 updatewmhints(c);
 drawbar();
 break;
 }
 if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
 updatetitle(c);
 if(c == sel)
 drawbar();
 }
 }
}

void
quit(const Arg *arg) {
 running = False;
}

void
resize(Client *c, int x, int y, int w, int h) {
 XWindowChanges wc;

 if(applysizehints(c, &x, &y, &w, &h)) {
 c->x = wc.x = x;
 c->y = wc.y = y;
 c->w = wc.width = w;
 c->h = wc.height = h;
 wc.border_width = c->bw;
 XConfigureWindow(dpy, c->win,
 CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
 configure(c);
 XSync(dpy, False);
 }
}

void
resizemouse(const Arg *arg) {
 int ocx, ocy;
 int nw, nh;
 Client *c;
 XEvent ev;

 if(!(c = sel))
 return;
 restack();
 ocx = c->x;
 ocy = c->y;
 if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
 None, cursor[CurResize], CurrentTime) != GrabSuccess)
 return;
 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
 do {
 XMaskEvent(dpy, MOUSEMASK|ExposureMask|SubstructureRedirectMask, &ev);
 switch(ev.type) {
 case ConfigureRequest:
 case Expose:
 case MapRequest:
 handler[ev.type](&ev);
 break;
 case MotionNotify:
 nw = MAX(ev.xmotion.x - ocx - 2 * c->bw + 1, 1);
 nh = MAX(ev.xmotion.y - ocy - 2 * c->bw + 1, 1);

 if(snap && nw >= wx && nw <= wx + ww
 && nh >= wy && nh <= wy + wh) {
 if(!c->isfloating && lt[sellt]->arrange
 && (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
 togglefloating(NULL);
 }
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, c->x, c->y, nw, nh);
 break;
 }
 }
 while(ev.type != ButtonRelease);
 XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
 XUngrabPointer(dpy, CurrentTime);
 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
restack(void) {
 Client *c;
 XEvent ev;
 XWindowChanges wc;

 drawbar();
 if(!sel)
 return;
 if(sel->isfloating || !lt[sellt]->arrange)
 XRaiseWindow(dpy, sel->win);
 if(lt[sellt]->arrange) {
 wc.stack_mode = Below;
 wc.sibling = barwin;
 for(c = stack; c; c = c->snext)
 if(!c->isfloating && ISVISIBLE(c)) {
 XConfigureWindow(dpy, c->win, CWSibling|CWStackMode, &wc);
 wc.sibling = c->win;
 }
 }
 XSync(dpy, False);
 while(XCheckMaskEvent(dpy, EnterWindowMask, &ev));
}

void
run(void) {
 XEvent ev;

 /* main event loop */
 XSync(dpy, False);
 while(running && !XNextEvent(dpy, &ev)) {
 if(handler[ev.type])
 (handler[ev.type])(&ev); /* call handler */
 }
}

void
scan(void) {
 unsigned int i, num;
 Window d1, d2, *wins = NULL;
 XWindowAttributes wa;

 if(XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
 for(i = 0; i < num; i++) {
 if(!XGetWindowAttributes(dpy, wins[i], &wa)
 || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
 continue;
 if(wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
 manage(wins[i], &wa);
 }
 for(i = 0; i < num; i++) { /* now the transients */
 if(!XGetWindowAttributes(dpy, wins[i], &wa))
 continue;
 if(XGetTransientForHint(dpy, wins[i], &d1)
 && (wa.map_state == IsViewable || getstate(wins[i]) == IconicState))
 manage(wins[i], &wa);
 }
 if(wins)
 XFree(wins);
 }
}

void
setclientstate(Client *c, long state) {
 long data[] = {state, None};

 XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
 PropModeReplace, (unsigned char *)data, 2);
}

void
setlayout(const Arg *arg) {
 if(!arg || !arg->v || arg->v != lt[sellt])
 sellt ^= 1;
 if(arg && arg->v)
 lt[sellt] = (Layout *)arg->v;
 if(sel)
 arrange();
 else
 drawbar();
}

/* arg > 1.0 will set mfact absolutly */
void
setmfact(const Arg *arg) {
 float f;

 if(!arg || !lt[sellt]->arrange)
 return;
 f = arg->f < 1.0 ? arg->f + mfact : arg->f - 1.0;
 if(f < 0.1 || f > 0.9)
 return;
 mfact = f;
 arrange();
}

void
setup(void) {
 unsigned int i;
 int w;
 XSetWindowAttributes wa;

 /* init screen */
 screen = DefaultScreen(dpy);
 root = RootWindow(dpy, screen);
 initfont(font);
 sx = 0;
 sy = 0;
 sw = DisplayWidth(dpy, screen);
 sh = DisplayHeight(dpy, screen);
 bh = dc.h = dc.font.height + 2;
 lt[0] = &layouts[0];
 lt[1] = &layouts[1 % LENGTH(layouts)];
 updategeom();

 /* init atoms */
 wmatom[WMProtocols] = XInternAtom(dpy, "WM_PROTOCOLS", False);
 wmatom[WMDelete] = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 wmatom[WMState] = XInternAtom(dpy, "WM_STATE", False);
 netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
 netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);

 /* init cursors */
 wa.cursor = cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
 cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
 cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);

 /* init appearance */
 dc.norm[ColBorder] = getcolor(normbordercolor);
 dc.norm[ColBG] = getcolor(normbgcolor);
 dc.norm[ColFG] = getcolor(normfgcolor);
 dc.sel[ColBorder] = getcolor(selbordercolor);
 dc.sel[ColBG] = getcolor(selbgcolor);
 dc.sel[ColFG] = getcolor(selfgcolor);
 dc.drawable = XCreatePixmap(dpy, root, DisplayWidth(dpy, screen), bh, DefaultDepth(dpy, screen));
 dc.gc = XCreateGC(dpy, root, 0, NULL);
 XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
 if(!dc.font.set)
 XSetFont(dpy, dc.gc, dc.font.xfont->fid);

 /* init bar */
 for(blw = i = 0; LENGTH(layouts) > 1 && i < LENGTH(layouts); i++) {
 w = TEXTW(layouts[i].symbol);
 blw = MAX(blw, w);
 }

 wa.override_redirect = True;
 wa.background_pixmap = ParentRelative;
 wa.event_mask = ButtonPressMask|ExposureMask;

 barwin = XCreateWindow(dpy, root, wx, by, ww, bh, 0, DefaultDepth(dpy, screen),
 CopyFromParent, DefaultVisual(dpy, screen),
 CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
 XDefineCursor(dpy, barwin, cursor[CurNormal]);
 XMapRaised(dpy, barwin);
 updatestatus();

 /* EWMH support per view */
 XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
 PropModeReplace, (unsigned char *) netatom, NetLast);

 /* select for events */
 wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
 |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
 |PropertyChangeMask;
 XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
 XSelectInput(dpy, root, wa.event_mask);

 grabkeys();
}

void
showhide(Client *c) {
 if(!c)
 return;
 if(ISVISIBLE(c)) { /* show clients top down */
 XMoveWindow(dpy, c->win, c->x, c->y);
 if(!lt[sellt]->arrange || c->isfloating)
 resize(c, c->x, c->y, c->w, c->h);
 showhide(c->snext);
 }
 else { /* hide clients bottom up */
 showhide(c->snext);
 XMoveWindow(dpy, c->win, c->x + 2 * sw, c->y);
 }
}


void
sigchld(int signal) {
 while(0 < waitpid(-1, NULL, WNOHANG));
}

void
spawn(const Arg *arg) {
 signal(SIGCHLD, sigchld);
 if(fork() == 0) {
 if(dpy)
 close(ConnectionNumber(dpy));
 setsid();
 execvp(((char **)arg->v)[0], (char **)arg->v);
 fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
 perror(" failed");
 exit(0);
 }
}

void
tag(const Arg *arg) {
 if(sel && arg->ui & TAGMASK) {
 sel->tags = arg->ui & TAGMASK;
 arrange();
 }
}

int
textnw(const char *text, unsigned int len) {
 XRectangle r;

 if(dc.font.set) {
 XmbTextExtents(dc.font.set, text, len, NULL, &r);
 return r.width;
 }
 return XTextWidth(dc.font.xfont, text, len);
}

void
tile(void) {
 int x, y, h, w, mw;
 unsigned int i, n;
 Client *c;

 for(n = 0, c = nexttiled(clients); c; c = nexttiled(c->next), n++);
 if(n == 0)
 return;

 /* master */
 c = nexttiled(clients);
 mw = mfact * ww;
 resize(c, wx, wy, (n == 1 ? ww : mw) - 2 * c->bw, wh - 2 * c->bw);

 if(--n == 0)
 return;

 /* tile stack */
 x = (wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : wx + mw;
 y = wy;
 w = (wx + mw > c->x + c->w) ? wx + ww - x : ww - mw;
 h = wh / n;
 if(h < bh)
 h = wh;

 for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
 resize(c, x, y, w - 2 * c->bw, /* remainder */ ((i + 1 == n)
 ? wy + wh - y - 2 * c->bw : h - 2 * c->bw));
 if(h != wh)
 y = c->y + HEIGHT(c);
 }
}

void
togglebar(const Arg *arg) {
 showbar = !showbar;
 updategeom();
 updatebar();
 arrange();
}

void
togglefloating(const Arg *arg) {
 if(!sel)
 return;
 sel->isfloating = !sel->isfloating || sel->isfixed;
 if(sel->isfloating)
 resize(sel, sel->x, sel->y, sel->w, sel->h);
 arrange();
}

void
toggletag(const Arg *arg) {
 unsigned int mask;

 if (!sel)
 return;
 
 mask = sel->tags ^ (arg->ui & TAGMASK);
 if(mask) {
 sel->tags = mask;
 arrange();
 }
}

void
toggleview(const Arg *arg) {
 unsigned int mask = tagset[seltags] ^ (arg->ui & TAGMASK);

 if(mask) {
 tagset[seltags] = mask;
 arrange();
 }
}

void
unmanage(Client *c) {
 XWindowChanges wc;

 wc.border_width = c->oldbw;
 /* The server grab construct avoids race conditions. */
 XGrabServer(dpy);
 XSetErrorHandler(xerrordummy);
 XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
 detach(c);
 detachstack(c);
 if(sel == c)
 focus(NULL);
 XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
 setclientstate(c, WithdrawnState);
 free(c);
 XSync(dpy, False);
 XSetErrorHandler(xerror);
 XUngrabServer(dpy);
 arrange();
}

void
unmapnotify(XEvent *e) {
 Client *c;
 XUnmapEvent *ev = &e->xunmap;

 if((c = getclient(ev->window)))
 unmanage(c);
}

void
updatebar(void) {
 if(dc.drawable != 0)
 XFreePixmap(dpy, dc.drawable);
 dc.drawable = XCreatePixmap(dpy, root, ww, bh, DefaultDepth(dpy, screen));
 XMoveResizeWindow(dpy, barwin, wx, by, ww, bh);
}

void
updategeom(void) {
#ifdef XINERAMA
 int n, i = 0;
 XineramaScreenInfo *info = NULL;

 /* window area geometry */
 if(XineramaIsActive(dpy) && (info = XineramaQueryScreens(dpy, &n))) { 
 if(n > 1) {
 int di, x, y;
 unsigned int dui;
 Window dummy;
 if(XQueryPointer(dpy, root, &dummy, &dummy, &x, &y, &di, &di, &dui))
 for(i = 0; i < n; i++)
 if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
 break;
 }
 wx = info[i].x_org;
 wy = showbar && topbar ? info[i].y_org + bh : info[i].y_org;
 ww = info[i].width;
 wh = showbar ? info[i].height - bh - BOTTOM_BAR_HEIGHT : info[i].height;
 XFree(info);
 }
 else
#endif
 {
 wx = sx;
 wy = showbar && topbar ? sy + bh : sy;
 ww = sw;
 wh = showbar ? sh - bh : sh;
 }

 /* bar position */
 by = showbar ? (topbar ? wy - bh : wy + wh) : -bh;
}

void
updatenumlockmask(void) {
 unsigned int i, j;
 XModifierKeymap *modmap;

 numlockmask = 0;
 modmap = XGetModifierMapping(dpy);
 for(i = 0; i < 8; i++)
 for(j = 0; j < modmap->max_keypermod; j++)
 if(modmap->modifiermap[i * modmap->max_keypermod + j] == XKeysymToKeycode(dpy, XK_Num_Lock))
 numlockmask = (1 << i);
 XFreeModifiermap(modmap);
}

void
updatesizehints(Client *c) {
 long msize;
 XSizeHints size;

 if(!XGetWMNormalHints(dpy, c->win, &size, &msize))
 /* size is uninitialized, ensure that size.flags aren't used */
 size.flags = PSize; 
 if(size.flags & PBaseSize) {
 c->basew = size.base_width;
 c->baseh = size.base_height;
 }
 else if(size.flags & PMinSize) {
 c->basew = size.min_width;
 c->baseh = size.min_height;
 }
 else
 c->basew = c->baseh = 0;
 if(size.flags & PResizeInc) {
 c->incw = size.width_inc;
 c->inch = size.height_inc;
 }
 else
 c->incw = c->inch = 0;
 if(size.flags & PMaxSize) {
 c->maxw = size.max_width;
 c->maxh = size.max_height;
 }
 else
 c->maxw = c->maxh = 0;
 if(size.flags & PMinSize) {
 c->minw = size.min_width;
 c->minh = size.min_height;
 }
 else if(size.flags & PBaseSize) {
 c->minw = size.base_width;
 c->minh = size.base_height;
 }
 else
 c->minw = c->minh = 0;
 if(size.flags & PAspect) {
 c->mina = (float)size.min_aspect.y / (float)size.min_aspect.x;
 c->maxa = (float)size.max_aspect.x / (float)size.max_aspect.y;
 }
 else
 c->maxa = c->mina = 0.0;
 c->isfixed = (c->maxw && c->minw && c->maxh && c->minh
 && c->maxw == c->minw && c->maxh == c->minh);
}

void
updatetitle(Client *c) {
 if(!gettextprop(c->win, netatom[NetWMName], c->name, sizeof c->name))
 gettextprop(c->win, XA_WM_NAME, c->name, sizeof c->name);
}

void
updatestatus() {
 if(!gettextprop(root, XA_WM_NAME, stext, sizeof(stext)))
 strcpy(stext, "dwm-"VERSION);
 drawbar();
}

void
updatewmhints(Client *c) {
 XWMHints *wmh;

 if((wmh = XGetWMHints(dpy, c->win))) {
 if(c == sel && wmh->flags & XUrgencyHint) {
 wmh->flags &= ~XUrgencyHint;
 XSetWMHints(dpy, c->win, wmh);
 }
 else
 c->isurgent = (wmh->flags & XUrgencyHint) ? True : False;

 XFree(wmh);
 }
}

void
view(const Arg *arg) {
 if((arg->ui & TAGMASK) == tagset[seltags])
 return;
 seltags ^= 1; /* toggle sel tagset */
 if(arg->ui & TAGMASK)
 tagset[seltags] = arg->ui & TAGMASK;
 arrange();
}

/* There's no way to check accesses to destroyed windows, thus those cases are
 * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
 * default error handler, which may call exit. */
int
xerror(Display *dpy, XErrorEvent *ee) {
 if(ee->error_code == BadWindow
 || (ee->request_code == X_SetInputFocus && ee->error_code == BadMatch)
 || (ee->request_code == X_PolyText8 && ee->error_code == BadDrawable)
 || (ee->request_code == X_PolyFillRectangle && ee->error_code == BadDrawable)
 || (ee->request_code == X_PolySegment && ee->error_code == BadDrawable)
 || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch)
 || (ee->request_code == X_GrabButton && ee->error_code == BadAccess)
 || (ee->request_code == X_GrabKey && ee->error_code == BadAccess)
 || (ee->request_code == X_CopyArea && ee->error_code == BadDrawable))
 return 0;
 fprintf(stderr, "dwm: fatal error: request code=%d, error code=%d\n",
 ee->request_code, ee->error_code);
 return xerrorxlib(dpy, ee); /* may call exit */
}

int
xerrordummy(Display *dpy, XErrorEvent *ee) {
 return 0;
}

/* Startup Error handler to check if another window manager
 * is already running. */
int
xerrorstart(Display *dpy, XErrorEvent *ee) {
 otherwm = True;
 return -1;
}

void
zoom(const Arg *arg) {
 Client *c = sel;

 if(!lt[sellt]->arrange || lt[sellt]->arrange == monocle || (sel && sel->isfloating))
 return;
 if(c == nexttiled(clients))
 if(!c || !(c = nexttiled(c->next)))
 return;
 detach(c);
 attach(c);
 focus(c);
 arrange();
}

int
main(int argc, char *argv[]) {
 if(argc == 2 && !strcmp("-v", argv[1]))
 die("dwm-"VERSION", ยฉ 2006-2009 dwm engineers, see LICENSE for details\n");
 else if(argc != 1)
 die("usage: dwm [-v]\n");

 if(!setlocale(LC_CTYPE, "") || !XSupportsLocale())
 fputs("warning: no locale support\n", stderr);

 if(!(dpy = XOpenDisplay(NULL)))
 die("dwm: cannot open display\n");

 checkotherwm();
 setup();
 scan();
 run();
 cleanup();

 XCloseDisplay(dpy);
 return 0;
}

Hello
Do you start your wallpaper at startx , if yes how do you do that?


Shell Scripter | C/C++/Python/Java Coder | ZSH

Offline

#7 2009-06-23 16:53:09

TjPhysicist
Member
From: Waterloo, Canada
Registered: 2008-04-12
Posts: 126
Website

Re: Show off your Dwm configuration!

@SpeedVin: use feh, just put in exec feh --bg-scale <path to jpeg> in your .xinitrc
Now onto my dwm config, here it is. I had more changes before to incorprate some stuff like per tag modes (if one if in tiling and i switch to another that is in max mode then when i switch back it becomes tiling). Anyways this now comes defaults on 5.5 i think. here is my config.h

/* See LICENSE file for copyright and license details. */
#include <X11/XF86keysym.h>

/* appearance */
static const char font[] = "-*-terminus-medium-r-normal-*-14-*-*-*-*-*-*-*";
static const char normbordercolor[] = "#cccccc";
static const char normbgcolor[] = "#000000";
static const char normfgcolor[] = "#ffffff";
static const char selbordercolor[] = "#0066ff";
static const char selbgcolor[] = "#0066ff";
static const char selfgcolor[] = "#ffffff";
static unsigned int borderpx = 1; /* border pixel of windows */
static unsigned int snap = 32; /* snap pixel */
static Bool showbar = True; /* False means no bar */
static Bool topbar = True; /* False means bottom bar */
static Bool readin = True; /* False means do not read stdin */
static Bool usegrab = False; //true means grab X during mouse resizals
/* tagging */
static const char tags[][MAXTAGLEN] = { "reg", "browse", "FF", "chat", "5", "6", "7", "8", "9" };
static unsigned int tagset[] = {1, 1}; /* after start, first tag is selected */

static Rule rules[] = {
 /* class instance title tags mask isfloating */
 { "Gimp", NULL, NULL, 0, True },
 { "Firefox", NULL, NULL, 1 << 2, False },
 { "firefox", NULL, NULL, 1 << 2, False },
 { NULL, NULL, "Vimperator",1 << 2, False},
 { "*MPlayer*", NULL, NULL, 0, True},
 { "MPlayer", NULL, NULL, 0, True},
 { "GNOME MPlayer", NULL, NULL, 0, True},
 { "*.pdf", NULL, NULL, 0, True},
};

/* layout(s) */
static float mfact = 0.90; /* factor of master area size [0.05..0.95] */
static Bool resizehints = False; /* False means respect size hints in tiled resizals */
static Layout layouts[] = {
 /* symbol arrange function */
 { "[T]=", tile }, /* first entry is default */
 { "[F]=", NULL }, /* no layout function means floating behavior */
 { "[M]=", monocle },
};

/* key definitions */
#define MODKEY Mod1Mask
#define WINKEY Mod4Mask
#define NONKEY 0
#define TAGKEYS(KEY,TAG) \
 { 0, KEY, view, {.ui = 1 << TAG} }, \
 { 0|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
 { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
 { MODKEY, KEY, toggletag, {.ui = 1 << TAG} },\

/* helper for spawning shell commands in the pre dwm-5.0 fashion */
//#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }

/* commands */
static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
static const char *termcmd[] = { "urxvt", "-e", "screenie", NULL };
static const char *bmenucmd[] = { "dmenu_bk", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };

//static const char *raisevol[] = {"vol", "-q", "set", "PCM", "2+", NULL};
//static const char *lowervol[] = {"amixer", "-q set","PCM", "2-", NULL};




static Key keys[] = {
 /* modifier key function argument */
 { MODKEY, XK_p, spawn, {.v = dmenucmd } },
 { WINKEY, XK_t, spawn, {.v = termcmd } },
 { MODKEY, XK_b, togglebar, {0} },
 { MODKEY, XK_a, spawn, {.v = bmenucmd } },
 { MODKEY, XK_j, focusstack, {.i = +1 } },
 { MODKEY, XK_k, focusstack, {.i = -1 } },
 { MODKEY, XK_h, setmfact, {.f = -0.05} },
 { MODKEY, XK_l, setmfact, {.f = +0.05} },
 { MODKEY, XK_Tab, zoom, {0} },
 { MODKEY, XK_F4, killclient, {0} },
 { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
 { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
 { MODKEY, XK_Return, setlayout, {.v = &layouts[2]} },
 { MODKEY, XK_space, setlayout, {0} },
 { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
 { MODKEY, XK_0, view, {.ui = ~0 } },
 { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
 TAGKEYS( XK_F1, 0)
 TAGKEYS( XK_F2, 1)
 TAGKEYS( XK_F3, 2)
 TAGKEYS( XK_F4, 3)
 TAGKEYS( XK_F5, 4)
 TAGKEYS( XK_F6, 5)
 TAGKEYS( XK_F7, 6)
 TAGKEYS( XK_F8, 7)
 TAGKEYS( XK_F9, 8)
 { MODKEY|ShiftMask, XK_q, quit, {0} }
};

/* button definitions */
/* click can be a tag number (starting at 0),
 * ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
static Button buttons[] = {
 /* click event mask button function argument */
 { ClkLtSymbol, 0, Button1, setlayout, {0} },
 { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
 { ClkWinTitle, 0, Button2, zoom, {0} },
 { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
 { ClkClientWin, MODKEY, Button1, movemouse, {0} },
 { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
 { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
 { ClkTagBar, 0, Button1, view, {0} },
 { ClkTagBar, 0, Button3, toggleview, {0} },
 { ClkTagBar, MODKEY, Button1, tag, {0} },
 { ClkTagBar, MODKEY, Button3, toggletag, {0} },
};

and here is dmenu_bk (same as dmenu_run with a different path)

#!/bin/sh
cd /etc/wmii-3.5
exe=`bk_path | dmenu ${1+"$@"}` && exec /etc/wmii-3.5/$exe

...and bk_path is...

#!/bin/bash
CACHE=$HOME/.dmenu_book
IFS=:

uptodate() {
 test -f "$CACHE" &&
 for dir in /home/tharihar/.Bin
 do
 test ! $dir -nt "$CACHE" || return 1
 done
}

if ! uptodate
then
 for dir in /home/tharihar/.Bin
 do
 cd "$dir" &&
 for file in *
 do
 test -x "$file" && echo "$file"
 done
 done | sort | uniq > $CACHE.$$
 mv "$CACHE".$$ "$CACHE"
fi

cat "$CACHE"

No changes made to vanilla dwm.c after 5.3.

Last edited by TjPhysicist (2009-06-23 16:58:08)


-Tj
Now reborn as Tjh_ (to keep it similar to my username in other places)

Offline

#8 2009-06-23 16:56:50

SpeedVin
Member
๐Ÿ‘ Image
From: Poland
Registered: 2009-04-29
Posts: 955

Re: Show off your Dwm configuration!

TjPhysicist wrote:

@SpeedVin: use feh, just put in exec feh --bg-scale <path to jpeg> in your .xinitrc

I just do that and it's doesen't work hmm maybe i have to put sleep 1 comand in my .xinitrc?

Last edited by SpeedVin (2009-06-23 16:57:41)


Shell Scripter | C/C++/Python/Java Coder | ZSH

Offline

#9 2009-06-23 17:00:21

TjPhysicist
Member
From: Waterloo, Canada
Registered: 2008-04-12
Posts: 126
Website

Re: Show off your Dwm configuration!

here is my .xinitrc

#!/bin/sh
# $Xorg: xinitrc.cpp,v 1.3 2000/08/17 19:54:30 cpqbld Exp $

userresources=$HOME/.Xresources
usermodmap=$HOME/.Xmodmap
sysresources=/etc/X11/xinit/.Xresources
sysmodmap=/etc/X11/xinit/.Xmodmap

# merge in defaults and keymaps

if [ -f $sysresources ]; then
 xrdb -merge $sysresources
fi

if [ -f $sysmodmap ]; then
 xmodmap $sysmodmap
fi

if [ -f $userresources ]; then
 xrdb -merge $userresources
fi

if [ -f $usermodmap ]; then
 xmodmap $usermodmap
fi

# start some nice programs
#sudo mount -a > /dev/null 2>&1
xbindkeys &
wallpaper > /dev/null
feh --bg-scale /home/tharihar/.wallpaper.jpg
/etc/X11/Xsession
#checkgmail &
#enlightenment_start

while true
do
 xsetroot -name "$(/home/tharihar/.Bin/dwmstatus)"
done &

#gnome-session &
#xclock -geometry 50x50-1+1 &
#gnome-terminal -geometry 80x50+494+51 &
#xterm -geometry 80x20+494-0 &
#exec xterm -geometry 80x66+0+0 -name login

Note wallpaper is a script that copies a random picture from my Pictures folder over to .wallpaper.jpg (so i have changing wallpaper on every boot/startx).


-Tj
Now reborn as Tjh_ (to keep it similar to my username in other places)

Offline

#10 2009-06-23 17:06:49

SpeedVin
Member
๐Ÿ‘ Image
From: Poland
Registered: 2009-04-29
Posts: 955

Re: Show off your Dwm configuration!

Ok that's works thanks TjPhysicist.


Shell Scripter | C/C++/Python/Java Coder | ZSH

Offline

#11 2009-06-23 17:18:18

Barghest
Member
From: Hanau/Germany
Registered: 2008-01-03
Posts: 563

Re: Show off your Dwm configuration!

TjPhysicist wrote:

@SpeedVin: use feh, just put in exec feh --bg-scale <path to jpeg> in your .xinitrc
Now onto my dwm config, here it is. I had more changes before to incorprate some stuff like per tag modes (if one if in tiling and i switch to another that is in max mode then when i switch back it becomes tiling). Anyways this now comes defaults on 5.5 i think. here is my config.h

Just tested 5.5 and pertag doesn't come by default and the pertag patch (for 5.4) isn't working anymore. ๐Ÿ‘ sad

Offline

#12 2009-06-24 04:12:43

zowki
Member
๐Ÿ‘ Image
From: Trapped in The Matrix
Registered: 2008-11-27
Posts: 582
Website

Re: Show off your Dwm configuration!

OK, got my thumbnails working! I also added my .xinitrc for those who want to know how to use a wallpaper.


How's my programming? Call 1-800-DEV-NULL

Offline

#13 2009-06-24 04:38:28

thayer
Fellow
๐Ÿ‘ Image
From: Vancouver, BC
Registered: 2007-05-20
Posts: 1,560
Website

Re: Show off your Dwm configuration!

๐Ÿ‘ thumb-20090621-3647748995.png

dwm, urxvt, screen, mutt...most configs are here: thttp://bit.ly/eXN8eB

Last edited by thayer (2011-02-08 00:15:12)


thayer williams ~ thayerwilliams.ca

Offline

#14 2009-06-24 05:57:50

TjPhysicist
Member
From: Waterloo, Canada
Registered: 2008-04-12
Posts: 126
Website

Re: Show off your Dwm configuration!

Barghest wrote:
TjPhysicist wrote:

@SpeedVin: use feh, just put in exec feh --bg-scale <path to jpeg> in your .xinitrc
Now onto my dwm config, here it is. I had more changes before to incorprate some stuff like per tag modes (if one if in tiling and i switch to another that is in max mode then when i switch back it becomes tiling). Anyways this now comes defaults on 5.5 i think. here is my config.h

Just tested 5.5 and pertag doesn't come by default and the pertag patch (for 5.4) isn't working anymore. ๐Ÿ‘ sad

strange,... ur right...i thought the changelog said smthg about including it in 5.5. O well, time to patch the patch again .. ๐Ÿ‘ smile
. I'll let you know when im done (i have 2 tests this week, so probably after)


-Tj
Now reborn as Tjh_ (to keep it similar to my username in other places)

Offline

#15 2009-06-24 10:51:04

cdwillis
Member
๐Ÿ‘ Image
From: /home/usa
Registered: 2008-11-20
Posts: 294

Re: Show off your Dwm configuration!

I've been tinkering with dwm tonight. This is what I have so far:

๐Ÿ‘ KUxcZl.png

I'm having a little trouble getting conky to play nice with the top dwm bar :\

Offline

#16 2009-06-24 22:16:15

droog
Member
๐Ÿ‘ Image
Registered: 2004-11-18
Posts: 877

Re: Show off your Dwm configuration!

TjPhysicist wrote:
Barghest wrote:
TjPhysicist wrote:

Just tested 5.5 and pertag doesn't come by default and the pertag patch (for 5.4) isn't working anymore. ๐Ÿ‘ sad

strange,... ur right...i thought the changelog said smthg about including it in 5.5. O well, time to patch the patch again .. ๐Ÿ‘ smile
. I'll let you know when im done (i have 2 tests this week, so probably after)

5.4-pertag works fine here on 5.5. if you're using multiple patches maybe apply them in a different order?

Applied it and re-diffed it so won't have the 15 line difference maybe it'll help.
http://two.xthost.info/navi/dwm/pertag-5.5.diff

/edit
nice shots ๐Ÿ‘ smile

Last edited by droog (2009-06-24 22:41:56)

Offline

#17 2009-06-26 13:50:31

zowki
Member
๐Ÿ‘ Image
From: Trapped in The Matrix
Registered: 2008-11-27
Posts: 582
Website

Re: Show off your Dwm configuration!

cdwillis, what is that program you used in your terminal to show that tux ascii art?


How's my programming? Call 1-800-DEV-NULL

Offline

#18 2009-06-26 18:52:03

Lexion
Member
๐Ÿ‘ Image
Registered: 2008-03-23
Posts: 510

Re: Show off your Dwm configuration!

zowki: it's called cowsay and it's in the repos.


urxvtc / wmii / zsh / configs / onebluecat.net
Arch will not hold your hand

Offline

#19 2009-06-26 22:32:05

portix
Member
Registered: 2009-01-13
Posts: 757

Re: Show off your Dwm configuration!

๐Ÿ‘ tMXZ5NQ

dwm-4.9 urxvt ncmpcpp mutt

Offline

#20 2009-06-27 01:36:34

nucleuswizard
Member
๐Ÿ‘ Image
From: Serbia
Registered: 2007-10-07
Posts: 79

Re: Show off your Dwm configuration!

@zowki
Could you post your scripts for volup,voldwn and volmute.Thanks

Offline

#21 2009-06-27 07:01:17

zowki
Member
๐Ÿ‘ Image
From: Trapped in The Matrix
Registered: 2008-11-27
Posts: 582
Website

Re: Show off your Dwm configuration!

nucleuswizard wrote:

@zowki
Could you post your scripts for volup,voldwn and volmute.Thanks

volup

amixer set Master 5%+

voldwn

amixer set Master 5%-

volmute

amixer set Master toggle

How's my programming? Call 1-800-DEV-NULL

Offline

#22 2009-07-01 00:55:06

FallenWizard
Member
๐Ÿ‘ Image
From: Vienna/ Austria
Registered: 2007-12-10
Posts: 99

Re: Show off your Dwm configuration!

nothing special

๐Ÿ‘ tMXdsMg

config at http://github.com/fallenwizard

Last edited by FallenWizard (2009-07-01 00:55:58)

Offline

#23 2009-07-01 02:06:47

cdwillis
Member
๐Ÿ‘ Image
From: /home/usa
Registered: 2008-11-20
Posts: 294

Re: Show off your Dwm configuration!

Nice setup FallenWizard

I changed the font to Dina, switched up the terminal colors and then fixed the menu bar colors to fit them:

๐Ÿ‘ ZRQTKs.png

Offline

#24 2009-07-01 02:43:30

TjPhysicist
Member
From: Waterloo, Canada
Registered: 2008-04-12
Posts: 126
Website

Re: Show off your Dwm configuration!

droog wrote:
TjPhysicist wrote:

strange,... ur right...i thought the changelog said smthg about including it in 5.5. O well, time to patch the patch again .. ๐Ÿ‘ smile
. I'll let you know when im done (i have 2 tests this week, so probably after)

5.4-pertag works fine here on 5.5. if you're using multiple patches maybe apply them in a different order?

Applied it and re-diffed it so won't have the 15 line difference maybe it'll help.
http://two.xthost.info/navi/dwm/pertag-5.5.diff

/edit
nice shots ๐Ÿ‘ smile

O i see, i guess i'll do that.

O also fgot to post latest screenshots...
Image

also I have added `tp` to the echo in dwmstatus file (for display in the bar). tp is:

#!bin/bash
echo -e "scale = 3 \n ($((($(date +%s) - $(date +%s -d $(date +%D))))) * 1.8550948*10^43)/(10^46)" | bc

This is influenced by the Kilosecond thread and wikipage, it displays the time in planck. (well Yota-zeta planck, i.e. 10^46planck times).

Last edited by TjPhysicist (2009-07-01 02:53:57)


-Tj
Now reborn as Tjh_ (to keep it similar to my username in other places)

Offline

#25 2009-07-01 13:12:27

SpeedVin
Member
๐Ÿ‘ Image
From: Poland
Registered: 2009-04-29
Posts: 955

Re: Show off your Dwm configuration!

zowki wrote:

Welcome all dwm users! Post a screenshot of your desktop and optionally along with your configuration files.

Heres mine:

Clean desktop
http://shaunsite.googlepages.com/thumb2.png

Busy desktop
http://shaunsite.googlepages.com/thumb1.png

I combine the work and play workspaces to prevent myself from doing both! ๐Ÿ‘ wink

Running programs: vim, w3m, urxvt, conky
Font: Terminus

I have question to you how do you dmenu like this please share your config ๐Ÿ‘ smile

Last edited by SpeedVin (2009-07-01 13:13:00)


Shell Scripter | C/C++/Python/Java Coder | ZSH

Offline

Board footer

Atom topic feed

Powered by FluxBB