You are not logged in.

#376 2011-10-18 19:43:45

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

Thanks Cloudef WORKS Perfect!!!


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#377 2011-10-18 20:14:56

vanvalium
Member
From: Austria
Registered: 2010-10-09
Posts: 86

Re: DWM Hackers Unite! Share (or request) dwm patches.

https://bitbucket.org/veselium/dwm-etc/src

I added the updatemenu changes and switched the order in the config so the commands are before the menu.
Again tested using the hg tip, other testers are welcome.

Keysupport hasn't been added yet

Offline

#378 2011-10-19 11:10:25

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

I updated the gist with that, I'll test it when I have time on vanilla DWM to be sure too smile

Offline

#379 2011-10-19 13:55:23

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 681

Re: DWM Hackers Unite! Share (or request) dwm patches.

I have tested your latest gist upon both vanilla v5.9 and latest hg tip, and it fails in both cases, but it's just because there's a "non-diff format" line which needs to be deleted(line 334; last line) and then it works fine on both v5.9 and hg tip.

Note, i've just tested that it patches ok, but not the actual functionality of the patch, as I do not use that patch myself...

Offline

#380 2011-10-19 15:37:16

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

mhertz wrote:

I have tested your latest gist upon both vanilla v5.9 and latest hg tip, and it fails in both cases, but it's just because there's a "non-diff format" line which needs to be deleted(line 334; last line) and then it works fine on both v5.9 and hg tip.

Note, i've just tested that it patches ok, but not the actual functionality of the patch, as I do not use that patch myself...

Updated the gist again, thanks.

Offline

#381 2011-10-19 19:08:23

vanvalium
Member
From: Austria
Registered: 2010-10-09
Posts: 86

Re: DWM Hackers Unite! Share (or request) dwm patches.

I have tested your latest gist upon both vanilla v5.9 and latest hg tip, and it fails in both cases, but it's just because there's a "non-diff format" line which needs to be deleted(line 334; last line) and then it works fine on both v5.9 and hg tip.

Note, i've just tested that it patches ok, but not the actual functionality of the patch, as I do not use that patch myself...

Didn't check for that, thanks.

Offline

#382 2011-10-22 21:17:27

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

vanvalium wrote:

Is anyone using dwmstatus and mpd?
Dwmstatus is very resource-friendly and it shouldn't be too hard to get mpd stats with in.

 

Hi check this  http://dotshare.it/dots/165/

Can someone give me a pango patch for the dwm-5.9?

Last edited by ivoarch (2011-10-22 21:23:49)


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#383 2011-10-23 00:47:36

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 681

Re: DWM Hackers Unite! Share (or request) dwm patches.

lolilolicon previously in this thread posted a link to the pango patch, which he had updated for v5.9:

lolilolicon wrote:

@Shrak, I updated the pango patch from AUR/pango for dwm 5.9 several days ago:
https://gist.github.com/1082030

It's only some offsetting stuff.
I didn't use it because it breaks my other patches... hmm

Source: https://bbs.archlinux.org/viewtopic.php … 84#p960784

Last edited by mhertz (2011-10-23 00:59:25)

Offline

#384 2011-10-23 09:43:09

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

@mhertz

Thanks!

I tried applying the patch manually
Any idea 

 dwm build options:
CFLAGS   = -std=c99 -pedantic -Wall -Os -I. -I/usr/include -I/usr/X11R6/include -DVERSION="5.9" -DXINERAMA
LDFLAGS  = -s -L/usr/lib -lc -L/usr/X11R6/lib -lX11 -L/usr/X11R6/lib -lXinerama
CC       = cc
CC dwm.c
In file included from /usr/include/X11/Xft/Xft.h:39:0,
                 from dwm.c:39:
/usr/include/ft2build.h:56:38: fatal error: freetype/config/ftheader.h: No such file or directory
compilation terminated.
make: *** [dwm.o] Error 1   

I changed something to use it with statuscolors roll

Litlle question about this part of patch

The Patch: 

  /* 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.norm[ColBorder] = getcolor(normbordercolor, dc.xftnorm+ColBorder);
+ dc.norm[ColBG] = getcolor(normbgcolor, dc.xftnorm+ColBG);
+ dc.norm[ColFG] = getcolor(normfgcolor, dc.xftnorm+ColFG);
+ dc.sel[ColBorder] = getcolor(selbordercolor, dc.xftsel+ColBorder);
+ dc.sel[ColBG] = getcolor(selbgcolor, dc.xftsel+ColBG);
+ dc.sel[ColFG] = getcolor(selfgcolor, dc.xftsel+ColFG);
+ 

I use status colors and this my original part of dwm.c 

 /* init appearance */
	for(int i=0; i<NUMCOLORS; i++) {
		dc.colors[i][ColBorder] = getcolor( colors[i][ColBorder] );
		dc.colors[i][ColFG] = getcolor( colors[i][ColFG] );
		dc.colors[i][ColBG] = getcolor( colors[i][ColBG] );
	}   

I modified so

