Merge branch 'dwm-statusallmons-20160731-56a31dc.diff' into patched
authorDaniel <thefekete@gmail.com>
Sat, 29 Dec 2018 01:06:23 +0000 (02:06 +0100)
committerDaniel <thefekete@gmail.com>
Sat, 29 Dec 2018 01:06:23 +0000 (02:06 +0100)
12 files changed:
BUGS [deleted file]
LICENSE
Makefile
README
TODO [deleted file]
config.def.h
config.mk
drw.c
drw.h
dwm.1
dwm.c
util.c

diff --git a/BUGS b/BUGS
deleted file mode 100644 (file)
index 6c9574a..0000000
--- a/BUGS
+++ /dev/null
@@ -1,44 +0,0 @@
----
-
-18:17 < Biolunar> when i change my resolution in dwm (to a smaller one) and then back to the native, the top bar is not repainted. that's since 5.7.2, in 5.6 it worked fine
-18:19 < Biolunar> is it just happening to me or a (known) bug?
-18:24 < Biolunar> and in addition, mplayers fullscreen is limited to the small resolution after i changed it back to the native
-
-reproducible with xrandr -s but not with --output and --mode, strange
-
----
-
-yet another corner case:
-open a terminal, focus another monitor, but without moving the mouse
-pointer there
-if there is no client on the other monitor to get the focus, then the
-terminal will be unfocused but it will accept input
-
----
-
-Donald Allen reported this:
-
-starting emacs from dmenu in archlinux results in missing configure of emacs, but mod1-space or mod1-shift-space fix this problem. this problem is new and did not happen in 1.6 xorg servers
-
----
-
-voltaic reports this:
-
-When I use two monitors, one larger in resolution than the other, the
-bar is drawn using the smaller x-dimension on both screens. I think
-what's happening is that there are two bars drawn, but the short bar
-is always on top of the long bar such that I can't see the information
-under the short bar. If I switch to the small screen, hide the short
-bar, and then switch to the large screen, the long bar is drawn
-correctly.
-
-A similar problem occurs when I have started dwm on a small resolution
-monitor (laptop screen) and then I switch to a large external display.
-When I do this, the bar itself is drawn for the original smaller
-resolution, but the information to be printed on the bar is
-right-aligned for a longer bar. So what I see is a bar that has the
-right hand side of it cut-off. See attached screenshot.
-
-I am using standard options for xrandr such as --output VGA1 --auto, etc.
-
----
diff --git a/LICENSE b/LICENSE
index 4fbb67e..954cdc9 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,18 +1,22 @@
 MIT/X Consortium License
 
-© 2006-2014 Anselm R Garbe <anselm@garbe.us>
-© 2010-2014 Hiltjo Posthuma <hiltjo@codemadness.org>
-© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
-© 2010-2011 Connor Lane Smith <cls@lubutu.com>
+© 2006-2017 Anselm R Garbe <anselm@garbe.us>
 © 2006-2009 Jukka Salmi <jukka at salmi dot ch>
-© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
+© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
 © 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
 © 2007-2009 Christof Musik <christof at sendfax dot de>
-© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
 © 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
 © 2008 Martin Hurton <martin dot hurton at gmail dot com>
 © 2008 Neale Pickett <neale dot woozle dot org>
-© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
+© 2009 Mate Nagy <mnagy at port70 dot net>
+© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
+© 2010-2012 Connor Lane Smith <cls@lubutu.com>
+© 2011 Christoph Lohmann <20h@r-36.net>
+© 2015-2016 Quentin Rameau <quinq@fifth.space>
+© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
+© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
 
 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
index 1ea40b7..77bcbc0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -15,46 +15,37 @@ options:
        @echo "CC       = ${CC}"
 
 .c.o:
-       @echo CC $<
-       @${CC} -c ${CFLAGS} $<
+       ${CC} -c ${CFLAGS} $<
 
 ${OBJ}: config.h config.mk
 
 config.h:
-       @echo creating $@ from config.def.h
-       @cp config.def.h $@
+       cp config.def.h $@
 
 dwm: ${OBJ}
-       @echo CC -o $@
-       @${CC} -o $@ ${OBJ} ${LDFLAGS}
+       ${CC} -o $@ ${OBJ} ${LDFLAGS}
 
 clean:
-       @echo cleaning
-       @rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
+       rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
 
 dist: clean
-       @echo creating dist tarball
-       @mkdir -p dwm-${VERSION}
-       @cp -R LICENSE TODO BUGS Makefile README config.def.h config.mk \
+       mkdir -p dwm-${VERSION}
+       cp -R LICENSE Makefile README config.def.h config.mk\
                dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
-       @tar -cf dwm-${VERSION}.tar dwm-${VERSION}
-       @gzip dwm-${VERSION}.tar
-       @rm -rf dwm-${VERSION}
+       tar -cf dwm-${VERSION}.tar dwm-${VERSION}
+       gzip dwm-${VERSION}.tar
+       rm -rf dwm-${VERSION}
 
 install: all
-       @echo installing executable file to ${DESTDIR}${PREFIX}/bin
-       @mkdir -p ${DESTDIR}${PREFIX}/bin
-       @cp -f dwm ${DESTDIR}${PREFIX}/bin
-       @chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
-       @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
-       @mkdir -p ${DESTDIR}${MANPREFIX}/man1
-       @sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
-       @chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
+       mkdir -p ${DESTDIR}${PREFIX}/bin
+       cp -f dwm ${DESTDIR}${PREFIX}/bin
+       chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
+       mkdir -p ${DESTDIR}${MANPREFIX}/man1
+       sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
+       chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
 
 uninstall:
-       @echo removing executable file from ${DESTDIR}${PREFIX}/bin
-       @rm -f ${DESTDIR}${PREFIX}/bin/dwm
-       @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
-       @rm -f ${DESTDIR}${MANPREFIX}/man1/dwm.1
+       rm -f ${DESTDIR}${PREFIX}/bin/dwm\
+               ${DESTDIR}${MANPREFIX}/man1/dwm.1
 
 .PHONY: all options clean dist install uninstall
diff --git a/README b/README
index 7abf1cf..95d4fd0 100644 (file)
--- a/README
+++ b/README
@@ -18,9 +18,6 @@ necessary as root):
 
     make clean install
 
-If you are going to use the default bluegray color scheme it is highly
-recommended to also install the bluegray files shipped in the dextra package.
-
 
 Running dwm
 -----------
diff --git a/TODO b/TODO
deleted file mode 100644 (file)
index b33a08d..0000000
--- a/TODO
+++ /dev/null
@@ -1,4 +0,0 @@
-- add a flag to Key to execute the command on release (needed for commands
-               affecting the keyboard grab, see scrot -s for example)
-- add updategeom() hook for external tools like dzen
-- consider onscreenkeyboard hooks for tablet deployment
index fd77a07..2d824d1 100644 (file)
@@ -3,6 +3,10 @@
 /* appearance */
 static const unsigned int borderpx  = 1;        /* border pixel of windows */
 static const unsigned int snap      = 32;       /* snap pixel */
