summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArtur Artamonov <freeartman@wechall.net>2014-06-29 19:14:44 +0300
committerArtur Artamonov <freeartman@wechall.net>2014-06-29 19:14:44 +0300
commit8db5030a687b9a91ca39296edb6cd4728e5d71bf (patch)
tree15af5652df82d83f0513817a1702c4f95414874e
downloaddwm-fancy-8db5030a687b9a91ca39296edb6cd4728e5d71bf.tar.gz
dwm-fancy-8db5030a687b9a91ca39296edb6cd4728e5d71bf.zip
Initial commit
-rw-r--r--.gitignore0
-rw-r--r--Kconfig18
-rw-r--r--LICENSE32
-rw-r--r--Makefile44
-rw-r--r--README.md9
-rw-r--r--config.def.h110
-rw-r--r--config.h132
-rw-r--r--debug/Kconfig24
-rw-r--r--debug/debug.h66
-rw-r--r--drw.c313
-rw-r--r--drw.h94
-rw-r--r--dwm.c2691
-rw-r--r--kconf2h/kconf2h.c50
-rw-r--r--kconf2h/kconf2h.h10
-rw-r--r--kconf2h/kconf2h_parser.c327
-rw-r--r--kconfig.h3
-rw-r--r--transient.c42
-rw-r--r--util.c17
-rw-r--r--util.h11
19 files changed, 3993 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitignore
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..4f71c2d
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,18 @@
+
+source "debug/Kconfig"
+
+config DWM_PERTAG
+ bool "One layout pertag"
+ default n
+
+config DWM_OPACITY
+ bool "Default opacity level"
+ default n
+
+config DWM_SYSTEMTRAY
+ bool "Add systemtray"
+ default n
+
+config DWM_PANGO
+ bool "Add pango support. Fonts, UTF-8, extraca icons"
+ default n
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e8e793a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+MIT/X Consortium License
+
+© 2006-2011 Anselm R Garbe <anselm@garbe.us>
+© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
+© 2010-2011 Connor Lane Smith <cls@lubutu.com>
+© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
+© 2007-2009 Premysl Hruby <dfenze at gmail 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-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>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..9f68e18
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,44 @@
+CC=cc
+CFLAGS=
+LDFLAGS=
+
+X11LIB = /usr/X11R6/lib
+
+XINERAMALIBS = -lXinerama
+XINERAMAFLAGS = -DXINERAMA
+
+
+CFLAGS += -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\"
+LDFLAGS += -L${X11LIB} -lX11 ${XINERAMALIBS}
+
+CFLAGS += `pkg-config --cflags xft pango pangoxft`
+LDFLAGS += `pkg-config --libs xft pango pangoxft`
+
+VERSION = 6.1
+
+SRC = dwm.c drw.c util.c
+OBJ = ${SRC:.c=.o}
+
+.c.o:
+ @echo CC $<
+ echo $(CFLAGS)
+ echo $(LDFLAGS)
+ ${CC} ${CFLAGS} -c $<
+
+dwm: ${OBJ}
+ @echo CC -o $@
+ echo $(CFLAGS)
+ ${CC} -o $@ ${OBJ} ${LDFLAGS}
+
+kconfig2h:
+ $(CC) -c kconf2h/kconf2h_parser.c
+ $(CC) kconf2h/kconf2h.c kconf2h_parser.o -o kconf2h/kconf2h
+
+menuconfig: kconfig2h
+ ./mconf Kconfig
+ kconf2h/kconf2h .config kconfig.h
+
+clean:
+ rm -rf dwm
+ rm -rf *.o
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c035e9a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,9 @@
+Here is dwm 6.1 for with applied patches:
+pertag
+?opacity
+?pango
+systemtray
+
+All patches can be turned off/on with menuconfig. Configuration
+utility mconf can be taken from linux kernel. For succesfully
+compile all sources mconf isnt needed.
diff --git a/config.def.h b/config.def.h
new file mode 100644
index 0000000..875885b
--- /dev/null
+++ b/config.def.h
@@ -0,0 +1,110 @@
+/* See LICENSE file for copyright and license details. */
+
+/* appearance */
+static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
+static const char normbordercolor[] = "#444444";
+static const char normbgcolor[] = "#222222";
+static const char normfgcolor[] = "#bbbbbb";
+static const char selbordercolor[] = "#005577";
+static const char selbgcolor[] = "#005577";
+static const char selfgcolor[] = "#eeeeee";
+static const unsigned int borderpx = 1; /* border pixel of windows */
+static const unsigned int snap = 32; /* snap pixel */
+static const Bool showbar = True; /* False means no bar */
+static const Bool topbar = True; /* False means bottom bar */
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+static const Rule rules[] = {
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+ /* class instance title tags mask isfloating monitor */
+ { "Gimp", NULL, NULL, 0, True, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, False, -1 },
+};
+
+/* layout(s) */
+static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster = 1; /* number of clients in master area */
+static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
+
+static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile }, /* first entry is default */
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
+static const char *termcmd[] = { "st", NULL };
+
+static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+ { MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+ TAGKEYS( XK_4, 3)
+ TAGKEYS( XK_5, 4)
+ TAGKEYS( XK_6, 5)
+ TAGKEYS( XK_7, 6)
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
+};
+
+/* button definitions */
+/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static Button buttons[] = {
+ /* click event mask button function argument */
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+};
+
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..e20678f
--- /dev/null
+++ b/config.h
@@ -0,0 +1,132 @@
+/* See LICENSE file for copyright and license details. */
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include "kconfig.h"
+
+/* appearance */
+#ifdef CONFIG_DWM_PANGO
+static const char font[] = "Sans 8";
+#else
+static const char font[] = "-*-terminus-medium-r-*-*-16-*-*-*-*-*-*-*";
+#endif
+static const char normbordercolor[] = "#444444";
+static const char normbgcolor[] = "#222222";
+static const char normfgcolor[] = "#bbbbbb";
+static const char selbordercolor[] = "#005577";
+static const char selbgcolor[] = "#005577";
+static const char selfgcolor[] = "#eeeeee";
+static const unsigned int borderpx = 1; /* border pixel of windows */
+static const unsigned int snap = 32; /* snap pixel */
+static const Bool showbar = True; /* False means no bar */
+static const Bool topbar = True; /* False means bottom bar */
+#ifdef CONFIG_DWM_OPACITY
+static const double defaultopacity = 0.75;
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+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 Bool systraypinningfailfirst = True; /* True: if pinning fails, display systray on the first monitor, False: display systray on the last monitor*/
+static const Bool showsystray = True; /* False means no systray */
+#endif
+#ifdef CONFIG_DWM_PANGO
+static const Bool statusmarkup = True; /* True means use pango markup in status message */
+#endif
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+static const Rule rules[] = {
+ /* class instance title tags mask isfloating monitor */
+ { "Gimp", NULL, NULL, 0, True, -1 },
+ { "Firefox", NULL, NULL, 1 << 8, False, -1 },
+};
+
+/* layout(s) */
+static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster = 1; /* number of clients in master area */
+static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
+
+static const Layout layouts[] = {
+ /* symbol arrange function */
+ { "[]=", tile }, /* first entry is default */
+ { "><>", NULL }, /* no layout function means floating behavior */
+ { "[M]", monocle },
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+ { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
+ { MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
+ { MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-fn", font, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbgcolor, "-sf", selfgcolor, NULL };
+static const char *termcmd[] = { "uxterm", NULL };
+
+static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+ { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
+#ifdef CONFIG_DWM_OPACITY
+ { MODKEY|ShiftMask, XK_s, spawn, SHCMD("transset-df -a --dec .1") },
+ { MODKEY|ShiftMask, XK_d, spawn, SHCMD("transset-df -a --inc .1") },
+ { MODKEY|ShiftMask, XK_f, spawn, SHCMD("transset-df -a .75") },
+#endif
+ { MODKEY, XK_b, togglebar, {0} },
+ { MODKEY, XK_j, focusstack, {.i = +1 } },
+ { MODKEY, XK_k, focusstack, {.i = -1 } },
+ { MODKEY, XK_i, incnmaster, {.i = +1 } },
+ { MODKEY, XK_d, incnmaster, {.i = -1 } },
+ { MODKEY, XK_h, setmfact, {.f = -0.05} },
+ { MODKEY, XK_l, setmfact, {.f = +0.05} },
+ { MODKEY, XK_Return, zoom, {0} },
+ { MODKEY, XK_Tab, view, {0} },
+ { MODKEY|ShiftMask, XK_c, killclient, {0} },
+ { MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
+ { MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
+ { MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
+ { MODKEY, XK_space, setlayout, {0} },
+ { MODKEY|ShiftMask, XK_space, togglefloating, {0} },
+ { MODKEY, XK_0, view, {.ui = ~0 } },
+ { MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
+ { MODKEY, XK_comma, focusmon, {.i = -1 } },
+ { MODKEY, XK_period, focusmon, {.i = +1 } },
+ { MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
+ { MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
+ TAGKEYS( XK_1, 0)
+ TAGKEYS( XK_2, 1)
+ TAGKEYS( XK_3, 2)
+ TAGKEYS( XK_4, 3)
+ TAGKEYS( XK_5, 4)
+ TAGKEYS( XK_6, 5)
+ TAGKEYS( XK_7, 6)
+ TAGKEYS( XK_8, 7)
+ TAGKEYS( XK_9, 8)
+ { MODKEY|ShiftMask, XK_q, quit, {0} },
+};
+
+/* button definitions */
+/* click can be ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static Button buttons[] = {
+ /* click event mask button function argument */
+ { ClkLtSymbol, 0, Button1, setlayout, {0} },
+ { ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
+ { ClkWinTitle, 0, Button2, zoom, {0} },
+ { ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
+ { ClkClientWin, MODKEY, Button1, movemouse, {0} },
+ { ClkClientWin, MODKEY, Button2, togglefloating, {0} },
+ { ClkClientWin, MODKEY, Button3, resizemouse, {0} },
+ { ClkTagBar, 0, Button1, view, {0} },
+ { ClkTagBar, 0, Button3, toggleview, {0} },
+ { ClkTagBar, MODKEY, Button1, tag, {0} },
+ { ClkTagBar, MODKEY, Button3, toggletag, {0} },
+};
+
+#endif
diff --git a/debug/Kconfig b/debug/Kconfig
new file mode 100644
index 0000000..21dae6d
--- /dev/null
+++ b/debug/Kconfig
@@ -0,0 +1,24 @@
+menuconfig DEBUG
+ bool "Enable debug output"
+ option debug
+
+if DEBUG
+config DEBUG_PRINT_DEBUG
+ bool "Print debug"
+ default y
+
+config DEBUG_COLORIZE
+ bool "Colorize output"
+ default n
+ depends on DEBUG_PRINT_DEBUG
+
+config DEBUG_PRINT_LINENUM
+ bool "Print line number in debug"
+ default n
+ depends on DEBUG_PRINT_DEBUG
+
+config DEBUG_PRINT_FILENAME
+ bool "Print file name in debug"
+ default n
+ depends on DEBUG_PRINT_DEBUG
+endif
diff --git a/debug/debug.h b/debug/debug.h
new file mode 100644
index 0000000..b030fbe
--- /dev/null
+++ b/debug/debug.h
@@ -0,0 +1,66 @@
+#ifndef __RB_DEBUG_UTILS_H
+#define __RB_DEBUG_UTILS_H
+
+
+//what about kprintf?
+
+//config options
+#define PRINTF printf
+//#define COLORIZE
+//#define PRINT_LINENUM
+//#define PRINT_FILENAME
+//#define PRINT_DEBUG
+
+
+//use color
+#ifdef CONFIG_DEBUG_COLORIZE
+ #define D_COLOR "1;32m"
+ #define D_COLOR_S "\033[" D_COLOR
+ #define D_COLOR_E "\033[0m"
+ #define E_COLOR "1;31m"
+ #define E_COLOR_S "\033[" E_COLOR
+ #define E_COLOR_E "\033[0m"
+#else
+ #define D_COLOR
+ #define D_COLOR_S
+ #define D_COLOR_E
+ #define E_COLOR
+ #define E_COLOR_S
+ #define E_COLOR_E
+#endif
+
+//print debug line
+#ifdef CONFIG_DEBUG_PRINT_LINENUM
+ #define PRINT_LINE_F "LINE:%d "
+ #define PRINT_LINE_D __LINE__
+#else
+ #define PRINT_LINE_F ""
+ #define PRINT_LINE_D ""
+#endif
+
+//print
+#ifdef CONFIG_DEBUG_PRINT_FILENAME
+ #define PRINT_FILE_F "FILE:%s "
+ #define PRINT_FILE_D __FILE__
+#else
+ #define PRINT_FILE_F ""
+ #define PRINT_FILE_D ""
+#endif
+
+//print debug string
+#ifdef CONFIG_DEBUG_PRINT_DEBUG
+ #define PRINT_DEBUG_F "Debug: "
+#else
+ #define PRINT_DEBUG_F ""
+#endif
+
+#define PRINT( format, args ... ) PRINTF( D_COLOR_S PRINT_DEBUG_F \
+ PRINT_FILE_F PRINT_LINE_F format D_COLOR_E, PRINT_FILE_D, \
+ PRINT_LINE_D, ##args);
+
+#define ERROR( format, args ... ) PRINTF( E_COLOR_S PRINT_DEBUG_F \
+ PRINT_FILE_F PRINT_LINE_F format E_COLOR_E, PRINT_FILE_D, \
+ PRINT_LINE_D, ##args);
+
+
+#endif
diff --git a/drw.c b/drw.c
new file mode 100644
index 0000000..f02d26c
--- /dev/null
+++ b/drw.c
@@ -0,0 +1,313 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+
+#include "drw.h"
+#include "util.h"
+
+#ifdef CONFIG_DWM_PANGO
+//char stext[512];
+//extern Bool statusmarkup;
+#endif
+
+Drw *
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) {
+ Drw *drw = (Drw *)calloc(1, sizeof(Drw));
+ if(!drw)
+ return NULL;
+ drw->dpy = dpy;
+ drw->screen = screen;
+ drw->root = root;
+ drw->w = w;
+ drw->h = h;
+ drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
+ drw->gc = XCreateGC(dpy, root, 0, NULL);
+ XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
+ return drw;
+}
+
+void
+drw_resize(Drw *drw, unsigned int w, unsigned int h) {
+ if(!drw)
+ return;
+ drw->w = w;
+ drw->h = h;
+ if(drw->drawable != 0)
+ XFreePixmap(drw->dpy, drw->drawable);
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
+}
+
+void
+drw_free(Drw *drw) {
+ XFreePixmap(drw->dpy, drw->drawable);
+ XFreeGC(drw->dpy, drw->gc);
+ free(drw);
+}
+
+Fnt *
+drw_font_create(Display *dpy, const char *fontname) {
+ Fnt *font;
+ char *def, **missing;
+ int n;
+
+ font = (Fnt *)calloc(1, sizeof(Fnt));
+ if(!font)
+ return NULL;
+
+#ifdef CONFIG_DWM_PANGO
+ PangoFontMap *fontmap;
+ PangoContext *context;
+ PangoFontDescription *desc;
+ PangoFontMetrics *metrics;
+
+ int screen = DefaultScreen(dpy);
+ fontmap = pango_xft_get_font_map(dpy, screen);
+ context = pango_font_map_create_context(fontmap);
+ desc = pango_font_description_from_string(fontname);
+ font->layout = pango_layout_new(context);
+ pango_layout_set_font_description(font->layout, desc);
+
+ metrics = pango_context_get_metrics(context, desc, NULL);
+ font->ascent = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE;
+ font->descent = pango_font_metrics_get_descent(metrics) / PANGO_SCALE;
+ font->h = font->ascent + font->descent;
+
+ pango_font_metrics_unref(metrics);
+ g_object_unref(context);
+#else
+ font->set = XCreateFontSet(dpy, fontname, &missing, &n, &def);
+ if(missing) {
+ while(n--)
+ fprintf(stderr, "drw: missing fontset: %s\n", missing[n]);
+ XFreeStringList(missing);
+ }
+ if(font->set) {
+ XFontStruct **xfonts;
+ char **font_names;
+ XExtentsOfFontSet(font->set);
+ n = XFontsOfFontSet(font->set, &xfonts, &font_names);
+ while(n--) {
+ font->ascent = MAX(font->ascent, (*xfonts)->ascent);
+ font->descent = MAX(font->descent,(*xfonts)->descent);
+ xfonts++;
+ }
+ }
+ else {
+ if(!(font->xfont = XLoadQueryFont(dpy, fontname))
+ && !(font->xfont = XLoadQueryFont(dpy, "fixed")))
+ die("error, cannot load font: '%s'\n", fontname);
+ font->ascent = font->xfont->ascent;
+ font->descent = font->xfont->descent;
+ }
+ font->h = font->ascent + font->descent;
+#endif
+ return font;
+}
+
+void
+drw_font_free(Display *dpy, Fnt *font) {
+ if(!font)
+ return;
+#ifdef CONFIG_DWM_PANGO
+ g_object_unref(font->layout);
+#else
+ if(font->set)
+ XFreeFontSet(dpy, font->set);
+ else
+ XFreeFont(dpy, font->xfont);
+#endif
+ free(font);
+}
+
+Clr *
+#ifdef CONFIG_DWM_PANGO
+drw_clr_create(Drw *drw, const char *clrname, XftColor *color) {
+#else
+drw_clr_create(Drw *drw, const char *clrname) {
+#endif
+ Clr *clr;
+ Colormap cmap;
+#ifdef CONFIG_DWM_PANGO
+ Visual *vis = DefaultVisual(drw->dpy, drw->screen);
+#else
+ XColor color;
+#endif
+
+ if(!drw)
+ return NULL;
+ clr = (Clr *)calloc(1, sizeof(Clr));
+ if(!clr)
+ return NULL;
+ cmap = DefaultColormap(drw->dpy, drw->screen);
+
+#ifdef CONFIG_DWM_PANGO
+ if(!XftColorAllocName(drw->dpy, vis, cmap, clrname, color))
+#else
+ if(!XAllocNamedColor(drw->dpy, cmap, clrname, &color, &color))
+#endif
+
+ die("error, cannot allocate color '%s'\n", clrname);
+
+#ifdef CONFIG_DWM_PANGO
+ clr->rgb = color->pixel;
+#else
+ clr->rgb = color.pixel;
+#endif
+
+ return clr;
+}
+
+void
+drw_clr_free(Clr *clr) {
+ if(clr)
+ free(clr);
+}
+
+void
+drw_setfont(Drw *drw, Fnt *font) {
+ if(drw)
+ drw->font = font;
+}
+
+void
+drw_setscheme(Drw *drw, ClrScheme *scheme) {
+ if(drw && scheme)
+ drw->scheme = scheme;
+}
+
+void
+drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert) {
+ int dx;
+
+ if(!drw || !drw->font || !drw->scheme)
+ return;
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw->scheme->fg->rgb);
+ dx = (drw->font->ascent + drw->font->descent + 2) / 4;
+ if(filled)
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx+1, dx+1);
+ else if(empty)
+ XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x+1, y+1, dx, dx);
+}
+
+void
+drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert) {
+#ifdef CONFIG_DWM_PANGO
+ char buf[512];
+#else
+ char buf[256];
+#endif
+ int i, tx, ty, th, len, olen;
+ Extnts tex;
+
+ if(!drw || !drw->scheme)
+ return;
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->fg->rgb : drw->scheme->bg->rgb);
+ XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
+ if(!text || !drw->font)
+ return;
+ olen = strlen(text);
+ drw_font_getexts(drw->font, text, olen, &tex);
+ th = drw->font->ascent + drw->font->descent;
+#ifdef CONFIG_DWM_PANGO
+ ty = y + (h / 2) - (th / 2);
+#else
+ ty = y + (h / 2) - (th / 2) + drw->font->ascent;
+#endif
+ tx = x + (h / 2);
+ /* shorten text if necessary */
+ /* shorten text if necessary (this could wreak havoc with pango markup but fortunately
+ dc.w is adjusted to the width of the status text and not the other way around) */
+ for(len = MIN(olen, sizeof buf); len && (tex.w > w - tex.h || w < tex.h); len--)
+ drw_font_getexts(drw->font, text, len, &tex);
+ if(!len)
+ return;
+ memcpy(buf, text, len);
+ if(len < olen)
+ for(i = len; i && i > len - 3; buf[--i] = '.');
+#ifdef CONFIG_DWM_PANGO
+ //if(text == stext && statusmarkup)
+ // pango_layout_set_markup(drw->font->layout, buf, len);
+ //else
+ pango_layout_set_text(drw->font->layout, buf, len);
+ //pango_xft_render_layout(drw->xft.drawable,
+ // (struct XftColor*)(invert ? drw->scheme->bg->rgb : drw->scheme->fg->rgb),
+ // drw->font->layout, x * PANGO_SCALE, y * PANGO_SCALE);
+ //if(text == stext && statusmarkup) /* clear markup attributes */
+ // pango_layout_set_attributes(drw->font->layout, NULL);
+#else
+ XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->rgb : drw->scheme->fg->rgb);
+ if(drw->font->set)
+ XmbDrawString(drw->dpy, drw->drawable, drw->font->set, drw->gc, tx, ty, buf, len);
+ else
+ XDrawString(drw->dpy, drw->drawable, drw->gc, tx, ty, buf, len);
+#endif
+}
+
+void
+drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h) {
+ if(!drw)
+ return;
+ XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
+ XSync(drw->dpy, False);
+}
+
+
+void
+drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex) {
+ if(!font || !text)
+ return;
+
+#ifdef CONFIG_DWM_PANGO
+ PangoRectangle r;
+ //if(text == stext && statusmarkup)
+ // pango_layout_set_markup(font->layout, text, len);
+ //else
+ pango_layout_set_text(font->layout, text, len);
+ pango_layout_get_extents(font->layout, 0, &r);
+ //if(text == stext && statusmarkup) /* clear markup attributes */
+ // pango_layout_set_attributes(font->layout, NULL);
+ tex->h = r.height;
+ tex->w = r.width / PANGO_SCALE;
+#else
+ XRectangle r;
+ if(font->set) {
+ XmbTextExtents(font->set, text, len, NULL, &r);
+ tex->w = r.width;
+ tex->h = r.height;
+ }
+ else {
+ tex->h = font->ascent + font->descent;
+ tex->w = XTextWidth(font->xfont, text, len);
+ }
+#endif
+}
+
+unsigned int
+drw_font_getexts_width(Fnt *font, const char *text, unsigned int len) {
+ Extnts tex;
+
+ if(!font)
+ return -1;
+ drw_font_getexts(font, text, len, &tex);
+ return tex.w;
+}
+
+Cur *
+drw_cur_create(Drw *drw, int shape) {
+ Cur *cur = (Cur *)calloc(1, sizeof(Cur));
+
+ if(!drw || !cur)
+ return NULL;
+ cur->cursor = XCreateFontCursor(drw->dpy, shape);
+ return cur;
+}
+
+void
+drw_cur_free(Drw *drw, Cur *cursor) {
+ if(!drw || !cursor)
+ return;
+ XFreeCursor(drw->dpy, cursor->cursor);
+ free(cursor);
+}
diff --git a/drw.h b/drw.h
new file mode 100644
index 0000000..f3c3eec
--- /dev/null
+++ b/drw.h
@@ -0,0 +1,94 @@
+/* See LICENSE file for copyright and license details. */
+
+#include "kconfig.h"
+
+#ifdef CONFIG_DWM_PANGO
+#include <X11/Xft/Xft.h>
+#include <pango/pango.h>
+#include <pango/pangoxft.h>
+
+typedef struct {
+ XftColor norm[4];
+ XftColor sel[4];
+ XftDraw *drawable;
+} Xft;
+#endif
+
+typedef struct {
+ unsigned long rgb;
+} Clr;
+
+typedef struct {
+ Cursor cursor;
+} Cur;
+
+typedef struct {
+ int ascent;
+ int descent;
+ unsigned int h;
+#ifdef CONFIG_DWM_PANGO
+ PangoLayout *layout;
+#else
+ XFontSet set;
+ XFontStruct *xfont;
+#endif
+} Fnt;
+
+typedef struct {
+ Clr *fg;
+ Clr *bg;
+ Clr *border;
+} ClrScheme;
+
+typedef struct {
+ unsigned int w, h;
+ Display *dpy;
+ int screen;
+ Window root;
+ Drawable drawable;
+ GC gc;
+ ClrScheme *scheme;
+#ifdef CONFIG_DWM_PANGO
+ Xft xft;
+#endif
+ Fnt *font;
+} Drw;
+
+typedef struct {
+ unsigned int w;
+ unsigned int h;
+} Extnts;
+
+/* Drawable abstraction */
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
+void drw_resize(Drw *drw, unsigned int w, unsigned int h);
+void drw_free(Drw *drw);
+
+/* Fnt abstraction */
+Fnt *drw_font_create(Display *dpy, const char *fontname);
+void drw_font_free(Display *dpy, Fnt *font);
+void drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *extnts);
+unsigned int drw_font_getexts_width(Fnt *font, const char *text, unsigned int len);
+
+/* Colour abstraction */
+#ifdef CONFIG_DWM_PANGO
+Clr *drw_clr_create(Drw *drw, const char *clrname, XftColor *color);
+#else
+Clr *drw_clr_create(Drw *drw, const char *clrname);
+#endif
+void drw_clr_free(Clr *clr);
+
+/* Cursor abstraction */
+Cur *drw_cur_create(Drw *drw, int shape);
+void drw_cur_free(Drw *drw, Cur *cursor);
+
+/* Drawing context manipulation */
+void drw_setfont(Drw *drw, Fnt *font);
+void drw_setscheme(Drw *drw, ClrScheme *scheme);
+
+/* Drawing functions */
+void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert);
+void drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert);
+
+/* Map functions */
+void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
diff --git a/dwm.c b/dwm.c
new file mode 100644
index 0000000..41260dd
--- /dev/null
+++ b/dwm.c
@@ -0,0 +1,2691 @@
+/* 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 */
+
+
+#include "drw.h"
+#include "util.h"
+//#include "config.h"
+
+/* macros */
+#define BUTTONMASK (ButtonPressMask|ButtonReleaseMask)
+#define CLEANMASK(mask) (mask & ~(numlockmask|LockMask) & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+#define INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->wx+(m)->ww) - MAX((x),(m)->wx)) \
+ * MAX(0, MIN((y)+(h),(m)->wy+(m)->wh) - MAX((y),(m)->wy)))
+#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+#define LENGTH(X) (sizeof X / sizeof X[0])
+#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) (drw_font_getexts_width(drw->font, X, strlen(X)) + drw->font->h)
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 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
+#endif
+
+/* enums */
+enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
+enum { SchemeNorm, SchemeSel, SchemeLast }; /* color schemes */
+enum { NetSupported, NetWMName, NetWMState,
+ NetWMFullscreen, NetActiveWindow, NetWMWindowType,
+#ifdef CONFIG_DWM_OPACITY
+ NetWMWindowsOpacity,
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ NetSystemTray, NetSystemTrayOP, NetSystemTrayOrientation,
+#endif
+ NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
+enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
+enum { ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+ ClkClientWin, ClkRootWin, ClkLast }; /* clicks */
+#ifdef CONFIG_DWM_SYSTEMTRAY
+enum { Manager, Xembed, XembedInfo, XLast }; /* Xembed atoms */
+#endif
+
+
+
+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 {
+ unsigned int mod;
+ KeySym keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
+} Key;
+
+typedef struct {
+ const char *symbol;
+ void (*arrange)(Monitor *);
+} Layout;
+
+
+#ifdef CONFIG_DWM_PERTAG
+ typedef struct Pertag Pertag;
+#endif
+struct Monitor {
+ char ltsymbol[16];
+ float mfact;
+ int nmaster;
+ 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];
+
+#ifdef CONFIG_DWM_PERTAG
+ Pertag *pertag;
+#endif
+};
+
+typedef struct {
+ const char *class;
+ const char *instance;
+ const char *title;
+ unsigned int tags;
+ Bool isfloating;
+ int monitor;
+} Rule;
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+typedef struct Systray Systray;
+struct Systray {
+ Window win;
+ Client *icons;
+};
+#endif
+
+/* function declarations */
+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 attachstack(Client *c);
+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 destroynotify(XEvent *e);
+static void detach(Client *c);
+static void detachstack(Client *c);
+static Monitor *dirtomon(int dir);
+static void drawbar(Monitor *m);
+static void drawbars(void);
+static void enternotify(XEvent *e);
+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);
+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 incnmaster(const Arg *arg);
+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 motionnotify(XEvent *e);
+static void movemouse(const Arg *arg);
+static Client *nexttiled(Client *c);
+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 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);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+static Bool sendevent(Window w, Atom proto, int m, long d0, long d1, long d2, long d3, long d4);
+#else
+static Bool sendevent(Client *c, Atom proto);
+#endif
+static void sendmon(Client *c, Monitor *m);
+static void setclientstate(Client *c, long state);
+static void setfocus(Client *c);
+static void setfullscreen(Client *c, Bool fullscreen);
+static void setlayout(const Arg *arg);
+static void setmfact(const Arg *arg);
+static void setup(void);
+static void showhide(Client *c);
+static void sigchld(int unused);
+static void spawn(const Arg *arg);
+static void tag(const Arg *arg);
+static void tagmon(const Arg *arg);
+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 updateclientlist(void);
+static void updatenumlockmask(void);
+static void updatesizehints(Client *c);
+static void updatestatus(void);
+static void updatewindowtype(Client *c);
+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);
+#ifdef CONFIG_DWM_OPACITY
+static void opacity(Client *c, double opacity);
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+static Atom getatomprop(Client *c, Atom prop);
+static unsigned int getsystraywidth();
+static void removesystrayicon(Client *i);
+static void resizebarwin(Monitor *m);
+static void resizerequest(XEvent *e);
+static Monitor *systraytomon(Monitor *m);
+static void updatesystray(void);
+static void updatesystrayicongeom(Client *i, int w, int h);
+static void updatesystrayiconstate(Client *i, XPropertyEvent *ev);
+static Client *wintosystrayicon(Window w);
+#endif
+
+/* variables */
+static const char broken[] = "broken";
+#ifdef CONFIG_DWM_PANGO
+static char stext[512];
+#else
+static char stext[256];
+#endif
+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,
+ [EnterNotify] = enternotify,
+ [Expose] = expose,
+ [FocusIn] = focusin,
+ [KeyPress] = keypress,
+ [MappingNotify] = mappingnotify,
+ [MapRequest] = maprequest,
+ [MotionNotify] = motionnotify,
+ [PropertyNotify] = propertynotify,
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ [ResizeRequest] = resizerequest,
+#endif
+ [UnmapNotify] = unmapnotify
+};
+static Atom wmatom[WMLast], netatom[NetLast];
+static Bool running = True;
+static Cur *cursor[CurLast];
+static ClrScheme scheme[SchemeLast];
+static Display *dpy;
+static Drw *drw;
+static Fnt *fnt;
+static Monitor *mons, *selmon;
+static Window root;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+static Systray *systray = NULL;
+static unsigned long systrayorientation = _NET_SYSTEM_TRAY_ORIENTATION_HORZ;
+static Atom wmatom[WMLast], netatom[NetLast], xatom[XLast];
+#endif
+
+
+/* configuration, allows nested code to access above variables */
+#include "config.h"
+
+#ifdef CONFIG_DWM_PERTAG
+typedef struct Pertag {
+ unsigned int curtag, prevtag; /* current and previous tag */
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
+ Bool showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
+ Client *prevzooms[LENGTH(tags) + 1]; /* store zoom information */
+} Pertag;
+#endif
+
+/* 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 = { NULL, NULL };
+
+ /* rule matching */
+ c->isfloating = c->tags = 0;
+ 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->wx + m->ww)
+ *x = m->wx + m->ww - WIDTH(c);
+ if(*y >= m->wy + m->wh)
+ *y = m->wy + m->wh - HEIGHT(c);
+ if(*x + *w + 2 * c->bw <= m->wx)
+ *x = m->wx;
+ if(*y + *h + 2 * c->bw <= m->wy)
+ *y = m->wy;
+ }
+ if(*h < bh)
+ *h = bh;
+ if(*w < bh)
+ *w = bh;
+ if(resizehints || c->isfloating || !c->mon->lt[c->mon->sellt]->arrange) {
+ /* 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);
+ if(m) {
+ arrangemon(m);
+ restack(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);
+}
+
+void
+attach(Client *c) {
+ c->next = c->mon->clients;
+ c->mon->clients = c;
+}
+
+void
+attachstack(Client *c) {
+ c->snext = c->mon->stack;
+ c->mon->stack = c;
+}
+
+void
+buttonpress(XEvent *e) {
+ unsigned int i, x, click;
+ Arg arg = {0};
+ Client *c;
+ Monitor *m;
+ XButtonPressedEvent *ev = &e->xbutton;
+
+ click = ClkRootWin;
+ /* 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
+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);
+ XUngrabKey(dpy, AnyKey, AnyModifier, root);
+ while(mons)
+ cleanupmon(mons);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ if(showsystray) {
+ XUnmapWindow(dpy, systray->win);
+ XDestroyWindow(dpy, systray->win);
+ free(systray);
+ }
+#endif
+ drw_cur_free(drw, cursor[CurNormal]);
+ drw_cur_free(drw, cursor[CurResize]);
+ drw_cur_free(drw, cursor[CurMove]);
+ drw_font_free(dpy, fnt);
+ drw_clr_free(scheme[SchemeNorm].border);
+ drw_clr_free(scheme[SchemeNorm].bg);
+ drw_clr_free(scheme[SchemeNorm].fg);
+ drw_clr_free(scheme[SchemeSel].border);
+ drw_clr_free(scheme[SchemeSel].bg);
+ drw_clr_free(scheme[SchemeSel].fg);
+ drw_free(drw);
+ XSync(dpy, False);
+ XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+}
+
+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);
+#ifdef CONFIG_DWM_PERTAG
+ int i;
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ XWindowAttributes wa;
+ XSetWindowAttributes swa;
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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));
+ c->win = cme->data.l[2];
+ 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].bg->rgb;
+ 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;
+ }
+#endif
+ if(!c)
+ return;
+ if(cme->message_type == netatom[NetWMState]) {
+ 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)));
+ }
+ else if(cme->message_type == netatom[NetActiveWindow]) {
+ if(!ISVISIBLE(c)) {
+ c->mon->seltags ^= 1;
+ c->mon->tagset[c->mon->seltags] = c->tags;
+ #ifdef CONFIG_DWM_PERTAG
+ for(i=0; !(c->tags & 1 << i); i++);
+ view(&(Arg){.ui = 1 << i});
+ #endif
+ }
+ 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;
+
+ // TODO: updategeom handling sucks, needs to be simplified
+ if(ev->window == root) {
+ dirty = (sw != ev->width || sh != ev->height);
+ sw = ev->width;
+ sh = ev->height;
+ if(updategeom() || dirty) {
+ drw_resize(drw, sw, bh);
+ updatebars();
+ for(m = mons; m; m = m->next)
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ resizebarwin(m);
+ #else
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+ #endif
+ #ifdef CONFIG_DWM_PANGO
+ //XftDrawChange(drw->xft->drawable, drw->drawable);
+ #endif
+ focus(NULL);
+ 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->oldx = c->x;
+ c->x = m->mx + ev->x;
+ }
+ if(ev->value_mask & CWY) {
+ c->oldy = c->y;
+ c->y = m->my + ev->y;
+ }
+ if(ev->value_mask & CWWidth) {
+ c->oldw = c->w;
+ c->w = ev->width;
+ }
+ if(ev->value_mask & CWHeight) {
+ c->oldh = c->h;
+ c->h = ev->height;
+ }
+ if((c->x + c->w) > m->mx + m->mw && c->isfloating)
+ c->x = m->mx + (m->mw / 2 - WIDTH(c) / 2); /* center in x direction */
+ if((c->y + c->h) > m->my + m->mh && c->isfloating)
+ c->y = m->my + (m->mh / 2 - HEIGHT(c) / 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;
+#ifdef CONFIG_DWM_PERTAG
+ int i;
+#endif
+
+ 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->nmaster = nmaster;
+ 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);
+#ifdef CONFIG_DWM_PERTAG
+ if(!(m->pertag = (Pertag *)calloc(1, sizeof(Pertag))))
+ die("fatal: could not malloc() %u bytes\n", sizeof(Pertag));
+ m->pertag->curtag = m->pertag->prevtag = 1;
+ for(i=0; i <= LENGTH(tags); i++) {
+ /* init nmaster */
+ m->pertag->nmasters[i] = m->nmaster;
+
+ /* init mfacts */
+ m->pertag->mfacts[i] = m->mfact;
+
+ /* init layouts */
+ m->pertag->ltidxs[i][0] = m->lt[0];
+ m->pertag->ltidxs[i][1] = m->lt[1];
+ m->pertag->sellts[i] = m->sellt;
+
+ /* init showbar */
+ m->pertag->showbars[i] = m->showbar;
+
+ /* swap focus and zoomswap*/
+ m->pertag->prevzooms[i] = NULL;
+ }
+#endif
+ return m;
+}
+
+void
+destroynotify(XEvent *e) {
+ Client *c;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+ if((c = wintoclient(ev->window)))
+ unmanage(c, True);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ else if((c = wintosystrayicon(ev->window))) {
+ removesystrayicon(c);
+ resizebarwin(selmon);
+ updatesystray();
+ }
+#endif
+}
+
+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;
+ }
+}
+
+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, xx, w;
+ unsigned int i, occ = 0, urg = 0;
+ Client *c;
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ resizebarwin(m);
+#endif
+ for(c = m->clients; c; c = c->next) {
+ occ |= c->tags;
+ if(c->isurgent)
+ urg |= c->tags;
+ }
+ x = 0;
+ for(i = 0; i < LENGTH(tags); i++) {
+ w = TEXTW(tags[i]);
+ drw_setscheme(drw, m->tagset[m->seltags] & 1 << i ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, tags[i], urg & 1 << i);
+ drw_rect(drw, x, 0, w, bh, m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+ occ & 1 << i, urg & 1 << i);
+ x += w;
+ }
+ w = blw = TEXTW(m->ltsymbol);
+ drw_setscheme(drw, &scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, m->ltsymbol, 0);
+ x += w;
+ xx = x;
+ if(m == selmon) { /* status is only drawn on selected monitor */
+ w = TEXTW(stext);
+ x = m->ww - w;
+ if(x < xx) {
+ x = xx;
+ w = m->ww - xx;
+ }
+ drw_text(drw, x, 0, w, bh, stext, 0);
+ }
+ else
+ x = m->ww;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ if(showsystray && m == systraytomon(m)) {
+ x -= getsystraywidth();
+ }
+#endif
+ if((w = x - xx) > bh) {
+ x = xx;
+ if(m->sel) {
+ drw_setscheme(drw, m == selmon ? &scheme[SchemeSel] : &scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, m->sel->name, 0);
+ drw_rect(drw, x, 0, w, bh, m->sel->isfixed, m->sel->isfloating, 0);
+ }
+ else {
+ drw_setscheme(drw, &scheme[SchemeNorm]);
+ drw_text(drw, x, 0, w, bh, NULL, 0);
+ }
+ }
+ drw_map(drw, m->barwin, 0, 0, m->ww, bh);
+}
+
+void
+drawbars(void) {
+ Monitor *m;
+
+ for(m = mons; m; m = m->next)
+ drawbar(m);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ updatesystray();
+#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);
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ if(m == selmon)
+ updatesystray();
+ #endif
+ }
+}
+
+void
+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, 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, scheme[SchemeSel].border->rgb);
+ setfocus(c);
+ }
+ else {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+ 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, False); /* s/True/False/ fixes input focus issues
+ in gedit and anjuta */
+ 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);
+ }
+}
+
+Atom
+getatomprop(Client *c, Atom prop) {
+ int di;
+ unsigned long dl;
+ unsigned char *p = NULL;
+ Atom da, atom = None;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ /* 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];
+#endif
+
+ if(XGetWindowProperty(dpy, c->win, prop, 0L, sizeof atom, False,
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ req,
+#else
+ XA_ATOM,
+#endif
+ &da, &di, &dl, &dl, &p) == Success && p) {
+ atom = *(Atom *)p;
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ if(da == xatom[XembedInfo] && dl == 2)
+ atom = ((Atom *)p)[1];
+ #endif
+ XFree(p);
+ }
+ return atom;
+}
+
+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
+incnmaster(const Arg *arg) {
+
+#ifdef CONFIG_DWM_PERTAG
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
+#else
+ selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
+#endif
+ arrange(selmon);
+}
+
+#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));
+}
+
+void
+killclient(const Arg *arg) {
+ if(!selmon->sel)
+ return;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ if(!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
+#else
+ if(!sendevent(selmon->sel, wmatom[WMDelete])) {
+#endif
+ 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);
+#ifdef CONFIG_DWM_OPACITY
+ opacity(c, defaultopacity);
+#endif
+ if(XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
+ c->mon = t->mon;
+ c->tags = t->tags;
+ }
+ else {
+ c->mon = selmon;
+ applyrules(c);
+ }
+ /* geometry */
+ 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->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 == 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->bw = borderpx;
+
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, w, CWBorderWidth, &wc);
+ XSetWindowBorder(dpy, w, scheme[SchemeNorm].border->rgb);
+ configure(c); /* propagates border_width, if size doesn't change */
+ updatewindowtype(c);
+ 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);
+ attach(c);
+ attachstack(c);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (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)
+ unfocus(selmon->sel, False);
+ c->mon->sel = c;
+ arrange(c->mon);
+ XMapWindow(dpy, c->win);
+ focus(NULL);
+}
+
+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;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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();
+ }
+#endif
+
+ 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
+motionnotify(XEvent *e) {
+ static Monitor *mon = NULL;
+ Monitor *m;
+ XMotionEvent *ev = &e->xmotion;
+
+ if(ev->window != root)
+ return;
+ if((m = recttomon(ev->x_root, ev->y_root, 1, 1)) != mon && mon) {
+ unfocus(selmon->sel, True);
+ selmon = m;
+ focus(NULL);
+ }
+ mon = m;
+}
+
+void
+movemouse(const Arg *arg) {
+ int x, y, ocx, ocy, nx, ny;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+
+ if(!(c = selmon->sel))
+ return;
+ if(c->isfullscreen) /* no support moving fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+ if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ None, cursor[CurMove]->cursor, 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 = recttomon(c->x, c->y, c->w, c->h)) != selmon) {
+ sendmon(c, m);
+ selmon = m;
+ focus(NULL);
+ }
+}
+
+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
+propertynotify(XEvent *e) {
+ Client *c;
+ Window trans;
+ XPropertyEvent *ev = &e->xproperty;
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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();
+ }
+#endif
+
+ 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);
+ }
+ if(ev->atom == netatom[NetWMWindowType])
+ updatewindowtype(c);
+ }
+}
+
+void
+quit(const Arg *arg) {
+ running = False;
+}
+
+Monitor *
+recttomon(int x, int y, int w, int h) {
+ Monitor *m, *r = selmon;
+ int a, area = 0;
+
+ for(m = mons; m; m = m->next)
+ if((a = INTERSECT(x, y, w, h, m)) > area) {
+ area = a;
+ r = m;
+ }
+ return r;
+}
+
+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;
+
+ c->oldx = c->x; c->x = wc.x = x;
+ c->oldy = c->y; c->y = wc.y = y;
+ c->oldw = c->w; c->w = wc.width = w;
+ c->oldh = c->h; c->h = wc.height = h;
+ wc.border_width = c->bw;
+ XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
+ configure(c);
+ XSync(dpy, False);
+}
+
+void
+resizemouse(const Arg *arg) {
+ int ocx, ocy;
+ int nw, nh;
+ Client *c;
+ Monitor *m;
+ XEvent ev;
+
+ if(!(c = selmon->sel))
+ return;
+ if(c->isfullscreen) /* no support resizing fullscreen windows by mouse */
+ return;
+ restack(selmon);
+ ocx = c->x;
+ ocy = c->y;
+ if(XGrabPointer(dpy, root, False, MOUSEMASK, GrabModeAsync, GrabModeAsync,
+ 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 {
+ 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 = recttomon(c->x, c->y, c->w, c->h)) != 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
+#ifdef CONFIG_DWM_SYSTEMTRAY
+sendevent(Window w, Atom proto, int mask, long d0, long d1, long d2, long d3, long d4) {
+#else
+sendevent(Client *c, Atom proto) {
+#endif
+ int n;
+ Atom *protocols;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ Atom mt;
+#endif
+ Bool exists = False;
+ XEvent ev;
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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;
+ }
+#else
+ if(XGetWMProtocols(dpy, c->win, &protocols, &n)) {
+ while(!exists && n--)
+ exists = protocols[n] == proto;
+ XFree(protocols);
+ }
+#endif
+ if(exists) {
+ ev.type = ClientMessage;
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ ev.xclient.window = w;
+ ev.xclient.message_type = mt;
+ #else
+ ev.xclient.window = c->win;
+ ev.xclient.message_type = wmatom[WMProtocols];
+ #endif
+ ev.xclient.format = 32;
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ 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);
+ #else
+ ev.xclient.data.l[0] = proto;
+ ev.xclient.data.l[1] = CurrentTime;
+ XSendEvent(dpy, c->win, False, NoEventMask, &ev);
+ #endif
+ }
+ return exists;
+}
+
+void
+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);
+ }
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ sendevent(c->win, wmatom[WMTakeFocus], NoEventMask, wmatom[WMTakeFocus], CurrentTime, 0, 0, 0);
+#else
+ sendevent(c, wmatom[WMTakeFocus]);
+#endif
+}
+
+void
+setfullscreen(Client *c, Bool fullscreen) {
+ if(fullscreen) {
+ XChangeProperty(dpy, c->win, 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, c->win, 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);
+ }
+}
+
+void
+setlayout(const Arg *arg) {
+ if(!arg || !arg->v || arg->v != selmon->lt[selmon->sellt]){
+ #ifdef CONFIG_DWM_PERTAG
+ selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ #else
+ selmon->sellt ^= 1;
+ #endif
+ }
+ if(arg && arg->v)
+ #ifdef CONFIG_DWM_PERTAG
+ selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
+ #else
+ selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ #endif
+
+ #ifdef CONFIG_DWM_PERTAG
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ #endif
+ 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;
+#ifdef CONFIG_DWM_PERTAG
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
+#else
+ selmon->mfact = f;
+#endif
+ arrange(selmon);
+}
+
+void
+setup(void) {
+ XSetWindowAttributes wa;
+
+ /* clean up any zombies immediately */
+ sigchld(0);
+
+ /* init screen */
+ screen = DefaultScreen(dpy);
+ root = RootWindow(dpy, screen);
+ fnt = drw_font_create(dpy, font);
+ sw = DisplayWidth(dpy, screen);
+ sh = DisplayHeight(dpy, screen);
+ bh = fnt->h + 2;
+ drw = drw_create(dpy, screen, root, sw, sh);
+ drw_setfont(drw, fnt);
+ 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);
+#ifdef CONFIG_DWM_OPACITY
+ netatom[NetWMWindowsOpacity] = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
+#endif
+ 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);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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);
+ xatom[Manager] = XInternAtom(dpy, "MANAGER", False);
+ xatom[Xembed] = XInternAtom(dpy, "_XEMBED", False);
+ xatom[XembedInfo] = XInternAtom(dpy, "_XEMBED_INFO", False);
+#endif
+ /* 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 */
+#ifdef CONFIG_DWM_PANGO
+ scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor, 0);
+ scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor, 0);
+ scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor, 0);
+ scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor, 0);
+ scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor, 0);
+ scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor, 0);
+#else
+ scheme[SchemeNorm].border = drw_clr_create(drw, normbordercolor);
+ scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor);
+ scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor);
+ scheme[SchemeSel].border = drw_clr_create(drw, selbordercolor);
+ scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor);
+ scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor);
+
+#endif
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ /* init system tray */
+ updatesystray();
+#endif
+ /* init bars */
+ updatebars();
+ updatestatus();
+ /* EWMH support per view */
+ XChangeProperty(dpy, root, netatom[NetSupported], XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) netatom, NetLast);
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ /* select for events */
+ wa.cursor = cursor[CurNormal]->cursor;
+ 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
+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, WIDTH(c) * -2, 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(arg->v == dmenucmd)
+ dmenumon[0] = '0' + selmon->num;
+ 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;
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+tagmon(const Arg *arg) {
+ if(!selmon->sel || !mons->next)
+ return;
+ sendmon(selmon->sel, dirtomon(arg->i));
+}
+
+void
+tile(Monitor *m) {
+ unsigned int i, n, h, mw, my, ty;
+ Client *c;
+
+ for(n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
+ if(n == 0)
+ return;
+
+ if(n > m->nmaster)
+ mw = m->nmaster ? m->ww * m->mfact : 0;
+ else
+ mw = m->ww;
+ for(i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
+ if(i < m->nmaster) {
+ h = (m->wh - my) / (MIN(n, m->nmaster) - i);
+ resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), False);
+ my += HEIGHT(c);
+ }
+ else {
+ h = (m->wh - ty) / (n - i);
+ resize(c, m->wx + mw, m->wy + ty, m->ww - mw - (2*c->bw), h - (2*c->bw), False);
+ ty += HEIGHT(c);
+ }
+}
+
+void
+togglebar(const Arg *arg) {
+#ifdef CONFIG_DWM_PERTAG
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
+#else
+ selmon->showbar = !selmon->showbar;
+#endif
+ updatebarpos(selmon);
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ 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);
+ }
+#else
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+#endif
+ arrange(selmon);
+}
+
+void
+togglefloating(const Arg *arg) {
+ if(!selmon->sel)
+ return;
+ if(selmon->sel->isfullscreen) /* no support for fullscreen windows */
+ 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;
+
+ if(!selmon->sel)
+ return;
+ newtags = selmon->sel->tags ^ (arg->ui & TAGMASK);
+ if(newtags) {
+ selmon->sel->tags = newtags;
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+toggleview(const Arg *arg) {
+ unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
+#ifdef CONFIG_DWM_PERTAG
+ int i;
+#endif
+
+ if(newtagset) {
+ #ifdef CONFIG_DWM_PERTAG
+ if(newtagset == ~0) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = 0;
+ }
+ /* test if the user did not select the same tag */
+ if(!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ for (i=0; !(newtagset & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+ #endif
+
+ selmon->tagset[selmon->seltags] = newtagset;
+
+ #ifdef CONFIG_DWM_PERTAG
+ /* apply settings for this view */
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+ #endif
+
+ focus(NULL);
+ arrange(selmon);
+ }
+}
+
+void
+unfocus(Client *c, Bool setfocus) {
+ if(!c)
+ return;
+ grabbuttons(c, False);
+ XSetWindowBorder(dpy, c->win, scheme[SchemeNorm].border->rgb);
+ if(setfocus) {
+ XSetInputFocus(dpy, root, RevertToPointerRoot, CurrentTime);
+ XDeleteProperty(dpy, root, netatom[NetActiveWindow]);
+ }
+}
+
+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);
+ updateclientlist();
+ arrange(m);
+}
+
+void
+unmapnotify(XEvent *e) {
+ Client *c;
+ XUnmapEvent *ev = &e->xunmap;
+
+ if((c = wintoclient(ev->window))) {
+ if(ev->send_event)
+ setclientstate(c, WithdrawnState);
+ else
+ unmanage(c, False);
+ }
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ else if((c = wintosystrayicon(ev->window))) {
+ removesystrayicon(c);
+ resizebarwin(selmon);
+ updatesystray();
+ }
+#endif
+}
+
+void
+updatebars(void) {
+ Monitor *m;
+#ifdef CONFIG_DWM_SYSTEMTRAY
+ unsigned int w;
+#endif
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+ .background_pixmap = ParentRelative,
+ .event_mask = ButtonPressMask|ExposureMask
+ };
+ for(m = mons; m; m = m->next) {
+ if (m->barwin)
+ continue;
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ 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),
+ #else
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
+ #endif
+ CopyFromParent, DefaultVisual(dpy, screen),
+ CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
+ XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
+ #ifdef CONFIG_DWM_SYSTEMTRAY
+ if(showsystray && m == systraytomon(m))
+ XMapRaised(dpy, systray->win);
+ #endif
+ 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;
+}
+
+void
+updateclientlist() {
+ Client *c;
+ Monitor *m;
+
+ XDeleteProperty(dpy, root, netatom[NetClientList]);
+ 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);
+}
+
+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;
+ 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
+updatewindowtype(Client *c) {
+ Atom state = getatomprop(c, netatom[NetWMState]);
+ Atom wtype = getatomprop(c, netatom[NetWMWindowType]);
+
+ if(state == netatom[NetWMFullscreen])
+ setfullscreen(c, True);
+ if(wtype == netatom[NetWMWindowTypeDialog])
+ c->isfloating = True;
+}
+
+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) {
+
+#ifdef CONFIG_DWM_PERTAG
+ int i;
+ unsigned int tmptag;
+#endif
+
+ if((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
+ return;
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ if(arg->ui & TAGMASK)
+ #ifdef CONFIG_DWM_PERTAG
+ {selmon->pertag->prevtag = selmon->pertag->curtag;
+ #endif
+ selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
+ #ifdef CONFIG_DWM_PERTAG
+ if(arg->ui == ~0)
+ selmon->pertag->curtag = 0;
+ else {
+ for (i=0; !(arg->ui & 1 << i); i++) ;
+ selmon->pertag->curtag = i + 1;
+ }
+ } else {
+ tmptag = selmon->pertag->prevtag;
+ selmon->pertag->prevtag = selmon->pertag->curtag;
+ selmon->pertag->curtag = tmptag;
+ }
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
+ togglebar(NULL);
+ #endif
+ focus(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 recttomon(x, y, 1, 1);
+ 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-2014 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;
+}
+
+#ifdef CONFIG_DWM_OPACITY
+void
+opacity(Client *c, double opacity)
+{
+ if(opacity >= 0 && opacity <= 1) {
+ unsigned long real_opacity[] = { opacity * 0xffffffff };
+ XChangeProperty(dpy, c->win, netatom[NetWMWindowsOpacity], XA_CARDINAL,
+ 32, PropModeReplace, (unsigned char *)real_opacity,
+ 1);
+ } else
+ XDeleteProperty(dpy, c->win, netatom[NetWMWindowsOpacity]);
+}
+#endif
+
+#ifdef CONFIG_DWM_SYSTEMTRAY
+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;
+}
+
+ 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
+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
+resizerequest(XEvent *e) {
+ XResizeRequestEvent *ev = &e->xresizerequest;
+ Client *i;
+
+ if((i = wintosystrayicon(ev->window))) {
+ updatesystrayicongeom(i, ev->width, ev->height);
+ resizebarwin(selmon);
+ updatesystray();
+ }
+}
+
+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
+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].bg->rgb);
+ wa.event_mask = ButtonPressMask | ExposureMask;
+ wa.override_redirect = True;
+ wa.background_pixel = scheme[SchemeNorm].bg->rgb;
+ XSelectInput(dpy, systray->win, SubstructureNotifyMask);
+ XChangeProperty(dpy, systray->win, netatom[NetSystemTrayOrientation], XA_CARDINAL, 32,
+ PropModeReplace, (unsigned char *)&systrayorientation, 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].bg->rgb;
+ 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].bg->rgb);
+ XFillRectangle(dpy, systray->win, drw->gc, 0, 0, w, bh);
+ XSync(dpy, False);
+}
+
+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;
+}
+#endif
diff --git a/kconf2h/kconf2h.c b/kconf2h/kconf2h.c
new file mode 100644
index 0000000..91ef6c7
--- /dev/null
+++ b/kconf2h/kconf2h.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+
+#include "kconf2h.h"
+
+int main( int argc, char **argv )
+{
+ FILE *fin = NULL;
+ FILE *fout = NULL;
+ struct stat st;
+
+ char *buf=NULL;
+ if ( argc == 3 )
+ {
+ fin = fopen( argv[1], "r+" );
+ fout = fopen( argv[2], "w+" );
+ fseek( fin, 0, SEEK_SET );
+ if ( fin && fout )
+ {
+ if ( stat( argv[1], &st ) )
+ {
+ goto error_exit;
+ }
+ buf = malloc( st.st_size ); memset( buf, 0, st.st_size );
+ size_t r_size = fread( buf, 1, st.st_size, fin );
+ if ( r_size > 0 )
+ {
+ int ret = parse_kconf2h( buf, fout );
+ printf("Kconfig file parsed %d %d bytes\n", ret, r_size );
+ } else
+ {
+ printf("ERR: while reading file %s [%d]\n", argv[1], r_size);
+ }
+error_exit:
+ if ( buf ) free( buf );
+ fclose( fin );
+ fclose( fout );
+ } else
+ {
+ printf("ERR: Cannot open file\n");
+ }
+ } else
+ {
+ printf("ERR: usage ./kconf2h [conffile] [outputheader]\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/kconf2h/kconf2h.h b/kconf2h/kconf2h.h
new file mode 100644
index 0000000..165d4cc
--- /dev/null
+++ b/kconf2h/kconf2h.h
@@ -0,0 +1,10 @@
+#ifndef __KCONF2H_H
+#define __KCONF2H_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int parse_kconf2h( const char*, FILE* );
+
+#endif
diff --git a/kconf2h/kconf2h_parser.c b/kconf2h/kconf2h_parser.c
new file mode 100644
index 0000000..5269c14
--- /dev/null
+++ b/kconf2h/kconf2h_parser.c
@@ -0,0 +1,327 @@
+
+#line 1 "kconf2h_parser.ragel"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "kconf2h.h"
+
+#define TYPE_YM 1
+#define TYPE_HEX 2
+#define TYPE_STR 3
+#define TYPE_DEC 4
+
+char *new_string( const char *start, const char *end )
+{
+ int str_s = end-start+1;
+ char *new_str=malloc( str_s+1 );
+ memcpy( new_str, start, str_s );
+ if ( new_str != NULL )
+ new_str[str_s]=0x0;
+ return new_str;
+}
+
+int o_head_def( FILE *f, int type, const char *s_define, const char *e_define,
+ const char *s_value, const char *e_value )
+{
+ if ( f != NULL )
+ {
+ if ( (s_define != NULL) && (e_define != NULL) && (s_define <= e_define) &&
+ (s_value != NULL) && ( e_value != NULL ) && ( s_value <= e_value ))
+ {
+ char *def = new_string( s_define, e_define );
+ char *val = NULL;
+ //printf( "%s\n", def );
+ fprintf( f, "#define %s", def );
+ free( def );
+
+ if ( type != TYPE_YM )
+ {
+ val = new_string( s_value, e_value );
+ fprintf( f, " %s", val );
+ free( val );
+ }
+ /*
+ switch ( type )
+ {
+ case TYPE_HEX:
+ fprintf( f, " %s", val );
+ break;
+ case TYPE_STR:
+ fprintf( f, " %s", val );
+ break;
+ case TYPE_DEC:
+ fprintf( f, " %s", val );
+ break;
+ default:
+ printf("Unknown Kconfig type %d\n", type);
+ }
+ */
+
+ fprintf( f, "\n" );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#line 71 "kconf2h_parser.c"
+static const char _k2h_actions[] = {
+ 0, 1, 0, 1, 2, 1, 7, 1,
+ 11, 2, 9, 1, 4, 3, 8, 10,
+ 11, 4, 4, 8, 10, 11, 4, 5,
+ 8, 10, 11, 4, 6, 8, 10, 11
+
+};
+
+static const char _k2h_key_offsets[] = {
+ 0, 0, 3, 6, 7, 8, 9, 10,
+ 11, 12, 17, 23, 30, 33, 37, 39,
+ 42, 46, 52, 59, 60
+};
+
+static const char _k2h_trans_keys[] = {
+ 10, 35, 67, 10, 32, 126, 79, 78,
+ 70, 73, 71, 95, 95, 48, 57, 65,
+ 90, 61, 95, 48, 57, 65, 90, 34,
+ 45, 48, 109, 121, 49, 57, 34, 32,
+ 126, 10, 34, 32, 126, 48, 57, 10,
+ 48, 57, 10, 120, 48, 57, 48, 57,
+ 65, 70, 97, 102, 10, 48, 57, 65,
+ 70, 97, 102, 10, 10, 35, 67, 0
+};
+
+static const char _k2h_single_lengths[] = {
+ 0, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 5, 1, 2, 0, 1,
+ 2, 0, 1, 1, 3
+};
+
+static const char _k2h_range_lengths[] = {
+ 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 2, 2, 1, 1, 1, 1, 1,
+ 1, 3, 3, 0, 0
+};
+
+static const char _k2h_index_offsets[] = {
+ 0, 0, 4, 7, 9, 11, 13, 15,
+ 17, 19, 23, 28, 35, 38, 42, 44,
+ 47, 51, 55, 60, 62
+};
+
+static const char _k2h_indicies[] = {
+ 0, 2, 3, 1, 0, 4, 1, 5,
+ 1, 6, 1, 7, 1, 8, 1, 9,
+ 1, 10, 1, 11, 11, 11, 1, 12,
+ 11, 11, 11, 1, 13, 14, 15, 17,
+ 17, 16, 1, 19, 18, 1, 20, 19,
+ 18, 1, 21, 1, 22, 21, 1, 22,
+ 23, 21, 1, 24, 24, 24, 1, 25,
+ 24, 24, 24, 1, 26, 1, 0, 2,
+ 3, 1, 0
+};
+
+static const char _k2h_trans_targs[] = {
+ 20, 0, 2, 3, 2, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 14, 16,
+ 15, 19, 12, 13, 20, 15, 20, 17,
+ 18, 20, 20
+};
+
+static const char _k2h_trans_actions[] = {
+ 7, 0, 1, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 5, 5, 5,
+ 5, 5, 0, 0, 22, 0, 17, 0,
+ 0, 27, 12
+};
+
+static const int k2h_start = 1;
+static const int k2h_first_final = 20;
+static const int k2h_error = 0;
+
+static const int k2h_en_main = 1;
+
+
+#line 87 "kconf2h_parser.ragel"
+
+
+int parse_kconf2h( const char *str, FILE *outf )
+{
+
+
+
+ static uint8_t cs;
+ const int stacksize = 10;
+ int res=0, *top=0, *stack=NULL;
+ stack = malloc( sizeof(stack)*stacksize );
+ char *p=(char *)str, *pe = (char *)str + strlen( str ), *eof=NULL;
+
+ /*
+ variables used in state machine
+ */
+ char *token_s=NULL, *token_e=NULL;
+ char *value_s=NULL, *value_e=NULL;
+ int token_type=0;
+ fprintf( outf, "#ifndef __KCONFIG_H\n" );
+ fprintf( outf, "#define __KCONFIG_H\n" );
+
+
+#line 172 "kconf2h_parser.c"
+ {
+ cs = k2h_start;
+ }
+
+#line 110 "kconf2h_parser.ragel"
+
+#line 179 "kconf2h_parser.c"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _k2h_trans_keys + _k2h_key_offsets[cs];
+ _trans = _k2h_index_offsets[cs];
+
+ _klen = _k2h_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _k2h_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _k2h_indicies[_trans];
+ cs = _k2h_trans_targs[_trans];
+
+ if ( _k2h_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _k2h_actions + _k2h_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 72 "kconf2h_parser.ragel"
+ {}
+ break;
+ case 1:
+#line 73 "kconf2h_parser.ragel"
+ {token_s = p;}
+ break;
+ case 2:
+#line 73 "kconf2h_parser.ragel"
+ {token_e = p-1;}
+ break;
+ case 3:
+#line 76 "kconf2h_parser.ragel"
+ {token_type=TYPE_YM;}
+ break;
+ case 4:
+#line 77 "kconf2h_parser.ragel"
+ {token_type=TYPE_DEC;}
+ break;
+ case 5:
+#line 78 "kconf2h_parser.ragel"
+ {token_type=TYPE_STR;}
+ break;
+ case 6:
+#line 79 "kconf2h_parser.ragel"
+ {token_type=TYPE_HEX;}
+ break;
+ case 7:
+#line 79 "kconf2h_parser.ragel"
+ {value_s = p;}
+ break;
+ case 8:
+#line 79 "kconf2h_parser.ragel"
+ {value_e = p-1;}
+ break;
+ case 9:
+#line 80 "kconf2h_parser.ragel"
+ {}
+ break;
+ case 10:
+#line 80 "kconf2h_parser.ragel"
+ { o_head_def( outf, token_type, token_s, token_e, value_s, value_e ); }
+ break;
+ case 11:
+#line 82 "kconf2h_parser.ragel"
+ {}
+ break;
+#line 301 "kconf2h_parser.c"
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 111 "kconf2h_parser.ragel"
+
+ if ( cs == k2h_error )
+ {
+ printf("ERR state [%d] pos[%d]:[%s]\n", res, p-str, p);
+ res = -1;
+ }
+
+ fprintf( outf, "#endif\n" );
+
+ return res;
+}
+
+
+
diff --git a/kconfig.h b/kconfig.h
new file mode 100644
index 0000000..a70c0a7
--- /dev/null
+++ b/kconfig.h
@@ -0,0 +1,3 @@
+#ifndef __KCONFIG_H
+#define __KCONFIG_H
+#endif
diff --git a/transient.c b/transient.c
new file mode 100644
index 0000000..040adb5
--- /dev/null
+++ b/transient.c
@@ -0,0 +1,42 @@
+/* cc transient.c -o transient -lX11 */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+int main(void) {
+ Display *d;
+ Window r, f, t = None;
+ XSizeHints h;
+ XEvent e;
+
+ d = XOpenDisplay(NULL);
+ if (!d)
+ exit(1);
+ r = DefaultRootWindow(d);
+
+ f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0);
+ h.min_width = h.max_width = h.min_height = h.max_height = 400;
+ h.flags = PMinSize | PMaxSize;
+ XSetWMNormalHints(d, f, &h);
+ XStoreName(d, f, "floating");
+ XMapWindow(d, f);
+
+ XSelectInput(d, f, ExposureMask);
+ while (1) {
+ XNextEvent(d, &e);
+
+ if (t == None) {
+ sleep(5);
+ t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0);
+ XSetTransientForHint(d, t, f);
+ XStoreName(d, t, "transient");
+ XMapWindow(d, t);
+ XSelectInput(d, t, ExposureMask);
+ }
+ }
+
+ XCloseDisplay(d);
+ exit(0);
+}
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..51acd1a
--- /dev/null
+++ b/util.c
@@ -0,0 +1,17 @@
+/* See LICENSE file for copyright and license details. */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+
+void
+die(const char *errstr, ...) {
+ va_list ap;
+
+ va_start(ap, errstr);
+ vfprintf(stderr, errstr, ap);
+ va_end(ap);
+ exit(EXIT_FAILURE);
+}
+
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..c05f038
--- /dev/null
+++ b/util.h
@@ -0,0 +1,11 @@
+/* See LICENSE file for copyright and license details. */
+
+#ifndef MAX
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+#endif
+
+#ifndef MIN
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#endif
+
+void die(const char *errstr, ...);