/* init appearance */
	for(int i=0; i<NUMCOLORS; i++) {
		dc.colors[i][ColBorder] = getcolor( colors[i], dc.xftcolors[i]+[ColBorder] );
		dc.colors[i][ColFG] = getcolor( colors[i], dc.xftcolors[i]+[ColFG] );
		dc.colors[i][ColBG] = getcolor( colors[i], dc.xftcolors[i]+[ColBG] );  

I'm wrong?


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#385 2011-10-23 11:50:24

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

I've updated the menu patch to support keyboard and custom key bindings.
Tested against vanilla dwm-5.9, both functionality and compile.

Search #define MENU_COLOR, in dwm.c to switch beetwen default dwm color stuff and fancycolor.
https://gist.github.com/1293166

Last edited by Cloudef (2011-10-23 11:51:10)

Offline

#386 2011-10-23 13:40:26

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

@Cloudef

Thanks for sharing it : 

I've tested and works!!!

Last edited by ivoarch (2011-10-23 18:04:52)


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#387 2011-10-24 01:39:53

mhertz
Member
From: Denmark
Registered: 2010-06-19
Posts: 681

Re: DWM Hackers Unite! Share (or request) dwm patches.

@ivoarch

Sorry, I don't use statuscolors and so don't know anything about that, but about the pango patch(which I also dosen't use, but nonetheless..), then i've just tested it on vanilla dwm-5.9 and you're right, it does fail.

This is because there's missing some edits needed in config.mk, and those missing edits is in the pango patch provided with the dwm-5.9-pango aur package.

That patch had a missing semicolon after the font declaration(which was fixed by an external config.h supplied in the aur package tarball) and so wouldn't compile if using the patched config.def.h, so I fixed that and upp'ed it for you/others:

dwm-5.9-pango.patch: http://ompldr.org/vYXkzOA

Last edited by mhertz (2011-10-24 01:40:56)

Offline

#388 2011-10-25 11:37:18

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

Now works in dwm without statuscolors patch,
for statuscolors not, I tried to change but I have not worked,
I tried to do the same as Cloudef, looking at his dwm.c and the patch and config.mk and not.
Found this thread https://bbs.archlinux.org/viewtopic.php?id=98096 
I will try again.


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#389 2011-10-26 17:22:53

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

I could compile my dwm with pango and statuscolors patch without errors,but now i have this problem

only statuscolor-patch
tYXpwZg

whit pango and statuscolors
tYXpwOA

@Cloudef my the setup of the patch is based on your dwm.c, I changed something, if you want
help me ,chek my 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 linked client
 * list on each monitor, the focus history is remembered through a stack list
 * on each monitor. 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 /* XINERAMA */
#ifdef XFT
#include <X11/Xft/Xft.h>
#include <pango/pango.h>
#include <pango/pangoxft.h>
#include <pango/pango-font.h>
#endif

/* macros */
#define BUTTONMASK              (ButtonPressMask|ButtonReleaseMask)
#define CLEANMASK(mask)         (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
#define INRECT(X,Y,RX,RY,RW,RH) ((X) >= (RX) && (X) < (RX) + (RW) && (Y) >= (RY) && (Y) < (RY) + (RH))
#define ISVISIBLE(C)            ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X)               (sizeof X / sizeof X[0])
 
#ifndef MAX
#define MAX(A, B)               ((A) > (B) ? (A) : (B))
#endif
#ifndef MIN
#define MIN(A, B)               ((A) < (B) ? (A) : (B))
#endif

#define MAXCOLORS               8
#define MOUSEMASK               (BUTTONMASK|PointerMotionMask)
#define WIDTH(X)                ((X)->w + 2 * (X)->bw)
#define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
#define TAGMASK                 ((1 << LENGTH(tags)) - 1)
#define TEXTW(X)                (textnw(X, strlen(X)) + dc.font.height)
#define TEXTW2(X)                (textnw(X,strlen(X)))  

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

typedef union {
	int i;
	unsigned int ui;
	float f;
	const 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 Monitor Monitor;
typedef struct Client Client;
struct Client {
	char name[256];
	float mina, maxa;
	int x, y, w, h;
	int oldx, oldy, oldw, oldh;
	int basew, baseh, incw, inch, maxw, maxh, minw, minh;
	int bw, oldbw;
	unsigned int tags;
	Bool isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
	Client *next;
	Client *snext;
	Monitor *mon;
	Window win;
};

typedef struct {
	int x, y, w, h;
	unsigned long colors[MAXCOLORS][ColLast];
	Drawable drawable;
	GC gc;
#ifdef XFT
   XftDraw  *xftdrawable;
   XftColor  xftcolors[MAXCOLORS][ColLast];

   PangoContext *pgc;
   PangoLayout  *plo;
   PangoFontDescription *pfd;
#endif

   struct {
      int ascent;
      int descent;
      int height;
#ifndef XFT
      XFontSet set;
      XFontStruct *xfont;
#endif 

	} font;
} DC; /* draw context */

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

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

typedef struct {
	const char *class;
	const char *instance;
	const char *title;
	unsigned int tags;
	Bool isfloating;
	int monitor;
} Rule;
 
typedef struct menuCtx {
   char *title;
   const struct menuCtx *ctx;
   void (*func)(const Arg *);
   const Arg arg;
} menuCtx;
typedef struct menu_t {
   Window win;
   int x, y, w, h;
   Drawable drawable;
   struct menu_t  *next, *child;
   const struct menuCtx *ctx;
   int sel;
   int sely; /* hack :) */
} menu_t;
static menu_t *menu  = NULL;
static menu_t *cmenu = NULL;

/* function declarations */ 
static void togglemenu(const Arg *arg); 
static void menu_up(const Arg *arg);
static void menu_down(const Arg *arg);
static void menu_next(const Arg *arg);
static void menu_prev(const Arg *arg);
static void menu_accept(const Arg *arg);
static void motionnotify(XEvent *e);
static void applyrules(Client *c);
static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact);
static void arrange(Monitor *m);
static void arrangemon(Monitor *m);
static void attach(Client *c);
static void attachaside(Client *c);
static void attachstack(Client *c);
static void bstack(Monitor *m); 
static void grid(Monitor *m); 
static void buttonpress(XEvent *e);
static void checkotherwm(void);
static void cleanup(void);
static void cleanupmon(Monitor *mon);
static void clearurgent(Client *c);
static void clientmessage(XEvent *e);
static void configure(Client *c);
static void configurenotify(XEvent *e);
static void configurerequest(XEvent *e);
static Monitor *createmon(void);
static void cycle(const Arg *arg);
static void destroynotify(XEvent *e);
static void detach(Client *c);
static void detachstack(Client *c);
static void die(const char *errstr, ...);
static Monitor *dirtomon(int dir);
static void drawbar(Monitor *m);
static void drawbars(void);
static void drawicon(const char *file, unsigned long col[ColLast]);
static void drawcoloredtext(char *text);
static void drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]);
static void drawtext(const char *text, unsigned long col[ColLast], Bool pad);
static void expose(XEvent *e);
static void focus(Client *c);
static void focusin(XEvent *e);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
#ifndef XFT
static unsigned long  getcolor(const char *colstr);
#else
static unsigned long  getcolor(const char *colstr, XftColor *color);
#endif
static Bool getrootptr(int *x, int *y);
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 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(Monitor *m);
static void movemouse(const Arg *arg);
static void nextlayout(const Arg *arg);
static Client *nexttiled(Client *c);
static void pop(Client *);
static void propertynotify(XEvent *e);
static Monitor *ptrtomon(int x, int y);
static void prevlayout(const Arg *arg);
static void quit(const Arg *arg);
static void resize(Client *c, int x, int y, int w, int h, Bool interact);
static void resizeclient(Client *c, int x, int y, int w, int h);
static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
static Bool sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
static void setfocus(Client *c);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setup(void);
static int shifttag(int dist);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
static void tag(const Arg *arg);
static void tagcycle(const Arg *arg);
static void tagmon(const Arg *arg);
static int textnw(const char *text, unsigned int len);
static void tile(Monitor *);
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 unfocus(Client *c, Bool setfocus);
static void unmanage(Client *c, Bool destroyed);
static void unmapnotify(XEvent *e);
static Bool updategeom(void);
static void updatebarpos(Monitor *m);
static void updatebars(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 Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
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 const char broken[] = "broken";
static char stext[256];
static int screen;
static int sw, sh;           /* X display screen geometry width, height */
static int bh, blw = 0;      /* bar geometry */
static int (*xerrorxlib)(Display *, XErrorEvent *);
static unsigned int numlockmask = 0;
static void (*handler[LASTEvent]) (XEvent *) = {
	[ButtonPress] = buttonpress,
	[ClientMessage] = clientmessage,
	[ConfigureRequest] = configurerequest,
	[ConfigureNotify] = configurenotify,
	[DestroyNotify] = destroynotify,
        [MotionNotify] = motionnotify,
	[Expose] = expose,
	[FocusIn] = focusin,
	[KeyPress] = keypress,
	[MappingNotify] = mappingnotify,
	[MapRequest] = maprequest,
	[PropertyNotify] = propertynotify,
	[UnmapNotify] = unmapnotify
};
static Atom wmatom[WMLast], netatom[NetLast];
static Bool running = True;
static Cursor cursor[CurLast];
static Display *dpy;
static DC dc;
static Monitor *mons = NULL, *selmon = NULL;
static Window root;
static int globalborder ;
static int globalborder ;

/* configuration, allows nested code to access above variables */
#include "config.h"

struct Monitor {
	char ltsymbol[16];
	float mfact;
	int num;
	int by;               /* bar geometry */
	int mx, my, mw, mh;   /* screen size */
	int wx, wy, ww, wh;   /* window area  */
	unsigned int seltags;
	unsigned int sellt;
	unsigned int tagset[2];
	Bool showbar;
	Bool topbar;
	Client *clients;
	Client *sel;
	Client *stack;
	Monitor *next;
	Window barwin;
	const Layout *lt[2];
	int curtag;
	int prevtag;
	const Layout *lts[LENGTH(tags) + 1];
	double mfacts[LENGTH(tags) + 1];
	Bool showbars[LENGTH(tags) + 1];
};

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

/* function implementations */
void
applyrules(Client *c) {
	const char *class, *instance;
	unsigned int i;
	const Rule *r;
	Monitor *m;
	XClassHint ch = { 0 };

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

Bool
applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool interact) {
	Bool baseismin;
	Monitor *m = c->mon;

	/* set minimum possible */
	*w = MAX(1, *w);
	*h = MAX(1, *h);
	if(interact) {
		if(*x > sw)
			*x = sw - WIDTH(c);
		if(*y > sh)
			*y = sh - HEIGHT(c);
		if(*x + *w + 2 * c->bw < 0)
			*x = 0;
		if(*y + *h + 2 * c->bw < 0)
			*y = 0;
	}
	else {
		if(*x > m->mx + m->mw)
			*x = m->mx + m->mw - WIDTH(c);
		if(*y > m->my + m->mh)
			*y = m->my + m->mh - HEIGHT(c);
		if(*x + *w + 2 * c->bw < m->mx)
			*x = m->mx;
		if(*y + *h + 2 * c->bw < m->my)
			*y = m->my;
	}
	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 + 0.5;
			else if(c->mina < (float)*h / *w)
				*h = *w * c->mina + 0.5;
		}
		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 = MAX(*w + c->basew, c->minw);
		*h = MAX(*h + c->baseh, 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(Monitor *m) {
	if(m)
		showhide(m->stack);
	else for(m = mons; m; m = m->next)
		showhide(m->stack);
	focus(NULL);
	if(m)
		arrangemon(m);
	else for(m = mons; m; m = m->next)
		arrangemon(m);
}

void
arrangemon(Monitor *m) {
	strncpy(m->ltsymbol, m->lt[m->sellt]->symbol, sizeof m->ltsymbol);
	if(m->lt[m->sellt]->arrange)
		m->lt[m->sellt]->arrange(m);
	restack(m);
}

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

void
attachaside(Client *c) {
	Client *at = nexttiled(c->mon->clients);;
	if(c->mon->sel == NULL || c->mon->sel->isfloating || !at) {
		attach(c);
		return;
	}
	c->next = at->next;
	at->next = c;
}

void
attachstack(Client *c) {
	c->snext = c->mon->stack;
	c->mon->stack = c;
}
 
/* 0 = DEFAULT
 * 1 = FANCY STATUS COLORS */
#define MENU_COLOR 0
static menu_t* openmenupos( const menuCtx *ctx, int x, int y );
static void closemenu( menu_t *target );
static void
updatemenu( menu_t *m, int x, int y ) {
   Drawable dble = dc.drawable;
   int ow = dc.w, oh = dc.h, ox = dc.x, oy = dc.y;
   unsigned long *col;

   if(!m) return;
   const int osel = m->sel;

   dc.drawable = m->drawable;
#ifdef XFT
   XftDrawChange(dc.xftdrawable, dc.drawable);
#endif
   size_t i;
   dc.x = 0;   dc.y = 0;
   dc.w = m->w;

   for(i = 0; m->ctx[i].title; ++i)
   {
      if (x > 0      && x < TEXTW2(m->ctx[i].title)
         && y > dc.y && y < dc.y + dc.font.height )
         m->sel = i;

      /* this check cause there is keyboard input too */
#if MENU_COLOR
      if(m->sel == i) { col = dc.colors[5]; m->sely = dc.y; }
      else col = dc.colors[0];
 #else 
      if(m->sel == i) { col = dc.colors[5]; m->sely = dc.y; } 
      else col = dc.colors[0]; 
#endif 

      dc.h = dc.font.height;
      drawtext(m->ctx[i].title, col, False);
      dc.y += dc.font.height;
   }

   XCopyArea(dpy, dc.drawable, m->win, dc.gc, 0, 0, m->w, m->h, 0, 0);
   XSync(dpy, False);

   dc.w = ow; dc.h = oh; dc.x = ox; dc.y = oy;
   dc.drawable = dble;
#ifdef XFT
   XftDrawChange(dc.xftdrawable, dc.drawable);
#endif

   /* only for mouse */
   if(m->sel != osel)
   {
      if(m->child) { closemenu(m->child); m->child = NULL; }
      if(m->ctx[m->sel].ctx != NULL)
         m->child = openmenupos( m->ctx[m->sel].ctx, m->x + m->w, m->y + m->sely );
   }
}

menu_t*
wintomenu( Window win )
{
   menu_t *m;

   if(!menu) return(NULL);
   for( m = menu; m; m = m->next )
      if(m->win == win) return(m);

   return(NULL);
}

menu_t*
ctxtomenu( const menuCtx *ctx )
{
   menu_t *m;

   if(!menu) return(NULL);
   for( m = menu; m; m = m->next )
      if(m->ctx == ctx) return(m);

   return(NULL);
}

static int
createmenu( menu_t *m, const menuCtx *ctx, int x, int y ) {
   size_t i, j;
   unsigned int modifiers[] = { 0, LockMask, numlockmask, numlockmask|LockMask };
   KeyCode code;

   if(ctxtomenu(ctx)) return(-1);

   m->x    = x;
   m->y    = y;
   m->w    = 0;
   m->h    = 0;
   m->ctx  = ctx;
   m->sel  = -1;
   m->child= NULL;

   for(i = 0; m->ctx[i].title; ++i)
   {
      if(m->w < TEXTW2(m->ctx[i].title))
         m->w = TEXTW2(m->ctx[i].title);
      m->h += dc.font.height;
   }
   if(i == 0) return(-1);

   XSetWindowAttributes wattr;
   wattr.override_redirect = True;
   wattr.background_pixmap = ParentRelative;
   wattr.event_mask = ButtonPressMask|ExposureMask;

   m->win = XCreateWindow(dpy, root, m->x, m->y, m->w, m->h, 0, DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), CWBackPixmap|CWOverrideRedirect|CWEventMask, &wattr);

   XSelectInput(dpy, m->win, PointerMotionMask|ButtonPressMask|KeyPressMask);

   XDefineCursor(dpy, m->win, cursor[CurNormal]);
   XMapRaised(dpy, m->win);

   m->drawable = XCreatePixmap(dpy, root, m->w, m->h, DefaultDepth(dpy, screen)); 
   updatemenu(m, m->x, m->y);

   if(selmon && selmon->sel)
   { grabbuttons(selmon->sel,False); XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime); XSync(dpy,False); }

   /* keyboard input */
   updatenumlockmask();
   {
      XUngrabKey(dpy, AnyKey, AnyModifier, m->win);
      for(i = 0; i < LENGTH(menu_keys); i++) {
         if((code = XKeysymToKeycode(dpy, menu_keys[i].keysym)))
            for(j = 0; j < LENGTH(modifiers); j++)
               XGrabKey(dpy, code, menu_keys[i].mod | modifiers[j], m->win,
                     True, GrabModeAsync, GrabModeAsync);
      }
   }

   XSetInputFocus(dpy, m->win, RevertToPointerRoot, CurrentTime);

   return(0);
}