+static const unsigned int systraypinning = 0;   /* 0: sloppy systray follows selected monitor, >0: pin systray to monitor X */
+static const unsigned int systrayspacing = 2;   /* systray spacing */
+static const int systraypinningfailfirst = 1;   /* 1: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
+static const int showsystray        = 1;     /* 0 means no systray */
 static const int showbar            = 1;        /* 0 means no bar */
 static const int topbar             = 1;        /* 0 means bottom bar */
 static const char *fonts[]          = { "monospace:size=10" };
@@ -12,10 +16,10 @@ static const char col_gray2[]       = "#444444";
 static const char col_gray3[]       = "#bbbbbb";
 static const char col_gray4[]       = "#eeeeee";
 static const char col_cyan[]        = "#005577";
-static const char *colors[SchemeLast][3]      = {
+static const char *colors[][3]      = {
        /*               fg         bg         border   */
        [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
-       [SchemeSel]  { col_gray4, col_cyan,  col_cyan  },
+       [SchemeSel]  = { col_gray4, col_cyan,  col_cyan  },
 };
 
 /* tagging */
@@ -97,7 +101,7 @@ static Key keys[] = {
 };
 
 /* button definitions */
-/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
 static Button buttons[] = {
        /* click                event mask      button          function        argument */
        { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
index 80dc936..25e2685 100644 (file)
--- a/config.mk
+++ b/config.mk
@@ -28,7 +28,7 @@ LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
 CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
 #CFLAGS   = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
 CFLAGS   = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
-LDFLAGS  = -s ${LIBS}
+LDFLAGS  = ${LIBS}
 
 # Solaris
 #CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
diff --git a/drw.c b/drw.c
index 987e53b..c638323 100644 (file)
--- a/drw.c
+++ b/drw.c
@@ -129,7 +129,7 @@ xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
                        return NULL;
                }
        } else {
-               die("no font specified.\n");
+               die("no font specified.");
        }
 
        font = ecalloc(1, sizeof(Fnt));
@@ -180,7 +180,7 @@ drw_fontset_free(Fnt *font)
 }
 
 void
-drw_clr_create(Drw *drw, XftColor *dest, const char *clrname)
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
 {
        if (!drw || !dest || !clrname)
                return;
@@ -188,19 +188,19 @@ drw_clr_create(Drw *drw, XftColor *dest, const char *clrname)
        if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
                               DefaultColormap(drw->dpy, drw->screen),
                               clrname, dest))
-               die("error, cannot allocate color '%s'\n", clrname);
+               die("error, cannot allocate color '%s'", clrname);
 }
 
 /* Wrapper to create color schemes. The caller has to call free(3) on the
  * returned color scheme when done using it. */
-Scm
+Clr *
 drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
 {
        size_t i;
-       Scm ret;
+       Clr *ret;
 
        /* need at least two colors for a scheme */
-       if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
+       if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(Clr))))
                return NULL;
 
        for (i = 0; i < clrcount; i++)
@@ -216,7 +216,7 @@ drw_setfontset(Drw *drw, Fnt *set)
 }
 
 void