static menu_t*
openmenupos( const menuCtx *ctx, int x, int y ) {
   menu_t **m, *mm;

   m  = &menu;
   mm =  menu;
   for(; mm; mm = mm->next)
      m = &mm->next;

   *m = calloc(1, sizeof(menu_t));
   if(!*m)
      return NULL;

   (*m)->next = NULL;
   if(createmenu(*m, ctx, x, y) == -1)
   { free(*m); *m = NULL; }

   return *m;
}

static menu_t*
openmenu( const menuCtx *ctx ) {
   int x, y;
   getrootptr( &x, &y );
   return openmenupos( ctx, x, y );
}

static void
closemenu( menu_t *target )
{
   menu_t **m, *mm;

   if(!target) return;

   /* this is not valid child anymore */
   for( mm = menu; mm; mm = mm->next )
      if(mm->child == target) mm->child = NULL;

   /* close childs */
   for( mm = target->child; mm; mm = mm->child )
      closemenu( mm );

   /* remove */
   m = &menu;
   for( mm = menu; mm && mm->next && mm->next != target; mm = mm->next )
      m = &mm;

   (*m)->next = target->next;
   XSetInputFocus(dpy, (*m)->win, RevertToPointerRoot, CurrentTime);

   XFreePixmap(dpy, target->drawable);
   XDestroyWindow(dpy, target->win);
   free(target);
   XSync(dpy, False);
}

static void
closemenus(void) {
   if(!menu) return;

   menu_t *m = menu, *next = NULL;
   while(m)
   {
      XDestroyWindow(dpy, m->win);

      next = m->next; free(m);
      m = next;
   }
   XSync(dpy, False);
   menu = NULL;
}

static void
buttonmenu( menu_t *m, int x, int y )
{
   if(!m) return;
   updatemenu(m, x, y);
   if(m->sel == -1)         return;
   if(!m->ctx[m->sel].func) return;

   m->ctx[m->sel].func(&m->ctx[m->sel].arg);
   closemenus();
}

void
togglemenu(const Arg *arg) {
   if(!menu)
      openmenu(&rootMenu[0]);
   else
      closemenus();
}

void
menu_up(const Arg *arg) {
   size_t i;
   cmenu->sel--;
   if(cmenu->sel < 0)
      for(i = 0; cmenu->ctx[i].title; i++) cmenu->sel = i;
   updatemenu(cmenu, 0, 0);
}

void
menu_down(const Arg *arg) {
   cmenu->sel++;
   if(!cmenu->ctx[cmenu->sel].title) cmenu->sel = 0;
   updatemenu(cmenu, 0, 0);
}

void
menu_next(const Arg *arg) {
   if(cmenu->sel > -1)
   {
      if(cmenu->child) { closemenu(cmenu->child); cmenu->child = NULL; }
      if(cmenu->ctx[cmenu->sel].ctx)
      {
         cmenu->child      = openmenupos( cmenu->ctx[cmenu->sel].ctx, cmenu->x + cmenu->w, cmenu->y + cmenu->sely );
         if(!cmenu->child) return;
         cmenu->child->sel = 0;
         updatemenu(cmenu->child, 0, 0);
      }
   }
}

void
menu_prev(const Arg *arg) {
   if(cmenu != menu) closemenu(cmenu);
}

void
menu_accept(const Arg *arg) {
   buttonmenu(cmenu, 0, 0);
} 

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

	click = ClkRootWin; 
   
        /* do action on Button1, or close menu if menu isn't clicked
         * with Button1 */
        if(ev->button == Button1)
        {
            if(menu)
            {
               if(!(mm = wintomenu(ev->window)))
               {
                  closemenus();
               } else
               { buttonmenu(mm, ev->x, ev->y); return; }
            }
        } 

	/* focus monitor if necessary */
	if((m = wintomon(ev->window)) && m != selmon) {
		unfocus(selmon->sel, True);
		selmon = m;
		focus(NULL);
	}
	if(ev->window == selmon->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 > selmon->ww - TEXTW(stext))
			click = ClkStatusText;
		else
			click = ClkWinTitle;
	}
	else if((c = wintoclient(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
motionnotify(XEvent *e) {
   menu_t  *mm;
   XMotionEvent *ev = &e->xmotion;

   if( (mm = wintomenu(ev->window)) )
   {
      updatemenu(mm, ev->x, ev->y);
      return;
   }
}

void
checkotherwm(void) {
	xerrorxlib = XSetErrorHandler(xerrorstart);
	/* this causes an error if some other window manager is running */
	XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask);
	XSync(dpy, False);
	XSetErrorHandler(xerror);
	XSync(dpy, False);
}

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

	view(&a);
	selmon->lt[selmon->sellt] = &foo;
	for(m = mons; m; m = m->next)
		while(m->stack)
			unmanage(m->stack, False);
#ifndef XFT
   if(dc.font.set)
      XFreeFontSet(dpy, dc.font.set);
   else
      XFreeFont(dpy, dc.font.xfont);
#endif
	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]);
	while(mons)
		cleanupmon(mons);
	XSync(dpy, False);
	XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
}