-drw_setscheme(Drw *drw, Scm scm)
+drw_setscheme(Drw *drw, Clr *scm)
 {
        if (drw)
                drw->scheme = scm;
@@ -331,7 +331,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
 
                        if (!drw->fonts->pattern) {
                                /* Refer to the comment in xfont_create for more information. */
-                               die("the first font in the cache must be loaded from a font string.\n");
+                               die("the first font in the cache must be loaded from a font string.");
                        }
 
                        fcpattern = FcPatternDuplicate(drw->fonts->pattern);
diff --git a/drw.h b/drw.h
index ff4355b..4bcd5ad 100644 (file)
--- a/drw.h
+++ b/drw.h
@@ -12,8 +12,8 @@ typedef struct Fnt {
        struct Fnt *next;
 } Fnt;
 
-enum { ColFg, ColBg, ColCount }; /* Scm index */
-typedef XftColor *Scm;
+enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */
+typedef XftColor Clr;
 
 typedef struct {
        unsigned int w, h;
@@ -22,7 +22,7 @@ typedef struct {
        Window root;
        Drawable drawable;
        GC gc;
-       Scm scheme;
+       Clr *scheme;
        Fnt *fonts;
 } Drw;
 
@@ -38,8 +38,8 @@ unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
 void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
 
 /* Colorscheme abstraction */
-void drw_clr_create(Drw *drw, XftColor *dest, const char *clrname);
-Scm drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
 
 /* Cursor abstraction */
 Cur *drw_cur_create(Drw *drw, int shape);
@@ -47,7 +47,7 @@ void drw_cur_free(Drw *drw, Cur *cursor);
 
 /* Drawing context manipulation */
 void drw_setfontset(Drw *drw, Fnt *set);
-void drw_setscheme(Drw *drw, Scm scm);
+void drw_setscheme(Drw *drw, Clr *scm);
 
 /* Drawing functions */
 void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
diff --git a/dwm.1 b/dwm.1
index 6687011..13b3729 100644 (file)
--- a/dwm.1
+++ b/dwm.1
@@ -10,8 +10,9 @@ and floating layouts. Either layout can be applied dynamically, optimising the
 environment for the application in use and the task performed.
 .P
 In tiled layouts windows are managed in a master and stacking area. The master
-area contains the window which currently needs most attention, whereas the
-stacking area contains all other windows. In monocle layout all windows are
+area on the left contains one window by default, and the stacking area on the
+right contains all other windows. The number of master area windows can be
+adjusted from zero to an arbitrary number. In monocle layout all windows are
 maximised to the screen size. In floating layout windows can be resized and
 moved freely. Dialog windows are always managed floating, regardless of the
 layout applied.
@@ -59,6 +60,11 @@ click on a tag label adds/removes that tag to/from the focused window.
 Start
 .BR st(1).
 .TP
+.B Mod1\-p
+Spawn
+.BR dmenu(1)
+for launching other programs.
+.TP
 .B Mod1\-,
 Focus previous screen, if any.
 .TP
@@ -93,10 +99,10 @@ Focus next window.
 Focus previous window.
 .TP
 .B Mod1\-i
-Increase clients in master area.
+Increase number of windows in master area.
 .TP
 .B Mod1\-d
-Decrease clients in master area.
+Decrease number of windows in master area.
 .TP
 .B Mod1\-l
 Increase master area size.
@@ -152,7 +158,7 @@ code. This keeps it fast, secure and simple.
 .SH SEE ALSO
 .BR dmenu (1),
 .BR st (1)
-.SH BUGS
+.SH ISSUES
 Java applications which use the XToolkit/XAWT backend may draw grey windows
 only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
 JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds
@@ -166,11 +172,5 @@ or
 (to pretend that a non-reparenting window manager is running that the
 XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable
 .BR _JAVA_AWT_WM_NONREPARENTING=1 .
-.P
-GTK 2.10.9+ versions contain a broken
-.BR Save\-As
-file dialog implementation,
-which requests to reconfigure its window size in an endless loop. However, its
-window is still respondable during this state, so you can simply ignore the flicker
-until a new GTK version appears, which will fix this bug, approximately
-GTK 2.10.12+ versions.
+.SH BUGS
+Send all bug reports with a patch to hackers@suckless.org.
diff --git a/dwm.c b/dwm.c
index 5217517..3c99798 100644 (file)
--- a/dwm.c
+++ b/dwm.c
@@ -3,7 +3,7 @@
  * 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
+ * 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
@@ -11,7 +11,7 @@
  * 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
+ * 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.
 #define HEIGHT(X)               ((X)->h + 2 * (X)->bw)
 #define TAGMASK                 ((1 << LENGTH(tags)) - 1)
 #define TEXTW(X)                (drw_fontset_getwidth(drw, (X)) + lrpad)
-#define ColBorder               2
+
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY      0
+#define XEMBED_WINDOW_ACTIVATE      1
+#define XEMBED_FOCUS_IN             4
+#define XEMBED_MODALITY_ON         10
+
+#define XEMBED_MAPPED              (1 << 0)
+#define XEMBED_WINDOW_ACTIVATE      1
+#define XEMBED_WINDOW_DEACTIVATE    2
+
+#define VERSION_MAJOR               0
+#define VERSION_MINOR               0
+#define XEMBED_EMBEDDED_VERSION (VERSION_MAJOR << 16) | VERSION_MINOR
 
 /* enums */
 enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
-enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
-enum { NetSupported, NetWMName, NetWMState,
+enum { SchemeNorm, SchemeSel }; /* color schemes */
+enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
+       NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation, NetSystemTrayOrientationHorz,
        NetWMFullscreen, NetActiveWindow, NetWMWindowType,
        NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
 enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
 enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
        ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
@@ -89,6 +106,7 @@ struct Client {
        char name[256];
        float mina, maxa;
        int x, y, w, h;
+       int sfx, sfy, sfw, sfh; /* stored float geometry, used on mode revert */
        int oldx, oldy, oldw, oldh;
        int basew, baseh, incw, inch, maxw, maxh, minw, minh;
        int bw, oldbw;
@@ -142,6 +160,12 @@ typedef struct {
        int monitor;
 } Rule;
 
+typedef struct Systray   Systray;
+struct Systray {
+       Window win;
+       Client *icons;
+};
+
 /* function declarations */
 static void applyrules(Client *c);
 static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
@@ -153,7 +177,6 @@ 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);
@@ -171,8 +194,10 @@ static void focus(Client *c);
 static void focusin(XEvent *e);
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
+static Atom getatomprop(Client *c, Atom prop);
 static int getrootptr(int *x, int *y);
 static long getstate(Window w);
+static unsigned int getsystraywidth();
 static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
 static void grabbuttons(Client *c, int focused);
 static void grabkeys(void);
@@ -190,13 +215,16 @@ static void pop(Client *);
 static void propertynotify(XEvent *e);
 static void quit(const Arg *arg);
 static Monitor *recttomon(int x, int y, int w, int h);
+static void removesystrayicon(Client *i);
 static void resize(Client *c, int x, int y, int w, int h, int interact);
+static void resizebarwin(Monitor *m);
 static void resizeclient(Client *c, int x, int y, int w, int h);
 static void resizemouse(const Arg *arg);
+static void resizerequest(XEvent *e);
 static void restack(Monitor *m);
 static void run(void);
 static void scan(void);
-static int sendevent(Client *c, Atom proto);
+static int sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
 static void sendmon(Client *c, Monitor *m);
 static void setclientstate(Client *c, long state);
 static void setfocus(Client *c);
@@ -204,9 +232,11 @@ static void setfullscreen(Client *c, int fullscreen);
 static void setlayout(const Arg *arg);
 static void setmfact(const Arg *arg);
 static void setup(void);
+static void seturgent(Client *c, int urg);
 static void showhide(Client *c);
 static void sigchld(int unused);
 static void spawn(const Arg *arg);
+static Monitor *systraytomon(Monitor *m);
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static void tile(Monitor *);
@@ -217,25 +247,30 @@ static void toggleview(const Arg *arg);
 static void unfocus(Client *c, int setfocus);
 static void unmanage(Client *c, int destroyed);
 static void unmapnotify(XEvent *e);
-static int updategeom(void);
 static void updatebarpos(Monitor *m);
 static void updatebars(void);
 static void updateclientlist(void);
+static int updategeom(void);
 static void updatenumlockmask(void);
 static void updatesizehints(Client *c);
 static void updatestatus(void);
-static void updatewindowtype(Client *c);
+static void updatesystray(void);
+static void updatesystrayicongeom(Client *i, int w, int h);
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
 static void updatetitle(Client *c);
+static void updatewindowtype(Client *c);
 static void updatewmhints(Client *c);
 static void view(const Arg *arg);
 static Client *wintoclient(Window w);
 static Monitor *wintomon(Window w);
+static Client *wintosystrayicon(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 Systray *systray =  NULL;
 static const char broken[] = "broken";
 static char stext[256];
 static int screen;
@@ -258,16 +293,17 @@ static void (*handler[LASTEvent]) (XEvent *) = {
        [MapRequest] = maprequest,
        [MotionNotify] = motionnotify,
        [PropertyNotify] = propertynotify,
+       [ResizeRequest] = resizerequest,
        [UnmapNotify] = unmapnotify
 };
-static Atom wmatom[WMLast], netatom[NetLast];
+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
 static int running = 1;
 static Cur *cursor[CurLast];
-static Scm scheme[SchemeLast];
+static Clr **scheme;
 static Display *dpy;
 static Drw *drw;
 static Monitor *mons, *selmon;
-static Window root;
+static Window root, wmcheckwin;
 
 /* configuration, allows nested code to access above variables */
 #include "config.h"
@@ -446,6 +482,8 @@ buttonpress(XEvent *e)
                        click = ClkWinTitle;
        } else if ((c = wintoclient(ev->window))) {
                focus(c);
+               restack(selmon);
+               XAllowEvents(dpy, ReplayPointer, CurrentTime);
                click = ClkClientWin;
        }
        for (i = 0; i < LENGTH(buttons); i++)
@@ -481,10 +519,16 @@ cleanup(void)
        XUngrabKey(dpy, AnyKey, AnyModifier, root);
        while (mons)
                cleanupmon(mons);
+       if (showsystray) {
+               XUnmapWindow(dpy, systray->win);
+               XDestroyWindow(dpy, systray->win);
+               free(systray);
+       }
        for (i = 0; i < CurLast; i++)
                drw_cur_free(drw, cursor[i]);
-       for (i = 0; i < SchemeLast; i++)
+       for (i = 0; i < LENGTH(colors); i++)
                free(scheme[i]);
+       XDestroyWindow(dpy, wmcheckwin);
        drw_free(drw);
        XSync(dpy, False);
        XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
@@ -507,37 +551,65 @@ cleanupmon(Monitor *mon)
        free(mon);
 }
 
-void
-clearurgent(Client *c)
-{
-       XWMHints *wmh;
-
-       c->isurgent = 0;
-       if (!(wmh = XGetWMHints(dpy, c->win)))
-               return;
-       wmh->flags &= ~XUrgencyHint;
-       XSetWMHints(dpy, c->win, wmh);
-       XFree(wmh);
-}
-
 void
 clientmessage(XEvent *e)
 {
+       XWindowAttributes wa;
+       XSetWindowAttributes swa;
        XClientMessageEvent *cme = &e->xclient;
        Client *c = wintoclient(cme->window);
 
+       if (showsystray && cme->window == systray->win && cme->message_type == netatom[NetSystemTrayOP]) {
+               /* add systray icons */
+               if (cme->data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) {
+                       if (!(c = (Client *)calloc(1, sizeof(Client))))
+                               die("fatal: could not malloc() %u bytes\n", sizeof(Client));
+                       if (!(c->win = cme->data.l[2])) {
+                               free(c);
+                               return;
+                       }
+                       c->mon = selmon;
+                       c->next = systray->icons;
+                       systray->icons = c;
+                       XGetWindowAttributes(dpy, c->win, &wa);
+                       c->x = c->oldx = c->y = c->oldy = 0;
+                       c->w = c->oldw = wa.width;
+                       c->h = c->oldh = wa.height;
+                       c->oldbw = wa.border_width;
+                       c->bw = 0;
+                       c->isfloating = True;
+                       /* reuse tags field as mapped status */
+                       c->tags = 1;
+                       updatesizehints(c);
+                       updatesystrayicongeom(c, wa.width, wa.height);
+                       XAddToSaveSet(dpy, c->win);
+                       XSelectInput(dpy, c->win, StructureNotifyMask | PropertyChangeMask | ResizeRedirectMask);
+                       XReparentWindow(dpy, c->win, systray->win, 0, 0);
+                       /* use parents background color */
+                       swa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+                       XChangeWindowAttributes(dpy, c->win, CWBackPixel, &swa);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_EMBEDDED_NOTIFY, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       /* FIXME not sure if I have to send these events, too */
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_FOCUS_IN, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       sendevent(c->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_MODALITY_ON, 0 , systray->win, XEMBED_EMBEDDED_VERSION);
+                       XSync(dpy, False);
+                       resizebarwin(selmon);
+                       updatesystray();
+                       setclientstate(c, NormalState);
+               }
+               return;
+       }
        if (!c)
                return;
        if (cme->message_type == netatom[NetWMState]) {
-               if (cme->data.l[1] == netatom[NetWMFullscreen] || cme->data.l[2] == netatom[NetWMFullscreen])
+               if (cme->data.l[1] == netatom[NetWMFullscreen]
+               || cme->data.l[2] == netatom[NetWMFullscreen])
                        setfullscreen(c, (cme->data.l[0] == 1 /* _NET_WM_STATE_ADD    */
-                                     || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
+                               || (cme->data.l[0] == 2 /* _NET_WM_STATE_TOGGLE */ && !c->isfullscreen)));
        } else if (cme->message_type == netatom[NetActiveWindow]) {
-               if (!ISVISIBLE(c)) {
-                       c->mon->seltags ^= 1;
-                       c->mon->tagset[c->mon->seltags] = c->tags;
-               }
-               pop(c);
+               if (c != selmon->sel && !c->isurgent)
+                       seturgent(c, 1);
        }
 }
 
@@ -580,7 +652,7 @@ configurenotify(XEvent *e)
                                for (c = m->clients; c; c = c->next)
                                        if (c->isfullscreen)
                                                resizeclient(c, m->mx, m->my, m->mw, m->mh);
-                               XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+                               resizebarwin(m);
                        }
                        focus(NULL);
                        arrange(NULL);
@@ -665,6 +737,11 @@ destroynotify(XEvent *e)
 
        if ((c = wintoclient(ev->window)))
                unmanage(c, 1);
+       else if ((c = wintosystrayicon(ev->window))) {
+               removesystrayicon(c);
+               resizebarwin(selmon);
+               updatesystray();
+       }
 }
 
 void
@@ -708,19 +785,23 @@ dirtomon(int dir)
 void
 drawbar(Monitor *m)
 {
-       int x, w, sw = 0;
+       int x, w, sw = 0, stw = 0;
        int boxs = drw->fonts->h / 9;
        int boxw = drw->fonts->h / 6 + 2;
        unsigned int i, occ = 0, urg = 0;
        Client *c;
 
+       if(showsystray && m == systraytomon(m))
+               stw = getsystraywidth();
+
        /* draw status first so it can be overdrawn by tags later */
        if (m == selmon || 1) { /* status is only drawn on selected monitor */
                drw_setscheme(drw, scheme[SchemeNorm]);
-               sw = TEXTW(stext) - lrpad / 2; /* no right padding so status text hugs the corner */
-               drw_text(drw, m->ww - sw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
+               sw = TEXTW(stext) - lrpad / 2 + 2; /* 2px right padding */
+               drw_text(drw, m->ww - sw - stw, 0, sw, bh, lrpad / 2 - 2, stext, 0);
        }
 
+       resizebarwin(m);
        for (c = m->clients; c; c = c->next) {
                occ |= c->tags;
                if (c->isurgent)
@@ -733,15 +814,15 @@ drawbar(Monitor *m)
                drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
                if (occ & 1 << i)
                        drw_rect(drw, x + boxs, boxs, boxw, boxw,
-                                m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
-                                urg & 1 << i);
+                               m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+                               urg & 1 << i);
                x += w;
        }
        w = blw = TEXTW(m->ltsymbol);
        drw_setscheme(drw, scheme[SchemeNorm]);
        x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
 
-       if ((w = m->ww - sw - x) > bh) {
+       if ((w = m->ww - sw - stw - x) > bh) {
                if (m->sel) {
                        drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
                        drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
@@ -752,7 +833,7 @@ drawbar(Monitor *m)
                        drw_rect(drw, x, 0, w, bh, 1, 1);
                }
        }
-       drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+       drw_map(drw, m->barwin, 0, 0, m->ww - stw, bh);
 }
 
 void
@@ -789,8 +870,11 @@ expose(XEvent *e)
        Monitor *m;
        XExposeEvent *ev = &e->xexpose;
 
-       if (ev->count == 0 && (m = wintomon(ev->window)))
+       if (ev->count == 0 && (m = wintomon(ev->window))) {
                drawbar(m);
+               if (m == selmon)
+                       updatesystray();
+       }
 }
 
 void
@@ -798,14 +882,13 @@ focus(Client *c)
 {
        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, 0);
        if (c) {
                if (c->mon != selmon)
                        selmon = c->mon;
                if (c->isurgent)
-                       clearurgent(c);
+                       seturgent(c, 0);
                detachstack(c);
                attachstack(c);
                grabbuttons(c, 1);
@@ -819,7 +902,7 @@ focus(Client *c)
        drawbars();
 }
 
-/* there are some broken focus acquiring clients */
+/* there are some broken focus acquiring clients needing extra handling */
 void
 focusin(XEvent *e)
 {
@@ -838,8 +921,7 @@ focusmon(const Arg *arg)
                return;
        if ((m = dirtomon(arg->i)) == selmon)
                return;
-       unfocus(selmon->sel, 0); /* s/1/0/ fixes input focus issues
-                                       in gedit and anjuta */
+       unfocus(selmon->sel, 0);
        selmon = m;
        focus(NULL);
 }
@@ -877,10 +959,17 @@ getatomprop(Client *c, Atom prop)
        unsigned long dl;
        unsigned char *p = NULL;
        Atom da, atom = None;
-
-       if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, XA_ATOM,
-                             &da, &di, &dl, &dl, &p) == Success && p) {
+       /* FIXME getatomprop should return the number of items and a pointer to
+        * the stored data instead of this workaround */
+       Atom req = XA_ATOM;
+       if (prop == xatom[XembedInfo])
+               req = xatom[XembedInfo];
+
+       if (XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False, req,
+               &da, &di, &dl, &dl, &p) == Success && p) {
                atom = *(Atom *)p;
+               if (da == xatom[XembedInfo] && dl == 2)
+                       atom = ((Atom *)p)[1];
                XFree(p);
        }
        return atom;
@@ -906,7 +995,7 @@ getstate(Window w)
        Atom real;
 
        if (XGetWindowProperty(dpy, w, wmatom[WMState], 0L, 2L, False, wmatom[WMState],
-                             &real, &format, &n, &extra, (unsigned char **)&p) != Success)
+               &real, &format, &n, &extra, (unsigned char **)&p) != Success)
                return -1;
        if (n != 0)
                result = *p;
@@ -914,6 +1003,16 @@ getstate(Window w)
        return result;
 }
 
+unsigned int
+getsystraywidth()
+{
+       unsigned int w = 0;
+       Client *i;
+       if(showsystray)
+               for(i = systray->icons; i; w += i->w + systrayspacing, i = i->next) ;
+       return w ? w + systrayspacing : 1;
+}
+
 int
 gettextprop(Window w, Atom atom, char *text, unsigned int size)
 {
@@ -924,8 +1023,7 @@ gettextprop(Window w, Atom atom, char *text, unsigned int size)
        if (!text || size == 0)
                return 0;
        text[0] = '\0';
-       XGetTextProperty(dpy, w, &name, atom);
-       if (!name.nitems)
+       if (!XGetTextProperty(dpy, w, &name, atom) || !name.nitems)
                return 0;
        if (name.encoding == XA_STRING)
                strncpy(text, (char *)name.value, size - 1);
@@ -948,17 +1046,16 @@ grabbuttons(Client *c, int focused)
                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
+               if (!focused)
                        XGrabButton(dpy, AnyButton, AnyModifier, c->win, False,
-                                   BUTTONMASK, GrabModeAsync, GrabModeSync, None, None);
+                               BUTTONMASK, GrabModeSync, GrabModeSync, None, None);
+               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);
        }
 }
 