void
cleanupmon(Monitor *mon) {
	Monitor *m;

	if(mon == mons)
		mons = mons->next;
	else {
		for(m = mons; m && m->next != mon; m = m->next);
		m->next = mon->next;
	}
	XUnmapWindow(dpy, mon->barwin);
	XDestroyWindow(dpy, mon->barwin);
	free(mon);
}

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
clientmessage(XEvent *e) {
	XClientMessageEvent *cme = &e->xclient;
	Client *c = wintoclient(cme->window);

	if(!c)
		return;
	if(cme->message_type == netatom[NetWMState] && cme->data.l[1] == netatom[NetWMFullscreen]) {
		if(cme->data.l[0] && !c->isfullscreen) {
			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
			                PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
			c->isfullscreen = True;
			c->oldstate = c->isfloating;
			c->oldbw = c->bw;
			c->bw = 0;
			c->isfloating = True;
			resizeclient(c, c->mon->mx, c->mon->my, c->mon->mw, c->mon->mh);
			XRaiseWindow(dpy, c->win);
		}
		else {
			XChangeProperty(dpy, cme->window, netatom[NetWMState], XA_ATOM, 32,
			                PropModeReplace, (unsigned char*)0, 0);
			c->isfullscreen = False;
			c->isfloating = c->oldstate;
			c->bw = c->oldbw;
			c->x = c->oldx;
			c->y = c->oldy;
			c->w = c->oldw;
			c->h = c->oldh;
			resizeclient(c, c->x, c->y, c->w, c->h);
			arrange(c->mon);
		}
	}
	else if(cme->message_type == netatom[NetActiveWindow]) {
		if(!ISVISIBLE(c)) {
			c->mon->seltags ^= 1;
			c->mon->tagset[c->mon->seltags] = c->tags;
		}
		pop(c);
	}
}

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) {
	Monitor *m;
	XConfigureEvent *ev = &e->xconfigure;
	Bool dirty;

	if(ev->window == root) {
		dirty = (sw != ev->width);
		sw = ev->width;
		sh = ev->height;
		if(updategeom() || dirty) {
			if(dc.drawable != 0)
				XFreePixmap(dpy, dc.drawable);
			dc.drawable = XCreatePixmap(dpy, root, sw, bh, DefaultDepth(dpy, screen));
#ifdef XFT
         XftDrawChange(dc.xftdrawable, dc.drawable);
#endif
			updatebars();
			for(m = mons; m; m = m->next)
				XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
			arrange(NULL);
		}
	}
}

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

	if((c = wintoclient(ev->window))) {
		if(ev->value_mask & CWBorderWidth)
			c->bw = ev->border_width;
		else if(c->isfloating || !selmon->lt[selmon->sellt]->arrange) {
			m = c->mon;
			if(ev->value_mask & CWX)
				c->x = m->mx + ev->x;
			if(ev->value_mask & CWY)
				c->y = m->my + ev->y;
			if(ev->value_mask & CWWidth)
				c->w = ev->width;
			if(ev->value_mask & CWHeight)
				c->h = ev->height;
			if((c->x + c->w) > m->mx + m->mw && c->isfloating)
				c->x = m->mx + (m->mw / 2 - c->w / 2); /* center in x direction */
			if((c->y + c->h) > m->my + m->mh && c->isfloating)
				c->y = m->my + (m->mh / 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);
}

Monitor *
createmon(void) {
	Monitor *m;
	unsigned int i;

	if(!(m = (Monitor *)calloc(1, sizeof(Monitor))))
		die("fatal: could not malloc() %u bytes\n", sizeof(Monitor));
	m->tagset[0] = m->tagset[1] = 1;
	m->mfact = mfact;
	m->showbar = showbar;
	m->topbar = topbar;
	m->lt[0] = &layouts[0];
	m->lt[1] = &layouts[1 % LENGTH(layouts)];
	strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);

	/* pertag init */
	m->curtag = m->prevtag = 1;
	for(i=0; i < LENGTH(tags) + 1 ; i++) {
		m->mfacts[i] = mfact;
		m->lts[i] = &layouts[0];
		m->showbars[i] = m->showbar;
	}

	return m;
}

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

	if((c = wintoclient(ev->window)))
		unmanage(c, True);
}

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

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

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

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

	if(c == c->mon->sel) {
		for(t = c->mon->stack; t && !ISVISIBLE(t); t = t->snext);
		c->mon->sel = t;
	}
}

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

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

Monitor *
dirtomon(int dir) {
	Monitor *m = NULL;

	if(dir > 0) {
		if(!(m = selmon->next))
			m = mons;
	}
	else {
		if(selmon == mons)
			for(m = mons; m->next; m = m->next);
		else
			for(m = mons; m->next != selmon; m = m->next);
	}
	return m;
}

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

	for(c = m->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 = dc.colors[ (m->tagset[m->seltags] & 1 << i ? 1:(urg & 1 << i ? 2:0))];
		drawtext(tags[i], col, True);
		drawsquare(m == selmon && selmon->sel && selmon->sel->tags & 1 << i, occ & 1 << i, col);
		dc.x += dc.w;
	}
	 blw = TEXTW(m->ltsymbol);

 if(useicons) {
 dc.w = dc.h;
 drawicon(m->lt[m->sellt]->icon, dc.colors[2]);
 }
 else {
 dc.w = blw;
 drawtext(m->ltsymbol, dc.colors[2], False);
 }
	dc.x += dc.w;
	x = dc.x;
	if(m == selmon) { /* status is only drawn on selected monitor */
		dc.w = TEXTW(stext);
		dc.x = m->ww - dc.w;
		if(dc.x < x) {
			dc.x = x;
			dc.w = m->ww - x;
		}
		drawcoloredtext(stext);
	}
	else
		dc.x = m->ww;
	if((dc.w = dc.x - x) > bh) {
		dc.x = x;
		if(m->sel) {
			col = m == selmon ? dc.colors[1] : dc.colors[0];
			drawtext(m->sel->name, col, True);
			drawsquare(m->sel->isfixed, m->sel->isfloating, col);
		}
		else
			drawtext(NULL, dc.colors[0], False);
	}
	XCopyArea(dpy, dc.drawable, m->barwin, dc.gc, 0, 0, m->ww, bh, 0, 0);
	XSync(dpy, False);
}

void
drawbars(void) {
	Monitor *m;

	for(m = mons; m; m = m->next)
		drawbar(m);
}

void
drawcoloredtext(char *text) {
	Bool first=True;
	char *buf = text, *ptr = buf, c = 1;
	unsigned long *col = dc.colors[0];
	int i, ox = dc.x;

	while( *ptr ) {
		for( i = 0; *ptr < 0 || *ptr > NUMCOLORS; i++, ptr++);
		if( !*ptr ) break;
		c=*ptr;
		*ptr=0;
		if( i ) {
			dc.w = selmon->ww - dc.x;
			drawtext(buf, col, first);
			dc.x += textnw(buf, i) + textnw(&c,1);
			if( first ) dc.x += ( dc.font.ascent + dc.font.descent ) / 2;
			first = False;
		} else if( first ) {
			ox = dc.x += textnw(&c,1);
		}
		*ptr = c;
		col = dc.colors[ c-1 ];
		buf = ++ptr;
	}
	if( !first ) dc.x-=(dc.font.ascent+dc.font.descent)/2;
	drawtext(buf, col, True);
	dc.x = ox;
}
 
void
drawicon(const char *file, unsigned long col[ColLast]) {
 Pixmap icon;
 int px, py;
 unsigned int pw, ph;
 icon = XCreatePixmap(dpy, dc.drawable, dc.h, dc.h, 1);
 XReadBitmapFile(dpy, dc.drawable, file, &pw, &ph, &icon, &px, &py);
 XSetForeground(dpy, dc.gc, col[ColBG]);
 XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, 0, dc.h, dc.h);
 XSetForeground(dpy, dc.gc, col[ColFG]);
 XSetBackground(dpy, dc.gc, col[ColBG]);
 XCopyPlane(dpy, icon, dc.drawable, dc.gc, px, py, pw, ph, dc.x, dc.h/2-ph/2+py, 1);
} 

void
drawsquare(Bool filled, Bool empty, unsigned long col[ColLast]) {
	int x;

	XSetForeground(dpy, dc.gc, col[ColFG]);
	x = (dc.font.ascent + dc.font.descent + 2) / 4;
	if(filled)
		XFillRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x+1, x+1);
	else if(empty)
		XDrawRectangle(dpy, dc.drawable, dc.gc, dc.x+1, dc.y+1, x, x);
}

void
drawtext(const char *text, unsigned long col[ColLast], Bool pad) {
	char buf[256];
	int i, x, y, h, len, olen;

	XSetForeground(dpy, dc.gc, col[ ColBG ]);
	XFillRectangle(dpy, dc.drawable, dc.gc, dc.x, dc.y, dc.w, dc.h);
	if(!text)
		return;
	olen = strlen(text);
	h    = pad ? (dc.font.ascent + dc.font.descent) : 0;
#ifndef XFT
   y    = dc.y + ((dc.h + dc.font.ascent - dc.font.descent) / 2);
#else
   y    = dc.y;
#endif
   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] = '.');
	  