@@ -976,7 +1073,7 @@ grabkeys(void)
                        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);
+                                               True, GrabModeAsync, GrabModeAsync);
        }
 }
 
@@ -1020,7 +1117,7 @@ killclient(const Arg *arg)
 {
        if (!selmon->sel)
                return;
-       if (!sendevent(selmon->sel, wmatom[WMDelete])) {
+       if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
                XGrabServer(dpy);
                XSetErrorHandler(xerrordummy);
                XSetCloseDownMode(dpy, DestroyAll);
@@ -1063,7 +1160,7 @@ manage(Window w, XWindowAttributes *wa)
        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 == c->mon->my) && (c->x + (c->w / 2) >= c->mon->wx)
-                  && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
+               && (c->x + (c->w / 2) < c->mon->wx + c->mon->ww)) ? bh : c->mon->my);
        c->bw = borderpx;
 
        wc.border_width = c->bw;
@@ -1073,6 +1170,10 @@ manage(Window w, XWindowAttributes *wa)
        updatewindowtype(c);
        updatesizehints(c);
        updatewmhints(c);
+       c->sfx = c->x;
+       c->sfy = c->y;
+       c->sfw = c->w;
+       c->sfh = c->h;
        XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
        grabbuttons(c, 0);
        if (!c->isfloating)
@@ -1082,7 +1183,7 @@ manage(Window w, XWindowAttributes *wa)
        attach(c);
        attachstack(c);
        XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
-                       (unsigned char *) &(c->win), 1);
+               (unsigned char *) &(c->win), 1);
        XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
        setclientstate(c, NormalState);
        if (c->mon == selmon)
@@ -1108,6 +1209,12 @@ maprequest(XEvent *e)
 {
        static XWindowAttributes wa;
        XMapRequestEvent *ev = &e->xmaprequest;
+       Client *i;
+       if ((i = wintosystrayicon(ev->window))) {
+               sendevent(i->win, netatom[Xembed], StructureNotifyMask, CurrentTime, XEMBED_WINDOW_ACTIVATE, 0, systray->win, XEMBED_EMBEDDED_VERSION);
+               resizebarwin(selmon);
+               updatesystray();
+       }
 
        if (!XGetWindowAttributes(dpy, ev->window, &wa))
                return;
@@ -1166,7 +1273,7 @@ movemouse(const Arg *arg)
        ocx = c->x;
        ocy = c->y;
        if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
-       None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
+               None, cursor[CurMove]->cursor, CurrentTime) != GrabSuccess)
                return;
        if (!getrootptr(&x, &y))
                return;
@@ -1185,20 +1292,17 @@ movemouse(const Arg *arg)
 
                        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 (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, 1);
                        break;
@@ -1235,6 +1339,16 @@ propertynotify(XEvent *e)
        Window trans;
        XPropertyEvent *ev = &e->xproperty;
 
+       if ((c = wintosystrayicon(ev->window))) {
+               if (ev->atom == XA_WM_NORMAL_HINTS) {
+                       updatesizehints(c);
+                       updatesystrayicongeom(c, c->w, c->h);
+               }
+               else
+                       updatesystrayiconstate(c, ev);
+               resizebarwin(selmon);
+               updatesystray();
+       }
        if ((ev->window == root) && (ev->atom == XA_WM_NAME))
                updatestatus();
        else if (ev->state == PropertyDelete)
@@ -1244,7 +1358,7 @@ propertynotify(XEvent *e)
                default: break;
                case XA_WM_TRANSIENT_FOR:
                        if (!c->isfloating && (XGetTransientForHint(dpy, c->win, &trans)) &&
-                          (c->isfloating = (wintoclient(trans)) != NULL))
+                               (c->isfloating = (wintoclient(trans)) != NULL))
                                arrange(c->mon);
                        break;
                case XA_WM_NORMAL_HINTS:
@@ -1285,6 +1399,20 @@ recttomon(int x, int y, int w, int h)
        return r;
 }
 
+void
+removesystrayicon(Client *i)
+{
+       Client **ii;
+
+       if (!showsystray || !i)
+               return;
+       for (ii = &systray->icons; *ii && *ii != i; ii = &(*ii)->next);
+       if (ii)
+               *ii = i->next;
+       free(i);
+}
+
+
 void
 resize(Client *c, int x, int y, int w, int h, int interact)
 {
@@ -1292,6 +1420,14 @@ resize(Client *c, int x, int y, int w, int h, int interact)
                resizeclient(c, x, y, w, h);
 }
 
+void
+resizebarwin(Monitor *m) {
+       unsigned int w = m->ww;
+       if (showsystray && m == systraytomon(m))
+               w -= getsystraywidth();
+       XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, w, bh);
+}
+
 void
 resizeclient(Client *c, int x, int y, int w, int h)
 {
@@ -1324,7 +1460,7 @@ resizemouse(const Arg *arg)
        ocx = c->x;
        ocy = c->y;
        if (XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
-                       None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
+               None, cursor[CurResize]->cursor, CurrentTime) != GrabSuccess)
                return;
        XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w + c->bw - 1, c->h + c->bw - 1);
        do {
@@ -1364,6 +1500,19 @@ resizemouse(const Arg *arg)
        }
 }
 