#ifdef XFT
         pango_layout_set_text(dc.plo, text, len);
	pango_xft_render_layout(dc.xftdrawable, (col==dc.colors[0]?dc.xftcolors[0]:dc.xftcolors[1])+(ColFG), dc.plo, x * PANGO_SCALE, y * PANGO_SCALE);
#else 
                 
    XSetForeground(dpy, dc.gc, col[ 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);
#endif
} 

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

	if((ev->mode != NotifyNormal || ev->detail == NotifyInferior) && ev->window != root)
		return;
	c = wintoclient(ev->window);
	m = c ? c->mon : wintomon(ev->window);
	if(m != selmon) {
		unfocus(selmon->sel, True);
		selmon = m;
	}
	else if(!c || c == selmon->sel)
		return;
	focus(c);
}

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

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

void
focus(Client *c) {  
        if(menu) return;
	if(!c || !ISVISIBLE(c))
		for(c = selmon->stack; c && !ISVISIBLE(c); c = c->snext);
	/* was if(selmon->sel) */
	if(selmon->sel && selmon->sel != c)
		unfocus(selmon->sel, False);
	if(c) {
		if(c->mon != selmon)
			selmon = c->mon;
		if(c->isurgent)
			clearurgent(c);
		detachstack(c);
		attachstack(c);
		grabbuttons(c, True);
		XSetWindowBorder(dpy, c->win, dc.colors[1][ColBorder]);
		setfocus(c);
	}
	else
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
	selmon->sel = c;
	drawbars();
}

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

	if(selmon->sel && ev->window != selmon->sel->win)
		setfocus(selmon->sel);
}

void
focusmon(const Arg *arg) {
	Monitor *m;

	if(!mons->next)
		return;
	if((m = dirtomon(arg->i)) == selmon)
		return;
	unfocus(selmon->sel, True);
	selmon = m;
	focus(NULL);
}

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

	if(!selmon->sel)
		return;
	if(arg->i > 0) {
		for(c = selmon->sel->next; c && !ISVISIBLE(c); c = c->next);
		if(!c)
			for(c = selmon->clients; c && !ISVISIBLE(c); c = c->next);
	}
	else {
		for(i = selmon->clients; i != selmon->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(selmon);
	}
}

unsigned long
#ifndef XFT
getcolor(const char *colstr) {
#else
getcolor(const char *colstr, XftColor *color) {
#endif
   Colormap cmap = DefaultColormap(dpy, screen);
#ifndef XFT
   XColor color;

   if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
      die("error, cannot allocate color '%s'\n", colstr);
   return color.pixel;
#else
   Visual *vis = DefaultVisual(dpy, screen);
   if(!XftColorAllocName(dpy,vis,cmap,colstr, color))
      die("error, cannot allocate color '%s'\n", colstr);

   return color->pixel;
#endif
} 

Bool
getrootptr(int *x, int *y) {
	int di;
	unsigned int dui;
	Window dummy;

	return XQueryPointer(dpy, root, &dummy, &dummy, x, y, &di, &di, &dui);
}

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

	if(XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
	                      &real, &format, &n, &extra, (unsigned char **)&p) != 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();
	{
		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) {
#ifdef XFT
   PangoFontMetrics *metrics;

   dc.pgc = pango_xft_get_context(dpy, screen);
   dc.pfd = pango_font_description_from_string(fontstr);

   metrics = pango_context_get_metrics(dc.pgc, dc.pfd, pango_language_from_string(setlocale(LC_CTYPE, "")));
   dc.font.ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
   dc.font.descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;

   pango_font_metrics_unref(metrics);

   dc.plo = pango_layout_new(dc.pgc);
   pango_layout_set_font_description(dc.plo, dc.pfd);

   dc.font.height = dc.font.ascent + dc.font.descent;
#else
   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;
#endif
}
	
#ifdef XINERAMA
static Bool
isuniquegeom(XineramaScreenInfo *unique, size_t n, XineramaScreenInfo *info) {
	while(n--)
		if(unique[n].x_org == info->x_org && unique[n].y_org == info->y_org
		&& unique[n].width == info->width && unique[n].height == info->height)
			return False;
	return True;
}
#endif /* XINERAMA */

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)); 
 
if(menu && (cmenu = wintomenu(ev->window)))
        {
               keysym = XKeycodeToKeysym(dpy, (KeyCode)ev->keycode, 0);
               for(i = 0; i < LENGTH(menu_keys); i++)
                       if(keysym == menu_keys[i].keysym
                       && CLEANMASK(menu_keys[i].mod) == CLEANMASK(ev->state)
                       && menu_keys[i].func)
                                    menu_keys[i].func(&(menu_keys[i].arg));
        }
}

void
killclient(const Arg *arg) {
	if(!selmon->sel)
		return;
	if(!sendevent(selmon->sel, wmatom[WMDelete])) {
		XGrabServer(dpy);
		XSetErrorHandler(xerrordummy);
		XSetCloseDownMode(dpy, DestroyAll);
		XKillClient(dpy, selmon->sel->win);
		XSync(dpy, False);
		XSetErrorHandler(xerror);
		XUngrabServer(dpy);
	}
}

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

	if(!(c = calloc(1, sizeof(Client))))
		die("fatal: could not malloc() %u bytes\n", sizeof(Client));
	c->win = w;
	updatetitle(c);
	if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
		c->mon = t->mon;
		c->tags = t->tags;
	}
	else {
		c->mon = selmon;
		applyrules(c);
	}
	/* geometry */
	 if(!c->mon->lt[c->mon->sellt]->arrange || c->isfloating) {
 c->x = c->oldx = (c->mon->mw - wa->width) / 2;
 c->y = c->oldy = (c->mon->mh - wa->height) / 2;
 }
 else {
 c->x = c->oldx = wa->x;
 c->y = c->oldy = wa->y; 
 }
	c->w = c->oldw = wa->width;
	c->h = c->oldh = wa->height;
	c->oldbw = wa->border_width;
	if(c->w == c->mon->mw && c->h == c->mon->mh) {
		c->isfloating = True;
		c->x = c->mon->mx;
		c->y = c->mon->my;
		c->bw = 0;
	}
	else {
		if(c->x + WIDTH(c) > c->mon->mx + c->mon->mw)
			c->x = c->mon->mx + c->mon->mw - WIDTH(c);
		if(c->y + HEIGHT(c) > c->mon->my + c->mon->mh)
			c->y = c->mon->my + c->mon->mh - HEIGHT(c);
		c->x = MAX(c->x, c->mon->mx);
		/* only fix client y-offset, if the client center might cover the bar */
		c->y = MAX(c->y, ((c->mon->by == 0) && (c->x + (c->w / 2) >= c->mon->wx)
		           && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
		c->bw = borderpx;
	}
	wc.border_width = c->bw;
	XConfigureWindow(dpy, w, CWBorderWidth, &wc);
	XSetWindowBorder(dpy, w, dc.colors[0][ColBorder]);
	configure(c); /* propagates border_width, if size doesn't change */
	updatesizehints(c);
	updatewmhints(c);
	XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
	grabbuttons(c, False);
	if(!c->isfloating)
		c->isfloating = c->oldstate = trans != None || c->isfixed;
	if(c->isfloating)
		XRaiseWindow(dpy, c->win);
	attachaside(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(c->mon);
}

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(!wintoclient(ev->window))
		manage(ev->window, &wa);
}

void
monocle(Monitor *m) {
	unsigned int n = 0;
	Client *c;

	for(c = m->clients; c; c = c->next)
		if(ISVISIBLE(c))
			n++;
	if(n > 0) /* override layout symbol */
		snprintf(m->ltsymbol, sizeof m->ltsymbol, "[%d]", n);
	for(c = nexttiled(m->clients); c; c = nexttiled(c->next))
		resize(c, m->wx, m->wy, m->ww - 2 * c->bw, m->wh - 2 * c->bw, False);
}

void
movemouse(const Arg *arg) {
	int x, y, ocx, ocy, nx, ny;
	Client *c;
	Monitor *m;
	XEvent ev;

	if(!(c = selmon->sel))
		return;
	restack(selmon);
	ocx = c->x;
	ocy = c->y;
	if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
	None, cursor[CurMove], CurrentTime) != GrabSuccess)
		return;
	if(!getrootptr(&x, &y))
		return;
	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(nx >= selmon->wx && nx <= selmon->wx + selmon->ww
			&& ny >= selmon->wy && ny <= selmon->wy + selmon->wh) {
				if(abs(selmon->wx - nx) < snap)
					nx = selmon->wx;
				else if(abs((selmon->wx + selmon->ww) - (nx + WIDTH(c))) < snap)
					nx = selmon->wx + selmon->ww - WIDTH(c);
				if(abs(selmon->wy - ny) < snap)
					ny = selmon->wy;
				else if(abs((selmon->wy + selmon->wh) - (ny + HEIGHT(c))) < snap)
					ny = selmon->wy + selmon->wh - HEIGHT(c);
				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
				&& (abs(nx - c->x) > snap || abs(ny - c->y) > snap))
					togglefloating(NULL);
			}
			if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
				resize(c, nx, ny, c->w, c->h, True);
			break;
		}
	} while(ev.type != ButtonRelease);
	XUngrabPointer(dpy, CurrentTime);
	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
		sendmon(c, m);
		selmon = m;
		focus(NULL);
	}
}

void
nextlayout(const Arg *arg) {
    Layout *l;
    for (l=(Layout *)layouts;l != selmon->lt[selmon->sellt];l++);
    if (l->symbol && (l + 1)->symbol)
        setlayout(&((Arg) { .v = (l + 1) }));
    else
        setlayout(&((Arg) { .v = layouts }));
}

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

void
pop(Client *c) {
	detach(c);
	attach(c);
	focus(c);
	arrange(c->mon);
}

void
prevlayout(const Arg *arg) {
    Layout *l;
    for (l=(Layout *)layouts;l != selmon->lt[selmon->sellt];l++);
    if (l != layouts && (l - 1)->symbol)
        setlayout(&((Arg) { .v = (l - 1) }));
    else
        setlayout(&((Arg) { .v = &layouts[LENGTH(layouts) - 2] }));
}

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 = wintoclient(ev->window))) {
		switch(ev->atom) {
		default: break;
		case XA_WM_TRANSIENT_FOR:
			if(!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
			   (c->isfloating = (wintoclient(trans)) != NULL))
				arrange(c->mon);
			break;
		case XA_WM_NORMAL_HINTS:
			updatesizehints(c);
			break;
		case XA_WM_HINTS:
			updatewmhints(c);
			drawbars();
			break;
		}
		if(ev->atom == XA_WM_NAME || ev->atom == netatom[NetWMName]) {
			updatetitle(c);
			if(c == c->mon->sel)
				drawbar(c->mon);
		}
	}
}

Monitor *
ptrtomon(int x, int y) {
	Monitor *m;

	for(m = mons; m; m = m->next)
		if(INRECT(x, y, m->wx, m->wy, m->ww, m->wh))
			return m;
	return selmon;
}
void
quit(const Arg *arg) {
	running = False;
}

void
resize(Client *c, int x, int y, int w, int h, Bool interact) {
	if(applysizehints(c, &x, &y, &w, &h, interact))
		resizeclient(c, x, y, w, h);
}

void
resizeclient(Client *c, int x, int y, int w, int h) {
	XWindowChanges wc;
	
	if(c->isfloating || selmon->lt[selmon->sellt]->arrange == NULL) { globalborder = 0 ; }
	else {
		if (selmon->lt[selmon->sellt]->arrange == monocle) { globalborder = 0 - borderpx ; }
		else { globalborder =  gappx ; }
	}

	c->oldx = c->x; c->x = wc.x = x + globalborder ;
	c->oldy = c->y; c->y = wc.y = y + globalborder ;
	c->oldw = c->w; c->w = wc.width = w - 2 * globalborder ;
	c->oldh = c->h; c->h = wc.height = h - 2 * globalborder ;
	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;
	Monitor *m;
	XEvent ev;

	if(!(c = selmon->sel))
		return;
	restack(selmon);
	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(c->mon->wx + nw >= selmon->wx && c->mon->wx + nw <= selmon->wx + selmon->ww
			&& c->mon->wy + nh >= selmon->wy && c->mon->wy + nh <= selmon->wy + selmon->wh)
			{
				if(!c->isfloating && selmon->lt[selmon->sellt]->arrange
				&& (abs(nw - c->w) > snap || abs(nh - c->h) > snap))
					togglefloating(NULL);
			}
			if(!selmon->lt[selmon->sellt]->arrange || c->isfloating)
				resize(c, c->x, c->y, nw, nh, True);
			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));
	if((m = ptrtomon(c->x + c->w / 2, c->y + c->h / 2)) != selmon) {
		sendmon(c, m);
		selmon = m;
		focus(NULL);
	}
}

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

	drawbar(m);
	if(!m->sel)
		return;
	if(m->sel->isfloating || !m->lt[m->sellt]->arrange)
		XRaiseWindow(dpy, m->sel->win);
	if(m->lt[m->sellt]->arrange) {
		wc.stack_mode = Below;
		wc.sibling = m->barwin;
		for(c = m->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
sendmon(Client *c, Monitor *m) {
	if(c->mon == m)
		return;
	unfocus(c, True);
	detach(c);
	detachstack(c);
	c->mon = m;
	c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
	attach(c);
	attachstack(c);
	focus(NULL);
	arrange(NULL);
}

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

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

Bool
sendevent(Client *c, Atom proto) {
	int n;
	Atom *protocols;
	Bool exists = False;
	XEvent ev;

	if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
		while(!exists && n--)
			exists = protocols[n] == proto;
		XFree(protocols);
	}
	if(exists) {
		ev.type = ClientMessage;
		ev.xclient.window = c->win;
		ev.xclient.message_type = wmatom[WMProtocols];
		ev.xclient.format = 32;
		ev.xclient.data.l[0] = proto;
		ev.xclient.data.l[1] = CurrentTime;
		XSendEvent(dpy, c->win, False, NoEventMask, &ev);
	}
	return exists;
}

void
setfocus(Client *c) {
	if(!c->neverfocus)
		XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
	sendevent(c, wmatom[WMTakeFocus]);
}

void
setlayout(const Arg *arg) {
	if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
		selmon->sellt ^= 1;
	if(arg && arg->v)
		selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag] = (Layout *)arg->v;
	strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
	if(selmon->sel)
		arrange(selmon);
	else
		drawbar(selmon);
}

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

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

void
setup(void) {
	XSetWindowAttributes wa;

	/* clean up any zombies immediately */
	sigchld(0);

	/* init screen */
	screen = DefaultScreen(dpy);
	root = RootWindow(dpy, screen);
	initfont(font);
	sw = DisplayWidth(dpy, screen);
	sh = DisplayHeight(dpy, screen);
	bh = dc.h = dc.font.height + 2;
	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);
	wmatom[WMTakeFocus] = XInternAtom(dpy, "WM_TAKE_FOCUS", False);
	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
	/* init cursors */
	cursor[CurNormal] = XCreateFontCursor(dpy, XC_left_ptr);
	cursor[CurResize] = XCreateFontCursor(dpy, XC_sizing);
	cursor[CurMove] = XCreateFontCursor(dpy, XC_fleur);
	/* init appearance */
#ifndef XFT
   for(int i=0; i<MAXCOLORS; i++) {
      dc.colors[i][ColBorder] = getcolor( colors[i][ColBorder] );
      dc.colors[i][ColFG] = getcolor( colors[i][ColFG] );
      dc.colors[i][ColBG] = getcolor( colors[i][ColBG] );
   }
#else
   for(int i=0; i<MAXCOLORS; i++) {
      dc.colors[i][ColBorder] = getcolor( colors[i][ColBorder], &dc.xftcolors[i][ColBorder] );
      dc.colors[i][ColFG] = getcolor( colors[i][ColFG], &dc.xftcolors[i][ColFG] );
      dc.colors[i][ColBG] = getcolor( colors[i][ColBG], &dc.xftcolors[i][ColBG] );
   }
#endif
   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);
#ifndef XFT
   if(!dc.font.set)
      XSetFont(dpy, dc.gc, dc.font.xfont->fid);
#else
   dc.xftdrawable = XftDrawCreate(dpy, dc.drawable, DefaultVisual(dpy,screen), DefaultColormap(dpy,screen));
   if(!dc.xftdrawable)
      printf("error, cannot create drawable\n");
#endif 
        /* init bars */
	updatebars();
	updatestatus();
	/* EWMH support per view */
	XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
			PropModeReplace, (unsigned char *) netatom, NetLast);
	/* select for events */
	wa.cursor = cursor[CurNormal];
	wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask
	                |EnterWindowMask|LeaveWindowMask|StructureNotifyMask
	                |PropertyChangeMask;
	XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
	XSelectInput(dpy, root, wa.event_mask);
	grabkeys();

        /* set default tag layouts */
        for (int i = 0; i < LENGTH(tags); i++)
        {
                if (taglayouts[i]!=0)
                {
                        Layout *l;
                        view(&((Arg) { .ui = 1 << i }));
                        l = (Layout *)layouts;
                        for (int j = 0; j < taglayouts[i]; j++)
                                l++;
                        setlayout(&((Arg) { .v = l }));
                }
        }
        view(&((Arg) { .ui = 1 << 0 }));
}

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

void
sigchld(int unused) {
	if(signal(SIGCHLD, sigchld) == SIG_ERR)
		die("Can't install SIGCHLD handler");
	while(0 < waitpid(-1, NULL, WNOHANG));
}

void
spawn(const Arg *arg) {
	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(EXIT_SUCCESS);
	}
}

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

void
tagmon(const Arg *arg) {
	if(!selmon->sel || !mons->next)
		return;
	sendmon(selmon->sel, dirtomon(arg->i));
}