+void
+resizerequest(XEvent *e)
+{
+       XResizeRequestEvent *ev = &e->xresizerequest;
+       Client *i;
+
+       if ((i = wintosystrayicon(ev->window))) {
+               updatesystrayicongeom(i, ev->width, ev->height);
+               resizebarwin(selmon);
+               updatesystray();
+       }
+}
+
 void
 restack(Monitor *m)
 {
@@ -1449,30 +1598,40 @@ setclientstate(Client *c, long state)
        long data[] = { state, None };
 
        XChangeProperty(dpy, c->win, wmatom[WMState], wmatom[WMState], 32,
-                       PropModeReplace, (unsigned char *)data, 2);
+               PropModeReplace, (unsigned char *)data, 2);
 }
 
 int
-sendevent(Client *c, Atom proto)
+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4)
 {
        int n;
-       Atom *protocols;
+       Atom *protocols, mt;
        int exists = 0;
        XEvent ev;
 
-       if (XGetWMProtocols(dpy, c->win, &protocols, &n)) {
-               while (!exists && n--)
-                       exists = protocols[n] == proto;
-               XFree(protocols);
+       if (proto == wmatom[WMTakeFocus] || proto == wmatom[WMDelete]) {
+               mt = wmatom[WMProtocols];
+               if (XGetWMProtocols(dpy, w, &protocols, &n)) {
+                       while (!exists && n--)
+                               exists = protocols[n] == proto;
+                       XFree(protocols);
+               }
+       }
+       else {
+               exists = True;
+               mt = proto;
        }
        if (exists) {
                ev.type = ClientMessage;
-               ev.xclient.window = c->win;
-               ev.xclient.message_type = wmatom[WMProtocols];
+               ev.xclient.window = w;
+               ev.xclient.message_type = mt;
                ev.xclient.format = 32;
-               ev.xclient.data.l[0] = proto;
-               ev.xclient.data.l[1] = CurrentTime;
-               XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+               ev.xclient.data.l[0] = d0;
+               ev.xclient.data.l[1] = d1;
+               ev.xclient.data.l[2] = d2;
+               ev.xclient.data.l[3] = d3;
+               ev.xclient.data.l[4] = d4;
+               XSendEvent(dpy, w, False, mask, &ev);
        }
        return exists;
 }
@@ -1483,10 +1642,10 @@ setfocus(Client *c)
        if (!c->neverfocus) {
                XSetInputFocus(dpy, c->win, RevertToPointerRoot, CurrentTime);
                XChangeProperty(dpy, root, netatom[NetActiveWindow],
-                               XA_WINDOW, 32, PropModeReplace,
-                               (unsigned char *) &(c->win), 1);
+                       XA_WINDOW, 32, PropModeReplace,
+                       (unsigned char *) &(c->win), 1);
        }
-       sendevent(c, wmatom[WMTakeFocus]);
+       sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
 }
 
 void
@@ -1494,7 +1653,7 @@ setfullscreen(Client *c, int fullscreen)
 {
        if (fullscreen && !c->isfullscreen) {
                XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
-                               PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
+                       PropModeReplace, (unsigned char*)&netatom[NetWMFullscreen], 1);
                c->isfullscreen = 1;
                c->oldstate = c->isfloating;
                c->oldbw = c->bw;
@@ -1504,7 +1663,7 @@ setfullscreen(Client *c, int fullscreen)
                XRaiseWindow(dpy, c->win);
        } else if (!fullscreen && c->isfullscreen){
                XChangeProperty(dpy, c->win, netatom[NetWMState], XA_ATOM, 32,
-                               PropModeReplace, (unsigned char*)0, 0);
+                       PropModeReplace, (unsigned char*)0, 0);
                c->isfullscreen = 0;
                c->isfloating = c->oldstate;
                c->bw = c->oldbw;
@@ -1531,7 +1690,7 @@ setlayout(const Arg *arg)
                drawbar(selmon);
 }
 
-/* arg > 1.0 will set mfact absolutly */
+/* arg > 1.0 will set mfact absolutely */
 void
 setmfact(const Arg *arg)
 {
@@ -1549,7 +1708,9 @@ setmfact(const Arg *arg)
 void
 setup(void)
 {
+       int i;
        XSetWindowAttributes wa;
+       Atom utf8string;
 
        /* clean up any zombies immediately */
        sigchld(0);
@@ -1561,47 +1722,82 @@ setup(void)
        root = RootWindow(dpy, screen);
        drw = drw_create(dpy, screen, root, sw, sh);
        if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
-               die("no fonts could be loaded.\n");
+               die("no fonts could be loaded.");
        lrpad = drw->fonts->h;
        bh = drw->fonts->h + 2;
        updategeom();
        /* init atoms */
+       utf8string = XInternAtom(dpy, "UTF8_STRING", False);
        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[NetSystemTray] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_S0", False);
+       netatom[NetSystemTrayOP] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_OPCODE", False);
+       netatom[NetSystemTrayOrientation] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION", False);
+       netatom[NetSystemTrayOrientationHorz] = XInternAtom(dpy, "_NET_SYSTEM_TRAY_ORIENTATION_HORZ", False);
        netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
        netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
+       netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
        netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
        netatom[NetWMWindowType] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
        netatom[NetWMWindowTypeDialog] = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
        netatom[NetClientList] = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
+       xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
+       xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
+       xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
        /* init cursors */
        cursor[CurNormal] = drw_cur_create(drw, XC_left_ptr);
        cursor[CurResize] = drw_cur_create(drw, XC_sizing);
        cursor[CurMove] = drw_cur_create(drw, XC_fleur);
        /* init appearance */
-       scheme[SchemeNorm] = drw_scm_create(drw, colors[SchemeNorm], 3);
-       scheme[SchemeSel] = drw_scm_create(drw, colors[SchemeSel], 3);
+       scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
+       for (i = 0; i < LENGTH(colors); i++)
+               scheme[i] = drw_scm_create(drw, colors[i], 3);
+       /* init system tray */
+       updatesystray();
        /* init bars */
        updatebars();
        updatestatus();
+       /* supporting window for NetWMCheck */
+       wmcheckwin = XCreateSimpleWindow(dpy, root, 0, 0, 1, 1, 0, 0, 0);
+       XChangeProperty(dpy, wmcheckwin, netatom[NetWMCheck], XA_WINDOW, 32,
+               PropModeReplace, (unsigned char *) &wmcheckwin, 1);
+       XChangeProperty(dpy, wmcheckwin, netatom[NetWMName], utf8string, 8,
+               PropModeReplace, (unsigned char *) "dwm", 3);
+       XChangeProperty(dpy, root, netatom[NetWMCheck], XA_WINDOW, 32,
+               PropModeReplace, (unsigned char *) &wmcheckwin, 1);
        /* EWMH support per view */
        XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
-                       PropModeReplace, (unsigned char *) netatom, NetLast);
+               PropModeReplace, (unsigned char *) netatom, NetLast);
        XDeleteProperty(dpy, root, netatom[NetClientList]);
-       /* select for events */
+       /* select events */
        wa.cursor = cursor[CurNormal]->cursor;
-       wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask|ButtonPressMask|PointerMotionMask
-                       |EnterWindowMask|LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
+       wa.event_mask = SubstructureRedirectMask|SubstructureNotifyMask
+               |ButtonPressMask|PointerMotionMask|EnterWindowMask
+               |LeaveWindowMask|StructureNotifyMask|PropertyChangeMask;
        XChangeWindowAttributes(dpy, root, CWEventMask|CWCursor, &wa);
        XSelectInput(dpy, root, wa.event_mask);
        grabkeys();
        focus(NULL);
 }
 
+
+void
+seturgent(Client *c, int urg)
+{
+       XWMHints *wmh;
+
+       c->isurgent = urg;
+       if (!(wmh = XGetWMHints(dpy, c->win)))
+               return;
+       wmh->flags = urg ? (wmh->flags | XUrgencyHint) : (wmh->flags & ~XUrgencyHint);
+       XSetWMHints(dpy, c->win, wmh);
+       XFree(wmh);
+}
+
 void
 showhide(Client *c)
 {
@@ -1693,7 +1889,18 @@ togglebar(const Arg *arg)
 {
        selmon->showbar = !selmon->showbar;
        updatebarpos(selmon);
-       XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+       resizebarwin(selmon);
+       if (showsystray) {
+               XWindowChanges wc;
+               if (!selmon->showbar)
+                       wc.y = -bh;
+               else if (selmon->showbar) {
+                       wc.y = 0;
+                       if (!selmon->topbar)
+                               wc.y = selmon->mh - bh;
+               }
+               XConfigureWindow(dpy, systray->win, CWY, &wc);
+       }
        arrange(selmon);
 }
 
@@ -1706,8 +1913,16 @@ togglefloating(const Arg *arg)
                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, 0);
+               /* restore last known float dimensions */
+               resize(selmon->sel, selmon->sel->sfx, selmon->sel->sfy,
+                      selmon->sel->sfw, selmon->sel->sfh, False);
+       else {
+               /* save last known float dimensions */
+               selmon->sel->sfx = selmon->sel->x;
+               selmon->sel->sfy = selmon->sel->y;
+               selmon->sel->sfw = selmon->sel->w;
+               selmon->sel->sfh = selmon->sel->h;
+       }
        arrange(selmon);
 }
 
@@ -1757,12 +1972,11 @@ unmanage(Client *c, int 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);
+               XGrabServer(dpy); /* avoid race conditions */
                XSetErrorHandler(xerrordummy);
                XConfigureWindow(dpy, c->win, CWBorderWidth, &wc); /* restore border */
                XUngrabButton(dpy, AnyButton, AnyModifier, c->win);
@@ -1789,25 +2003,39 @@ unmapnotify(XEvent *e)
                else
                        unmanage(c, 0);
        }
+       else if ((c = wintosystrayicon(ev->window))) {
+               /* KLUDGE! sometimes icons occasionally unmap their windows, but do
+                * _not_ destroy them. We map those windows back */
+               XMapRaised(dpy, c->win);
+               updatesystray();
+       }
 }
 
 void
 updatebars(void)
 {
+       unsigned int w;
        Monitor *m;
        XSetWindowAttributes wa = {
                .override_redirect = True,
                .background_pixmap = ParentRelative,
                .event_mask = ButtonPressMask|ExposureMask
        };
+       XClassHint ch = {"dwm", "dwm"};
        for (m = mons; m; m = m->next) {
                if (m->barwin)
                        continue;
-               m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
-                                         CopyFromParent, DefaultVisual(dpy, screen),
-                                         CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+               w = m->ww;
+               if (showsystray && m == systraytomon(m))
+                       w -= getsystraywidth();
+               m->barwin = XCreateWindow(dpy, root, m->wx, m->by, w, bh, 0, DefaultDepth(dpy, screen),
+                               CopyFromParent, DefaultVisual(dpy, screen),
+                               CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
                XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+               if (showsystray && m == systraytomon(m))
+                       XMapRaised(dpy, systray->win);
                XMapRaised(dpy, m->barwin);
+               XSetClassHint(dpy, m->barwin, &ch);
        }
 }
 
@@ -1834,8 +2062,8 @@ updateclientlist()
        for (m = mons; m; m = m->next)
                for (c = m->clients; c; c = c->next)
                        XChangeProperty(dpy, root, netatom[NetClientList],
-                                       XA_WINDOW, 32, PropModeAppend,
-                                       (unsigned char *) &(c->win), 1);
+                               XA_WINDOW, 32, PropModeAppend,
+                               (unsigned char *) &(c->win), 1);
 }
 
 int
@@ -1859,8 +2087,8 @@ updategeom(void)
                                memcpy(&unique[j++], &info[i], sizeof(XineramaScreenInfo));
                XFree(info);
                nn = j;
-               if (n <= nn) {
-                       for (i = 0; i < (nn - n); i++) { /* new monitors available */
+               if (n <= nn) { /* new monitors available */
+                       for (i = 0; i < (nn - n); i++) {
                                for (m = mons; m && m->next; m = m->next);
                                if (m)
                                        m->next = createmon();
@@ -1869,8 +2097,8 @@ updategeom(void)
                        }
                        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))
+                               || unique[i].x_org != m->mx || unique[i].y_org != m->my
+                               || unique[i].width != m->mw || unique[i].height != m->mh)
                                {
                                        dirty = 1;
                                        m->num = i;
@@ -1880,13 +2108,11 @@ updategeom(void)
                                        m->mh = m->wh = unique[i].height;
                                        updatebarpos(m);
                                }
-               } else {
-                       /* less monitors available nn < n */
+               } else { /* less monitors available nn < n */
                        for (i = nn; i < n; i++) {
                                for (m = mons; m && m->next; m = m->next);
-                               while (m->clients) {
+                               while ((c = m->clients)) {
                                        dirty = 1;
-                                       c = m->clients;
                                        m->clients = c->next;
                                        detachstack(c);
                                        c->mon = mons;
@@ -1901,8 +2127,7 @@ updategeom(void)
                free(unique);
        } else
 #endif /* XINERAMA */
-       /* default monitor setup */
-       {
+       { /* default monitor setup */
                if (!mons)
                        mons = createmon();
                if (mons->mw != sw || mons->mh != sh) {
@@ -1930,7 +2155,7 @@ updatenumlockmask(void)
        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))
+                               == XKeysymToKeycode(dpy, XK_Num_Lock))
                                numlockmask = (1 << i);
        XFreeModifiermap(modmap);
 }
@@ -1975,17 +2200,7 @@ updatesizehints(Client *c)
                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);
+       c->isfixed = (c->maxw && c->maxh && c->maxw == c->minw && c->maxh == c->minh);
 }
 
 void
@@ -1998,6 +2213,129 @@ updatestatus(void)
                drawbar(m);
 }
 