int
textnw(const char *text, unsigned int len) {
         // remove non-printing color codes before calculating width
         char *ptr = (char *) text;
         unsigned int i, ibuf, lenbuf=len;
         char buf[len+1];
         
         for(i=0, ibuf=0; *ptr && i<len; i++, ptr++) {
                 if(*ptr <= NUMCOLORS && *ptr > 0) {
                         if (i < len) { lenbuf--; }
                 } else {
                         buf[ibuf]=*ptr;
                         ibuf++;
                 }
         }
         buf[ibuf]=0;
 
#ifdef XFT
   PangoRectangle r;
   pango_layout_set_text(dc.plo, buf, lenbuf);
   pango_layout_get_extents(dc.plo, &r, 0);
   return r.width / PANGO_SCALE;
#else
   if(dc.font.set) {
      XRectangle r;
      XmbTextExtents(dc.font.set, buf, lenbuf, NULL, &r);
      return r.width;
   } else {
      return XTextWidth(dc.font.xfont, buf, lenbuf);
   }
#endif

}

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

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;
	/* master */
	c = nexttiled(m->clients);
	mw = m->mfact * m->ww;
	resize(c, m->wx, m->wy, (n == 1 ? m->ww : mw) - 2 * c->bw, m->wh - 2 * c->bw, False);
	if(--n == 0)
		return;
	/* tile stack */
	x = (m->wx + mw > c->x + c->w) ? c->x + c->w + 2 * c->bw : m->wx + mw;
	y = m->wy;
	w = (m->wx + mw > c->x + c->w) ? m->wx + m->ww - x : m->ww - mw;
	h = m->wh / n;
	if(h < bh)
		h = m->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)
		       ? m->wy + m->wh - y - 2 * c->bw : h - 2 * c->bw), False);
		if(h != m->wh)
			y = c->y + HEIGHT(c);
	}
}

static void
bstack(Monitor *m) {
	int x, y, h, w, mh;
	unsigned int i, n;
	Client *c;

	for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
	if(n == 0)
		return;
	/* master */
	c = nexttiled(m->clients);
	mh = m->mfact * m->wh;
	resize(c, m->wx, m->wy, m->ww - 2 * c->bw, (n == 1 ? m->wh : mh) - 2 * c->bw, False);
	if(--n == 0)
		return;
	/* tile stack */
	x = m->wx;
	y = (m->wy + mh > c->y + c->h) ? c->y + c->h + 2 * c->bw : m->wy + mh;
	w = m->ww / n;
	h = (m->wy + mh > c->y + c->h) ? m->wy + m->wh - y : m->wh - mh;
	if(w < bh)
		w = m->ww;
	for(i = 0, c = nexttiled(c->next); c; c = nexttiled(c->next), i++) {
		resize(c, x, y, /* remainder */ ((i + 1 == n)
		       ? m->wx + m->ww - x - 2 * c->bw : w - 2 * c->bw), h - 2 * c->bw, False);
		if(w != m->ww)
			x = c->x + WIDTH(c);
	}
}
 
void
grid(Monitor *m) {
	unsigned int i, n, cx, cy, cw, ch, aw, ah, cols, rows;
	Client *c;

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

	/* grid dimensions */	for(rows = 0; rows <= n/2; rows++)
		if(rows*rows >= n)
			break;
	cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;

	/* window geoms (cell height/width) */
	ch = m->wh / (rows ? rows : 1);
	cw = m->ww / (cols ? cols : 1);
	for(i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
		cx = m->wx + (i / rows) * cw;
		cy = m->wy + (i % rows) * ch;
		/* adjust height/width of last row/column's windows */
		ah = ((i + 1) % rows == 0) ? m->wh - ch * rows : 0;
		aw = (i >= rows * (cols - 1)) ? m->ww - cw * cols : 0;
		resize(c, cx, cy, cw - 2 * c->bw + aw, ch - 2 * c->bw + ah, False);
		i++;
	}
}

void
togglebar(const Arg *arg) {
	selmon->showbar = selmon->showbars[selmon->curtag] = !selmon->showbar;
	updatebarpos(selmon);
	XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
	arrange(selmon);
}

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

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

	if(!selmon->sel)
		return;
	newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
	if(newtags) {
		selmon->sel->tags = newtags;
		if(newtags == ~0) {
			selmon->prevtag = selmon->curtag;
			selmon->curtag = 0;
		}
		if(!(newtags & 1 << (selmon->curtag - 1))) {
			selmon->prevtag = selmon->curtag;
			for (i=0; !(newtags & 1 << i); i++);
			selmon->curtag = i + 1;
		}
		selmon->sel->tags = newtags;
		selmon->lt[selmon->sellt] = selmon->lts[selmon->curtag];
		selmon->mfact = selmon->mfacts[selmon->curtag];
		if (selmon->showbar != selmon->showbars[selmon->curtag])
			togglebar(NULL);
		arrange(selmon);
	}
}

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

	if(newtagset) {
		selmon->tagset[selmon->seltags] = newtagset;
		arrange(selmon);
	}
}

void
unfocus(Client *c, Bool setfocus) {
	if(!c)
		return;
	grabbuttons(c, False);
	XSetWindowBorder(dpy, c->win, dc.colors[0][ColBorder]);
	if(setfocus)
		XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
}

void
unmanage(Client *c, Bool destroyed) {
	Monitor *m = c->mon;
	XWindowChanges wc;

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

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

	if((c = wintoclient(ev->window)))
		unmanage(c, False);
}

void
updatebars(void) {
	Monitor *m;
	XSetWindowAttributes wa = {
		.override_redirect = True,
		.background_pixmap = ParentRelative,
		.event_mask = ButtonPressMask|ExposureMask
	};
	for(m = mons; m; m = m->next) {
		m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
		                          CopyFromParent, DefaultVisual(dpy, screen),
		                          CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
		XDefineCursor(dpy, m->barwin, cursor[CurNormal]);
		XMapRaised(dpy, m->barwin);
	}
}

void
updatebarpos(Monitor *m) {
	m->wy = m->my;
	m->wh = m->mh;
	if(m->showbar) {
		m->wh -= bh;
		m->by = m->topbar ? m->wy : m->wy + m->wh;
		m->wy = m->topbar ? m->wy + bh : m->wy;
	}
	else
		m->by = -bh;
}

Bool
updategeom(void) {
	Bool dirty = False;

#ifdef XINERAMA
	if(XineramaIsActive(dpy)) {
		int i, j, n, nn;
		Client *c;
		Monitor *m;
		XineramaScreenInfo *info = XineramaQueryScreens(dpy, &nn);
		XineramaScreenInfo *unique = NULL;

		for(n = 0, m = mons; m; m = m->next, n++);
		/* only consider unique geometries as separate screens */
		if(!(unique = (XineramaScreenInfo *)malloc(sizeof(XineramaScreenInfo) * nn)))
			die("fatal: could not malloc() %u bytes\n", sizeof(XineramaScreenInfo) * nn);
		for(i = 0, j = 0; i < nn; i++)
			if(isuniquegeom(unique, j, &info[i]))
				memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
		XFree(info);
		nn = j;
		if(n <= nn) {
			for(i = 0; i < (nn - n); i++) { /* new monitors available */
				for(m = mons; m && m->next; m = m->next);
				if(m)
					m->next = createmon();
				else
					mons = createmon();
			}
			for(i = 0, m = mons; i < nn && m; m = m->next, i++)
				if(i >= n
				|| (unique[i].x_org != m->mx || unique[i].y_org != m->my
				    || unique[i].width != m->mw || unique[i].height != m->mh))
				{
					dirty = True;
					m->num = i;
					m->mx = m->wx = unique[i].x_org;
					m->my = m->wy = unique[i].y_org;
					m->mw = m->ww = unique[i].width;
					m->mh = m->wh = unique[i].height - 18;
					updatebarpos(m);
				}
		}
		else { /* less monitors available nn < n */
			for(i = nn; i < n; i++) {
				for(m = mons; m && m->next; m = m->next);
				while(m->clients) {
					dirty = True;
					c = m->clients;
					m->clients = c->next;
					detachstack(c);
					c->mon = mons;
					attach(c);
					attachstack(c);
				}
				if(m == selmon)
					selmon = mons;
				cleanupmon(m);
			}
		}
		free(unique);
	}
	else
#endif /* XINERAMA */
	/* default monitor setup */
	{
		if(!mons)
			mons = createmon();
		if(mons->mw != sw || mons->mh != sh) {
			dirty = True;
			mons->mw = mons->ww = sw;
			mons->mh = mons->wh = sh;
			updatebarpos(mons);
		}
	}
	if(dirty) {
		selmon = mons;
		selmon = wintomon(root);
	}
	return dirty;
}

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 / size.min_aspect.x;
		c->maxa = (float)size.max_aspect.x / 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);
	if(c->name[0] == '\0') /* hack to mark broken clients */
		strcpy(c->name, broken);
}

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

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

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

void
view(const Arg *arg) {
	unsigned int i;

	if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
		return;
	selmon->seltags ^= 1; /* toggle sel tagset */
	if(arg->ui & TAGMASK) {
		selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
		selmon->prevtag = selmon->curtag;
		if(arg->ui == ~0)
			selmon->curtag = 0;
		else {
			for (i=0; !(arg->ui & 1 << i); i++);
			selmon->curtag = i + 1;
		}
	} else {
		selmon->prevtag= selmon->curtag ^ selmon->prevtag;
		selmon->curtag^= selmon->prevtag;
		selmon->prevtag= selmon->curtag ^ selmon->prevtag;
	}
	selmon->lt[selmon->sellt]= selmon->lts[selmon->curtag];
	selmon->mfact = selmon->mfacts[selmon->curtag];
	if(selmon->showbar != selmon->showbars[selmon->curtag])
		togglebar(NULL);
	arrange(selmon);
}

Client *
wintoclient(Window w) {
	Client *c;
	Monitor *m;

	for(m = mons; m; m = m->next)
		for(c = m->clients; c; c = c->next)
			if(c->win == w)
				return c;
	return NULL;
}

Monitor *
wintomon(Window w) {
	int x, y;
	Client *c;
	Monitor *m;

	if(w == root && getrootptr(&x, &y))
		return ptrtomon(x, y);
	for(m = mons; m; m = m->next)
		if(w == m->barwin)
			return m;
	if((c = wintoclient(w)))
		return c->mon;
	return selmon;
}

/* 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) {
	die("dwm: another window manager is already running\n");
	return -1;
}

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

	if(!selmon->lt[selmon->sellt]->arrange
	|| (selmon->sel && selmon->sel->isfloating))
		return;
	if(c == nexttiled(selmon->clients))
		if(!c || !(c = nexttiled(c->next)))
			return;
	pop(c);
}

int
main(int argc, char *argv[]) {
	if(argc == 2 && !strcmp("-v", argv[1]))
		die("dwm-"VERSION", © 2006-2011 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 EXIT_SUCCESS;
}

static int
shifttag(int dist)
{
        int i, curtags;
        int seltag = 0;
        int numtags = LENGTH(tags);

        curtags = selmon->tagset[selmon->seltags];
        for(i = 0; i < LENGTH(tags); i++) {
                if((curtags & (1 << i)) != 0) {
                        seltag = i;
                        break;
                }
        }

        seltag += dist;
        if(seltag < 0)
                seltag = numtags - (-seltag) % numtags;
        else
                seltag %= numtags;

        return 1 << seltag;
}

static void
cycle(const Arg *arg)
{
        const Arg a = { .i = shifttag(arg->i) };
        view(&a);
}

static void
tagcycle(const Arg *arg)
{
        const Arg a = { .i = shifttag(arg->i) };
        tag(&a);
        view(&a);
}

 
Thanks!


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#390 2011-10-26 17:37:25

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

@ivoarch
What font are you using? Also, the colors will not work that great with XFT unless you modify to the drawtext functions (and others that use color), use index instead of reference to the color struct. I haven't really tested the XFT support in my dwm.c that much, only few fonts.. So it might be rather buggy.

Offline

#391 2011-10-26 17:44:03

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

The font is Sans,  I think the problem is in
drawtext  or drawsquare,

Last edited by ivoarch (2011-10-26 23:26:00)


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#392 2011-10-27 04:12:10

3picide
Member
Registered: 2010-10-06
Posts: 6

Re: DWM Hackers Unite! Share (or request) dwm patches.

Anyone have any version of pertag working with the latest dwm? (preferably with bstack and the patch that removes borders from clients when they're the only one in the tag [forget the name])

I tried manually patching the newest version of dwm with the newest version of pertag from jokerboy's bitbucket. I can't find the source that is supposed to be at 1650 according to the patch. Most of the surrounding code isn't even in the file at all. The bits that are are too generic for me to know which function to patch.

Offline

#393 2011-10-27 06:07:20

Pooh-Bah
Member
Registered: 2011-07-13
Posts: 47

Re: DWM Hackers Unite! Share (or request) dwm patches.

I newbie in DWM, but don't like how DWM resizes windows. Long time I use tmux and tmux "passive" tiling is better, imho.

Default dwm using "active" splitting, - when open new windows, it resizes previous too. Looks like:
tYXp6Ng

I want like in tmux, "passive" splitting, do not resize previous windows at right:
tYXp6Nw

Offline

#394 2011-10-27 06:38:05

JokerBoy
Member
From: România
Registered: 2009-09-24
Posts: 641

Re: DWM Hackers Unite! Share (or request) dwm patches.

3picide wrote:

Anyone have any version of pertag working with the latest dwm? (preferably with bstack and the patch that removes borders from clients when they're the only one in the tag [forget the name])

I tried manually patching the newest version of dwm with the newest version of pertag from jokerboy's bitbucket. I can't find the source that is supposed to be at 1650 according to the patch. Most of the surrounding code isn't even in the file at all. The bits that are are too generic for me to know which function to patch.

monocle_no_borders.diff?

I'll be switching back to -hg in a few days.. So you can wait. The pertag2 patch doesn't apply now 'cause tile was replaced with something similar to ntile, but without the pertag support.

Offline

#395 2011-10-27 07:38:59

lolilolicon
Member
Registered: 2009-03-05
Posts: 1,722

Re: DWM Hackers Unite! Share (or request) dwm patches.

Pooh-Bah wrote:

I newbie in DWM, but don't like how DWM resizes windows. Long time I use tmux and tmux "passive" tiling is better, imho.

Default dwm using "active" splitting, - when open new windows, it resizes previous too. Looks like:
http://ompldr.org/tYXp6Ng

I want like in tmux, "passive" splitting, do not resize previous windows at right:
http://ompldr.org/tYXp6Nw

Manual tiling is better suited for you, it seems.


This silver ladybug at line 28...

Offline

#396 2011-10-27 19:19:55

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

@ivoarch
Sorry for late reply, I tested the font and different sizes on my dwm.c and could not reproduce, so I'll check your code and try to find what's wrong.

E: at your drawtext function do this:

#ifndef XFT
   y    = dc.y + ((dc.h + dc.font.ascent - dc.font.descent) / 2);
#else
   y    = dc.y + dc.h - dc.font.height;
#endif

I suggest grepping XFT on the sources in my master branch, if there are more issues.

Last edited by Cloudef (2011-10-27 19:43:47)

Offline

#397 2011-10-29 11:14:39

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

@Cloudef 

Before   tYXpwOA

I removed this part of my dwm.c 

+ // remove non-printing color codes before calculating width
+ char *ptr = (char *) text;
+ unsigned int i, ibuf, lenbuf=len;
+ char buf[len+1];
+ XRectangle r;
+ for(i=0, ibuf=0; *ptr && i<len; i++, ptr++) {
+ if(*ptr <= NUMCOLORS && *ptr > 0) {
+ if (i < len) { lenbuf--; }
+ } else {
+ buf[ibuf]=*ptr;
+ ibuf++;
+ }
+ }
+ buf[ibuf]=0;
+
+ if(dc.font.set) {
+ XmbTextExtents(dc.font.set, buf, lenbuf, NULL, &r);
+ return r.width;
+ }
+ return XTextWidth(dc.font.xfont, buf, lenbuf);
 }  

the part is from new version of the statuscolors patch http://lists.suckless.org/dev/1011/6445.html
and WORK!!   

now looks like this

int
textnw(const char *text, unsigned int len) {
 
#ifdef XFT
   PangoRectangle r;
   pango_layout_set_text(dc.plo, text, len);
   pango_layout_get_extents(dc.plo, &r, 0);
   return r.width / PANGO_SCALE;
#else
   XRectangle r;

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

} 

But some double free()
tYjB5YQ
any idea how to change this  i=0, ibuf=0; and ptr > 0  buf[ibuf]=0;

Last edited by ivoarch (2011-10-29 11:28:52)


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#398 2011-10-29 12:07:27

Cloudef
Member
Registered: 2010-10-12
Posts: 636

Re: DWM Hackers Unite! Share (or request) dwm patches.

@ivoarch
Double free doesn't at least come from that part of code. Can't really help, even the newer screenshot you posted has some spacing issues, which I don't get with the same font.

Offline

#399 2011-10-29 15:53:37

ivoarch
Member
Registered: 2011-03-31
Posts: 436

Re: DWM Hackers Unite! Share (or request) dwm patches.

@Cloudef 

Thanks for the answer,I'll leave it so of moment


I love GnuEmacs, GnuScreen, ratpoison, and conkeror.
Github )||( Weblog

Offline

#400 2011-10-29 17:16:02

Army
Member
Registered: 2007-12-07
Posts: 1,784

Re: DWM Hackers Unite! Share (or request) dwm patches.

Hi guys

I can't find anything about this on the interweb, so I'll ask here:

Can I disable focus-follow-mouse in dwm? It drives me mad!
Is there a patch which provides a fullscreen mode? This one isn't really THAT important, but it would be nice in some situations.

Thanks guys!

Offline

Board footer

Powered by FluxBB