+void
+updatesystrayicongeom(Client *i, int w, int h)
+{
+       if (i) {
+               i->h = bh;
+               if (w == h)
+                       i->w = bh;
+               else if (h == bh)
+                       i->w = w;
+               else
+                       i->w = (int) ((float)bh * ((float)w / (float)h));
+               applysizehints(i, &(i->x), &(i->y), &(i->w), &(i->h), False);
+               /* force icons into the systray dimenons if they don't want to */
+               if (i->h > bh) {
+                       if (i->w == i->h)
+                               i->w = bh;
+                       else
+                               i->w = (int) ((float)bh * ((float)i->w / (float)i->h));
+                       i->h = bh;
+               }
+       }
+}
+
+void
+updatesystrayiconstate(Client *i, XPropertyEvent *ev)
+{
+       long flags;
+       int code = 0;
+
+       if (!showsystray || !i || ev->atom != xatom[XembedInfo] ||
+                       !(flags = getatomprop(i, xatom[XembedInfo])))
+               return;
+
+       if (flags & XEMBED_MAPPED && !i->tags) {
+               i->tags = 1;
+               code = XEMBED_WINDOW_ACTIVATE;
+               XMapRaised(dpy, i->win);
+               setclientstate(i, NormalState);
+       }
+       else if (!(flags & XEMBED_MAPPED) && i->tags) {
+               i->tags = 0;
+               code = XEMBED_WINDOW_DEACTIVATE;
+               XUnmapWindow(dpy, i->win);
+               setclientstate(i, WithdrawnState);
+       }
+       else
+               return;
+       sendevent(i->win, xatom[Xembed], StructureNotifyMask, CurrentTime, code, 0,
+                       systray->win, XEMBED_EMBEDDED_VERSION);
+}
+
+void
+updatesystray(void)
+{
+       XSetWindowAttributes wa;
+       XWindowChanges wc;
+       Client *i;
+       Monitor *m = systraytomon(NULL);
+       unsigned int x = m->mx + m->mw;
+       unsigned int w = 1;
+
+       if (!showsystray)
+               return;
+       if (!systray) {
+               /* init systray */
+               if (!(systray = (Systray *)calloc(1, sizeof(Systray))))
+                       die("fatal: could not malloc() %u bytes\n", sizeof(Systray));
+               systray->win = XCreateSimpleWindow(dpy, root, x, m->by, w, bh, 0, 0, scheme[SchemeSel][ColBg].pixel);
+               wa.event_mask        = ButtonPressMask | ExposureMask;
+               wa.override_redirect = True;
+               wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+               XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+               XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+                               PropModeReplace, (unsigned char *)&netatom[NetSystemTrayOrientationHorz], 1);
+               XChangeWindowAttributes(dpy, systray->win, CWEventMask|CWOverrideRedirect|CWBackPixel, &wa);
+               XMapRaised(dpy, systray->win);
+               XSetSelectionOwner(dpy, netatom[NetSystemTray], systray->win, CurrentTime);
+               if (XGetSelectionOwner(dpy, netatom[NetSystemTray]) == systray->win) {
+                       sendevent(root, xatom[Manager], StructureNotifyMask, CurrentTime, netatom[NetSystemTray], systray->win, 0, 0);
+                       XSync(dpy, False);
+               }
+               else {
+                       fprintf(stderr, "dwm: unable to obtain system tray.\n");
+                       free(systray);
+                       systray = NULL;
+                       return;
+               }
+       }
+       for (w = 0, i = systray->icons; i; i = i->next) {
+               /* make sure the background color stays the same */
+               wa.background_pixel  = scheme[SchemeNorm][ColBg].pixel;
+               XChangeWindowAttributes(dpy, i->win, CWBackPixel, &wa);
+               XMapRaised(dpy, i->win);
+               w += systrayspacing;
+               i->x = w;
+               XMoveResizeWindow(dpy, i->win, i->x, 0, i->w, i->h);
+               w += i->w;
+               if (i->mon != m)
+                       i->mon = m;
+       }
+       w = w ? w + systrayspacing : 1;
+       x -= w;
+       XMoveResizeWindow(dpy, systray->win, x, m->by, w, bh);
+       wc.x = x; wc.y = m->by; wc.width = w; wc.height = bh;
+       wc.stack_mode = Above; wc.sibling = m->barwin;
+       XConfigureWindow(dpy, systray->win, CWX|CWY|CWWidth|CWHeight|CWSibling|CWStackMode, &wc);
+       XMapWindow(dpy, systray->win);
+       XMapSubwindows(dpy, systray->win);
+       /* redraw background */
+       XSetForeground(dpy, drw->gc, scheme[SchemeNorm][ColBg].pixel);
+       XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
+       XSync(dpy, False);
+}
+
+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
 updatewindowtype(Client *c)
 {
@@ -2054,6 +2392,16 @@ wintoclient(Window w)
        return NULL;
 }
 
+Client *
+wintosystrayicon(Window w) {
+       Client *i = NULL;
+
+       if (!showsystray || !w)
+               return i;
+       for (i = systray->icons; i && i->win != w; i = i->next) ;
+       return i;
+}
+
 Monitor *
 wintomon(Window w)
 {
@@ -2072,8 +2420,8 @@ wintomon(Window w)
 }
 
 /* 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.  */
+ * ignored (especially on UnmapNotify's). Other types of errors call Xlibs
+ * default error handler, which may call exit. */
 int
 xerror(Display *dpy, XErrorEvent *ee)
 {
@@ -2088,7 +2436,7 @@ xerror(Display *dpy, XErrorEvent *ee)
        || (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);
+               ee->request_code, ee->error_code);
        return xerrorxlib(dpy, ee); /* may call exit */
 }
 
@@ -2103,10 +2451,26 @@ xerrordummy(Display *dpy, XErrorEvent *ee)
 int
 xerrorstart(Display *dpy, XErrorEvent *ee)
 {
-       die("dwm: another window manager is already running\n");
+       die("dwm: another window manager is already running");
        return -1;
 }
 
+Monitor *
+systraytomon(Monitor *m) {
+       Monitor *t;
+       int i, n;
+       if(!systraypinning) {
+               if(!m)
+                       return selmon;
+               return m == selmon ? m : NULL;
+       }
+       for(n = 1, t = mons; t && t->next; n++, t = t->next) ;
+       for(i = 1, t = mons; t && t->next && i < systraypinning; i++, t = t->next) ;
+       if(systraypinningfailfirst && n < systraypinning)
+               return mons;
+       return t;
+}
+
 void
 zoom(const Arg *arg)
 {
@@ -2125,15 +2489,19 @@ int
 main(int argc, char *argv[])
 {
        if (argc == 2 && !strcmp("-v", argv[1]))
-               die("dwm-"VERSION "\n");
+               die("dwm-"VERSION);
        else if (argc != 1)
-               die("usage: dwm [-v]\n");
+               die("usage: dwm [-v]");
        if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
                fputs("warning: no locale support\n", stderr);
        if (!(dpy = XOpenDisplay(NULL)))
-               die("dwm: cannot open display\n");
+               die("dwm: cannot open display");
        checkotherwm();
        setup();
+#ifdef __OpenBSD__
+       if (pledge("stdio rpath proc exec", NULL) == -1)
+               die("pledge");
+#endif /* __OpenBSD__ */
        scan();
        run();
        cleanup();
diff --git a/util.c b/util.c
index 6b703e9..fe044fc 100644 (file)
--- a/util.c
+++ b/util.c
@@ -12,7 +12,7 @@ ecalloc(size_t nmemb, size_t size)
        void *p;
 
        if (!(p = calloc(nmemb, size)))
-               perror(NULL);
+               die("calloc:");
        return p;
 }
 
@@ -27,6 +27,8 @@ die(const char *fmt, ...) {
        if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
                fputc(' ', stderr);
                perror(NULL);
+       } else {
+               fputc('\n', stderr);
        }
 
        exit(1);