aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.def.h206
-rw-r--r--config.mk8
-rw-r--r--drw.c2
-rw-r--r--drw.h2
-rw-r--r--dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff430
-rw-r--r--dwm-bidi-20220309-0386419.diff132
-rw-r--r--dwm-xresources-20210827-138b405.diff240
-rw-r--r--dwm.c304
8 files changed, 1210 insertions, 114 deletions
diff --git a/config.def.h b/config.def.h
index a2ac963..cfcfc2d 100644
--- a/config.def.h
+++ b/config.def.h
@@ -1,116 +1,146 @@
/* See LICENSE file for copyright and license details. */
/* appearance */
-static const unsigned int borderpx = 1; /* border pixel of windows */
-static const unsigned int snap = 32; /* snap pixel */
-static const int showbar = 1; /* 0 means no bar */
-static const int topbar = 1; /* 0 means bottom bar */
-static const char *fonts[] = { "monospace:size=10" };
-static const char dmenufont[] = "monospace:size=10";
-static const char col_gray1[] = "#222222";
-static const char col_gray2[] = "#444444";
-static const char col_gray3[] = "#bbbbbb";
-static const char col_gray4[] = "#eeeeee";
-static const char col_cyan[] = "#005577";
-static const char *colors[][3] = {
- /* fg bg border */
- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
+static unsigned int borderpx = 1; /* border pixel of windows */
+static unsigned int snap = 32; /* snap pixel */
+static int showbar = 1; /* 0 means no bar */
+static int topbar = 1; /* 0 means bottom bar */
+static const int usealtbar = 1; /* 1 means use non-dwm status bar */
+static const char *altbarclass = "Polybar"; /* Alternate bar class name */
+static const char *alttrayname = "tray"; /* Polybar tray instance name */
+static const char *altbarcmd =
+ "$HOME/bar.sh"; /* Alternate bar launch command */
+static char font[] = "monospace:size=10";
+static char dmenufont[] = "monospace:size=10";
+static const char *fonts[] = {font};
+static char normbgcolor[] = "#222222";
+static char normbordercolor[] = "#444444";
+static char normfgcolor[] = "#bbbbbb";
+static char selfgcolor[] = "#eeeeee";
+static char selbordercolor[] = "#005577";
+static char selbgcolor[] = "#005577";
+static char *colors[][3] = {
+ /* fg bg border */
+ [SchemeNorm] = {normfgcolor, normbgcolor, normbordercolor},
+ [SchemeSel] = {selfgcolor, selbgcolor, selbordercolor},
};
/* tagging */
-static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+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, 1, -1 },
- { "Firefox", NULL, NULL, 1 << 8, 0, -1 },
+ /* xprop(1):
+ * WM_CLASS(STRING) = instance, class
+ * WM_NAME(STRING) = title
+ */
+ /* class instance title tags mask isfloating monitor */
+ {"Gimp", NULL, NULL, 0, 1, -1},
+ {"Firefox", NULL, NULL, 1 << 8, 0, -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 int resizehints = 1; /* 1 means respect size hints in tiled resizals */
-static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
+static int nmaster = 1; /* number of clients in master area */
+static int resizehints = 1; /* 1 means respect size hints in tiled resizals */
+static const int lockfullscreen =
+ 1; /* 1 will force focus on the fullscreen window */
static const Layout layouts[] = {
- /* symbol arrange function */
- { "[]=", tile }, /* first entry is default */
- { "><>", NULL }, /* no layout function means floating behavior */
- { "[M]", monocle },
+ /* 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} },
+#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 } }
+#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", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
-static const char *termcmd[] = { "st", NULL };
+static char dmenumon[2] =
+ "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = {"dmenu_run", "-m", dmenumon, "-fn",
+ dmenufont, "-nb", normbgcolor, "-nf",
+ normfgcolor, "-sb", selbordercolor, "-sf",
+ selfgcolor, NULL};
+static const char *termcmd[] = {"st", NULL};
+
+/*
+ * Xresources preferences to load at startup
+ */
+ResourcePref resources[] = {
+ {"font", STRING, &font},
+ {"dmenufont", STRING, &dmenufont},
+ {"normbgcolor", STRING, &normbgcolor},
+ {"normbordercolor", STRING, &normbordercolor},
+ {"normfgcolor", STRING, &normfgcolor},
+ {"selbgcolor", STRING, &selbgcolor},
+ {"selbordercolor", STRING, &selbordercolor},
+ {"selfgcolor", STRING, &selfgcolor},
+ {"borderpx", INTEGER, &borderpx},
+ {"snap", INTEGER, &snap},
+ {"showbar", INTEGER, &showbar},
+ {"topbar", INTEGER, &topbar},
+ {"nmaster", INTEGER, &nmaster},
+ {"resizehints", INTEGER, &resizehints},
+ {"mfact", FLOAT, &mfact},
+};
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} },
+ /* 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 ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
+ * ClkClientWin, or ClkRootWin */
static Button buttons[] = {
- /* click event mask button function argument */
- { ClkLtSymbol, 0, Button1, setlayout, {0} },
- { 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} },
+ /* 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.mk b/config.mk
index b6eb7e0..5b60a24 100644
--- a/config.mk
+++ b/config.mk
@@ -10,6 +10,8 @@ MANPREFIX = ${PREFIX}/share/man
X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib
+BDINC = /usr/include/fribidi
+
# Xinerama, comment if you don't want it
XINERAMALIBS = -lXinerama
XINERAMAFLAGS = -DXINERAMA
@@ -20,9 +22,11 @@ FREETYPEINC = /usr/include/freetype2
# OpenBSD (uncomment)
#FREETYPEINC = ${X11INC}/freetype2
+BDLIBS = -lfribidi
+
# includes and libs
-INCS = -I${X11INC} -I${FREETYPEINC}
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
+INCS = -I${X11INC} -I${FREETYPEINC} -I$(BDINC)
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} $(BDLIBS)
# flags
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
diff --git a/drw.c b/drw.c
index 4cdbcbe..8f1059e 100644
--- a/drw.c
+++ b/drw.c
@@ -208,7 +208,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
/* Wrapper to create color schemes. The caller has to call free(3) on the
* returned color scheme when done using it. */
Clr *
-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
+drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount)
{
size_t i;
Clr *ret;
diff --git a/drw.h b/drw.h
index 4bcd5ad..42b04ce 100644
--- a/drw.h
+++ b/drw.h
@@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
/* Colorscheme abstraction */
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
+Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *drw, int shape);
diff --git a/dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff b/dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff
new file mode 100644
index 0000000..065ee1e
--- /dev/null
+++ b/dwm-anybar-polybar-tray-fix-20200810-bb2e722.diff
@@ -0,0 +1,430 @@
+From 9b5719969ce85c3ecc0238d49c0255c5c2cc79f0 Mon Sep 17 00:00:00 2001
+From: mihirlad55 <mihirlad55@gmail.com>
+Date: Mon, 10 Aug 2020 01:39:28 +0000
+Subject: [PATCH] Add support for managing external status bars
+
+This patch allows dwm to manage other status bars such as
+polybar/lemonbar without them needing to set override-redirect. For
+all intents and purposes, DWM treats this bar as if it were its own
+and as a result helps the status bar and DWM live in harmony.
+
+This has a few advantages
+* The bar does not block fullscreen windows
+* DWM makes room for the status bar, so windows do not overlap the bar
+* The bar can be hidden/killed and DWM will not keep an unsightly gap
+ where the bar was
+* DWM receives EnterNotify events when your cursor enters the bar
+
+To use another status bar, set usealtbar to 1 in your config.h and set
+altbarclass to the class name (can be found using xprop) to the class
+name of your status bar. Also make sure that if your status bar will
+be displayed on top, topbar is set to 1 in your config, and if it will
+be displayed on bottom, topbar is set to 0. This patch does not
+support bars that are not docked at the top or at the bottom of your
+monitor.
+
+This verison of the patch fixes handling of polybar's tray.
+
+The patch is developed at https://github.com/mihirlad55/dwm-anybar
+---
+ config.def.h | 4 ++
+ dwm.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++----
+ 2 files changed, 181 insertions(+), 15 deletions(-)
+
+diff --git a/dwm.c b/dwm.c
+index 9fd0286..c1d8ce0 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -47,8 +47,8 @@
+ /* 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 INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
++ * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
+ #define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+ #define MOUSEMASK (BUTTONMASK|PointerMotionMask)
+@@ -116,7 +116,8 @@ struct Monitor {
+ float mfact;
+ int nmaster;
+ int num;
+- int by; /* bar geometry */
++ int by, bh; /* bar geometry */
++ int tx, tw; /* bar tray geometry */
+ int mx, my, mw, mh; /* screen size */
+ int wx, wy, ww, wh; /* window area */
+ unsigned int seltags;
+@@ -129,6 +130,7 @@ struct Monitor {
+ Client *stack;
+ Monitor *next;
+ Window barwin;
++ Window traywin;
+ const Layout *lt[2];
+ };
+
+@@ -179,6 +181,8 @@ 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 managealtbar(Window win, XWindowAttributes *wa);
++static void managetray(Window win, XWindowAttributes *wa);
+ static void mappingnotify(XEvent *e);
+ static void maprequest(XEvent *e);
+ static void monocle(Monitor *m);
+@@ -195,6 +199,7 @@ static void resizemouse(const Arg *arg);
+ static void restack(Monitor *m);
+ static void run(void);
+ static void scan(void);
++static void scantray(void);
+ static int sendevent(Client *c, Atom proto);
+ static void sendmon(Client *c, Monitor *m);
+ static void setclientstate(Client *c, long state);
+@@ -207,6 +212,7 @@ static void seturgent(Client *c, int urg);
+ static void showhide(Client *c);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static void spawnbar();
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *);
+@@ -216,6 +222,8 @@ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unfocus(Client *c, int setfocus);
+ static void unmanage(Client *c, int destroyed);
++static void unmanagealtbar(Window w);
++static void unmanagetray(Window w);
+ static void unmapnotify(XEvent *e);
+ static void updatebarpos(Monitor *m);
+ static void updatebars(void);
+@@ -230,6 +238,7 @@ static void updatewmhints(Client *c);
+ static void view(const Arg *arg);
+ static Client *wintoclient(Window w);
+ static Monitor *wintomon(Window w);
++static int wmclasscontains(Window win, const char *class, const char *name);
+ static int xerror(Display *dpy, XErrorEvent *ee);
+ static int xerrordummy(Display *dpy, XErrorEvent *ee);
+ static int xerrorstart(Display *dpy, XErrorEvent *ee);
+@@ -505,8 +514,10 @@ cleanupmon(Monitor *mon)
+ for (m = mons; m && m->next != mon; m = m->next);
+ m->next = mon->next;
+ }
+- XUnmapWindow(dpy, mon->barwin);
+- XDestroyWindow(dpy, mon->barwin);
++ if (!usealtbar) {
++ XUnmapWindow(dpy, mon->barwin);
++ XDestroyWindow(dpy, mon->barwin);
++ }
+ free(mon);
+ }
+
+@@ -568,7 +579,7 @@ configurenotify(XEvent *e)
+ for (c = m->clients; c; c = c->next)
+ if (c->isfullscreen)
+ resizeclient(c, m->mx, m->my, m->mw, m->mh);
+- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
++ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh);
+ }
+ focus(NULL);
+ arrange(NULL);
+@@ -639,6 +650,7 @@ createmon(void)
+ m->nmaster = nmaster;
+ m->showbar = showbar;
+ m->topbar = topbar;
++ m->bh = bh;
+ m->lt[0] = &layouts[0];
+ m->lt[1] = &layouts[1 % LENGTH(layouts)];
+ strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
+@@ -649,10 +661,15 @@ void
+ destroynotify(XEvent *e)
+ {
+ Client *c;
++ Monitor *m;
+ XDestroyWindowEvent *ev = &e->xdestroywindow;
+
+ if ((c = wintoclient(ev->window)))
+ unmanage(c, 1);
++ else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
++ unmanagealtbar(ev->window);
++ else if (m->traywin == ev->window)
++ unmanagetray(ev->window);
+ }
+
+ void
+@@ -696,6 +713,9 @@ dirtomon(int dir)
+ void
+ drawbar(Monitor *m)
+ {
++ if (usealtbar)
++ return;
++
+ int x, w, tw = 0;
+ int boxs = drw->fonts->h / 9;
+ int boxw = drw->fonts->h / 6 + 2;
+@@ -1077,6 +1097,45 @@ manage(Window w, XWindowAttributes *wa)
+ focus(NULL);
+ }
+
++void
++managealtbar(Window win, XWindowAttributes *wa)
++{
++ Monitor *m;
++ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
++ return;
++
++ m->barwin = win;
++ m->by = wa->y;
++ bh = m->bh = wa->height;
++ updatebarpos(m);
++ arrange(m);
++ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
++ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
++ XMapWindow(dpy, win);
++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
++ (unsigned char *) &win, 1);
++}
++
++void
++managetray(Window win, XWindowAttributes *wa)
++{
++ Monitor *m;
++ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
++ return;
++
++ m->traywin = win;
++ m->tx = wa->x;
++ m->tw = wa->width;
++ updatebarpos(m);
++ arrange(m);
++ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
++ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
++ XMapWindow(dpy, win);
++ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
++ (unsigned char *) &win, 1);
++}
++
++
+ void
+ mappingnotify(XEvent *e)
+ {
+@@ -1097,7 +1156,9 @@ maprequest(XEvent *e)
+ return;
+ if (wa.override_redirect)
+ return;
+- if (!wintoclient(ev->window))
++ if (wmclasscontains(ev->window, altbarclass, ""))
++ managealtbar(ev->window, &wa);
++ else if (!wintoclient(ev->window))
+ manage(ev->window, &wa);
+ }
+
+@@ -1393,7 +1454,9 @@ scan(void)
+ if (!XGetWindowAttributes(dpy, wins[i], &wa)
+ || wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
+ continue;
+- if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
++ if (wmclasscontains(wins[i], altbarclass, ""))
++ managealtbar(wins[i], &wa);
++ else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+ manage(wins[i], &wa);
+ }
+ for (i = 0; i < num; i++) { /* now the transients */
+@@ -1408,6 +1471,29 @@ scan(void)
+ }
+ }
+
++void
++scantray(void)
++{
++ unsigned int num;
++ Window d1, d2, *wins = NULL;
++ XWindowAttributes wa;
++
++ if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
++ for (unsigned int i = 0; i < num; i++) {
++ if (wmclasscontains(wins[i], altbarclass, alttrayname)) {
++ if (!XGetWindowAttributes(dpy, wins[i], &wa))
++ break;
++ managetray(wins[i], &wa);
++ }
++ }
++ }
++
++ if (wins)
++ XFree(wins);
++}
++
++
++
+ void
+ sendmon(Client *c, Monitor *m)
+ {
+@@ -1546,7 +1632,7 @@ setup(void)
+ if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
+ die("no fonts could be loaded.");
+ lrpad = drw->fonts->h;
+- bh = drw->fonts->h + 2;
++ bh = usealtbar ? 0 : drw->fonts->h + 2;
+ updategeom();
+ /* init atoms */
+ utf8string = XInternAtom(dpy, "UTF8_STRING", False);
+@@ -1595,6 +1681,7 @@ setup(void)
+ XSelectInput(dpy, root, wa.event_mask);
+ grabkeys();
+ focus(NULL);
++ spawnbar();
+ }
+
+
+@@ -1653,6 +1740,13 @@ spawn(const Arg *arg)
+ }
+ }
+
++void
++spawnbar()
++{
++ if (*altbarcmd)
++ system(altbarcmd);
++}
++
+ void
+ tag(const Arg *arg)
+ {
+@@ -1702,9 +1796,18 @@ tile(Monitor *m)
+ void
+ togglebar(const Arg *arg)
+ {
++ /**
++ * Polybar tray does not raise maprequest event. It must be manually scanned
++ * for. Scanning it too early while the tray is being populated would give
++ * wrong dimensions.
++ */
++ if (!selmon->traywin)
++ scantray();
++
+ selmon->showbar = !selmon->showbar;
+ updatebarpos(selmon);
+- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
++ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh);
++ XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh);
+ arrange(selmon);
+ }
+
+@@ -1787,10 +1890,41 @@ unmanage(Client *c, int destroyed)
+ arrange(m);
+ }
+
++void
++unmanagealtbar(Window w)
++{
++ Monitor *m = wintomon(w);
++
++ if (!m)
++ return;
++
++ m->barwin = 0;
++ m->by = 0;
++ m->bh = 0;
++ updatebarpos(m);
++ arrange(m);
++}
++
++void
++unmanagetray(Window w)
++{
++ Monitor *m = wintomon(w);
++
++ if (!m)
++ return;
++
++ m->traywin = 0;
++ m->tx = 0;
++ m->tw = 0;
++ updatebarpos(m);
++ arrange(m);
++}
++
+ void
+ unmapnotify(XEvent *e)
+ {
+ Client *c;
++ Monitor *m;
+ XUnmapEvent *ev = &e->xunmap;
+
+ if ((c = wintoclient(ev->window))) {
+@@ -1798,12 +1932,18 @@ unmapnotify(XEvent *e)
+ setclientstate(c, WithdrawnState);
+ else
+ unmanage(c, 0);
+- }
++ } else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
++ unmanagealtbar(ev->window);
++ else if (m->traywin == ev->window)
++ unmanagetray(ev->window);
+ }
+
+ void
+ updatebars(void)
+ {
++ if (usealtbar)
++ return;
++
+ Monitor *m;
+ XSetWindowAttributes wa = {
+ .override_redirect = True,
+@@ -1829,11 +1969,11 @@ updatebarpos(Monitor *m)
+ m->wy = m->my;
+ m->wh = m->mh;
+ if (m->showbar) {
+- m->wh -= bh;
++ m->wh -= m->bh;
+ m->by = m->topbar ? m->wy : m->wy + m->wh;
+- m->wy = m->topbar ? m->wy + bh : m->wy;
++ m->wy = m->topbar ? m->wy + m->bh : m->wy;
+ } else
+- m->by = -bh;
++ m->by = -m->bh;
+ }
+
+ void
+@@ -2070,13 +2210,35 @@ wintomon(Window w)
+ if (w == root && getrootptr(&x, &y))
+ return recttomon(x, y, 1, 1);
+ for (m = mons; m; m = m->next)
+- if (w == m->barwin)
++ if (w == m->barwin || w == m->traywin)
+ return m;
+ if ((c = wintoclient(w)))
+ return c->mon;
+ return selmon;
+ }
+
++int
++wmclasscontains(Window win, const char *class, const char *name)
++{
++ XClassHint ch = { NULL, NULL };
++ int res = 1;
++
++ if (XGetClassHint(dpy, win, &ch)) {
++ if (ch.res_name && strstr(ch.res_name, name) == NULL)
++ res = 0;
++ if (ch.res_class && strstr(ch.res_class, class) == NULL)
++ res = 0;
++ } else
++ res = 0;
++
++ if (ch.res_class)
++ XFree(ch.res_class);
++ if (ch.res_name)
++ XFree(ch.res_name);
++
++ return res;
++}
++
+ /* 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. */
+--
+2.28.0
+
diff --git a/dwm-bidi-20220309-0386419.diff b/dwm-bidi-20220309-0386419.diff
new file mode 100644
index 0000000..1d9be02
--- /dev/null
+++ b/dwm-bidi-20220309-0386419.diff
@@ -0,0 +1,132 @@
+From 0386419cfb5311d4a7516ece8f3f8fe923c43098 Mon Sep 17 00:00:00 2001
+From: MahdiMirzade <me@mahdym.ir>
+Date: Wed, 9 Mar 2022 17:44:42 +0330
+Subject: [PATCH] [PATCH] Added support for RTL languages (Farsi, Arabic and
+ Hebrew using the FriBiDi library) - 9th Mar 2022 Fix
+
+---
+ config.mk | 8 ++++++--
+ dwm.c | 40 +++++++++++++++++++++++++++++++++-------
+ 2 files changed, 39 insertions(+), 9 deletions(-)
+
+diff --git a/config.mk b/config.mk
+index b6eb7e0..5b60a24 100644
+--- a/config.mk
++++ b/config.mk
+@@ -10,6 +10,8 @@ MANPREFIX = ${PREFIX}/share/man
+ X11INC = /usr/X11R6/include
+ X11LIB = /usr/X11R6/lib
+
++BDINC = /usr/include/fribidi
++
+ # Xinerama, comment if you don't want it
+ XINERAMALIBS = -lXinerama
+ XINERAMAFLAGS = -DXINERAMA
+@@ -20,9 +22,11 @@ FREETYPEINC = /usr/include/freetype2
+ # OpenBSD (uncomment)
+ #FREETYPEINC = ${X11INC}/freetype2
+
++BDLIBS = -lfribidi
++
+ # includes and libs
+-INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
++INCS = -I${X11INC} -I${FREETYPEINC} -I$(BDINC)
++LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} $(BDLIBS)
+
+ # flags
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
+diff --git a/dwm.c b/dwm.c
+index a96f33c..4f11fa0 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -40,6 +40,7 @@
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+ #include <X11/Xft/Xft.h>
++#include <fribidi.h>
+
+ #include "drw.h"
+ #include "util.h"
+@@ -238,6 +239,7 @@ static void zoom(const Arg *arg);
+ /* variables */
+ static const char broken[] = "broken";
+ static char stext[256];
++static char fribidi_text[BUFSIZ] = "";
+ static int screen;
+ static int sw, sh; /* X display screen geometry width, height */
+ static int bh, blw = 0; /* bar geometry */
+@@ -276,6 +278,26 @@ static Window root, wmcheckwin;
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
+ /* function implementations */
++static void
++apply_fribidi(char *str)
++{
++ FriBidiStrIndex len = strlen(str);
++ FriBidiChar logical[BUFSIZ];
++ FriBidiChar visual[BUFSIZ];
++ FriBidiParType base = FRIBIDI_PAR_ON;
++ FriBidiCharSet charset;
++ fribidi_boolean result;
++
++ fribidi_text[0] = 0;
++ if (len>0)
++ {
++ charset = fribidi_parse_charset("UTF-8");
++ len = fribidi_charset_to_unicode(charset, str, len, logical);
++ result = fribidi_log2vis(logical, len, &base, visual, NULL, NULL, NULL);
++ len = fribidi_unicode_to_charset(charset, visual, len, fribidi_text);
++ }
++}
++
+ void
+ applyrules(Client *c)
+ {
+@@ -708,8 +730,9 @@ drawbar(Monitor *m)
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
+ drw_setscheme(drw, scheme[SchemeNorm]);
+- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
+- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
++ apply_fribidi(stext);
++ tw = TEXTW(fribidi_text) - lrpad + 2; /* 2px right padding */
++ drw_text(drw, m->ww - tw, 0, tw, bh, 0, fribidi_text, 0);
+ }
+
+ for (c = m->clients; c; c = c->next) {
+@@ -719,23 +742,26 @@ drawbar(Monitor *m)
+ }
+ x = 0;
+ for (i = 0; i < LENGTH(tags); i++) {
+- w = TEXTW(tags[i]);
++ apply_fribidi(tags[i]);
++ w = TEXTW(fribidi_text);
+ drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, urg & 1 << i);
+ if (occ & 1 << i)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw,
+ m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
+ urg & 1 << i);
+ x += w;
+ }
+- w = blw = TEXTW(m->ltsymbol);
++ apply_fribidi(m->ltsymbol);
++ w = blw = TEXTW(fribidi_text);
+ drw_setscheme(drw, scheme[SchemeNorm]);
+- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
++ x = drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0);
+
+ if ((w = m->ww - tw - x) > bh) {
+ if (m->sel) {
+ drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
+- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
++ apply_fribidi(m->sel->name);
++ drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0);
+ if (m->sel->isfloating)
+ drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
+ } else {
+--
+2.35.1
+
diff --git a/dwm-xresources-20210827-138b405.diff b/dwm-xresources-20210827-138b405.diff
new file mode 100644
index 0000000..29852a9
--- /dev/null
+++ b/dwm-xresources-20210827-138b405.diff
@@ -0,0 +1,240 @@
+From f30583c6e2ab5e7de6ef4ebf156076ac0f6e69fc Mon Sep 17 00:00:00 2001
+From: Jack Bird <jack.bird@durham.ac.uk>
+Date: Fri, 27 Aug 2021 00:53:14 +0100
+Subject: [PATCH] xresources updated for 138b405
+
+---
+ config.def.h | 61 ++++++++++++++++++++++++++++++--------------
+ drw.c | 2 +-
+ drw.h | 2 +-
+ dwm.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 116 insertions(+), 21 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index a2ac963..87ac198 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -1,21 +1,23 @@
+ /* See LICENSE file for copyright and license details. */
+
+ /* appearance */
+-static const unsigned int borderpx = 1; /* border pixel of windows */
+-static const unsigned int snap = 32; /* snap pixel */
+-static const int showbar = 1; /* 0 means no bar */
+-static const int topbar = 1; /* 0 means bottom bar */
+-static const char *fonts[] = { "monospace:size=10" };
+-static const char dmenufont[] = "monospace:size=10";
+-static const char col_gray1[] = "#222222";
+-static const char col_gray2[] = "#444444";
+-static const char col_gray3[] = "#bbbbbb";
+-static const char col_gray4[] = "#eeeeee";
+-static const char col_cyan[] = "#005577";
+-static const char *colors[][3] = {
+- /* fg bg border */
+- [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+- [SchemeSel] = { col_gray4, col_cyan, col_cyan },
++static unsigned int borderpx = 1; /* border pixel of windows */
++static unsigned int snap = 32; /* snap pixel */
++static int showbar = 1; /* 0 means no bar */
++static int topbar = 1; /* 0 means bottom bar */
++static char font[] = "monospace:size=10";
++static char dmenufont[] = "monospace:size=10";
++static const char *fonts[] = { font };
++static char normbgcolor[] = "#222222";
++static char normbordercolor[] = "#444444";
++static char normfgcolor[] = "#bbbbbb";
++static char selfgcolor[] = "#eeeeee";
++static char selbordercolor[] = "#005577";
++static char selbgcolor[] = "#005577";
++static char *colors[][3] = {
++ /* fg bg border */
++ [SchemeNorm] = { normfgcolor, normbgcolor, normbordercolor },
++ [SchemeSel] = { selfgcolor, selbgcolor, selbordercolor },
+ };
+
+ /* tagging */
+@@ -32,9 +34,9 @@ static const Rule rules[] = {
+ };
+
+ /* 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 int resizehints = 1; /* 1 means respect size hints in tiled resizals */
++static float mfact = 0.55; /* factor of master area size [0.05..0.95] */
++static int nmaster = 1; /* number of clients in master area */
++static int resizehints = 1; /* 1 means respect size hints in tiled resizals */
+ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
+
+ static const Layout layouts[] = {
+@@ -57,9 +59,30 @@ static const Layout layouts[] = {
+
+ /* commands */
+ static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+-static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
++static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", normbgcolor, "-nf", normfgcolor, "-sb", selbordercolor, "-sf", selfgcolor, NULL };
+ static const char *termcmd[] = { "st", NULL };
+
++/*
++ * Xresources preferences to load at startup
++ */
++ResourcePref resources[] = {
++ { "font", STRING, &font },
++ { "dmenufont", STRING, &dmenufont },
++ { "normbgcolor", STRING, &normbgcolor },
++ { "normbordercolor", STRING, &normbordercolor },
++ { "normfgcolor", STRING, &normfgcolor },
++ { "selbgcolor", STRING, &selbgcolor },
++ { "selbordercolor", STRING, &selbordercolor },
++ { "selfgcolor", STRING, &selfgcolor },
++ { "borderpx", INTEGER, &borderpx },
++ { "snap", INTEGER, &snap },
++ { "showbar", INTEGER, &showbar },
++ { "topbar", INTEGER, &topbar },
++ { "nmaster", INTEGER, &nmaster },
++ { "resizehints", INTEGER, &resizehints },
++ { "mfact", FLOAT, &mfact },
++};
++
+ static Key keys[] = {
+ /* modifier key function argument */
+ { MODKEY, XK_p, spawn, {.v = dmenucmd } },
+diff --git a/drw.c b/drw.c
+index 4cdbcbe..8f1059e 100644
+--- a/drw.c
++++ b/drw.c
+@@ -208,7 +208,7 @@ drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
+ /* Wrapper to create color schemes. The caller has to call free(3) on the
+ * returned color scheme when done using it. */
+ Clr *
+-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
++drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount)
+ {
+ size_t i;
+ Clr *ret;
+diff --git a/drw.h b/drw.h
+index 4bcd5ad..42b04ce 100644
+--- a/drw.h
++++ b/drw.h
+@@ -39,7 +39,7 @@ void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned in
+
+ /* Colorscheme abstraction */
+ void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
+-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
++Clr *drw_scm_create(Drw *drw, char *clrnames[], size_t clrcount);
+
+ /* Cursor abstraction */
+ Cur *drw_cur_create(Drw *drw, int shape);
+diff --git a/dwm.c b/dwm.c
+index 5e4d494..2214b19 100644
+--- a/dwm.c
++++ b/dwm.c
+@@ -36,6 +36,7 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xproto.h>
+ #include <X11/Xutil.h>
++#include <X11/Xresource.h>
+ #ifdef XINERAMA
+ #include <X11/extensions/Xinerama.h>
+ #endif /* XINERAMA */
+@@ -141,6 +142,19 @@ typedef struct {
+ int monitor;
+ } Rule;
+
++/* Xresources preferences */
++enum resource_type {
++ STRING = 0,
++ INTEGER = 1,
++ FLOAT = 2
++};
++
++typedef struct {
++ char *name;
++ enum resource_type type;
++ void *dst;
++} ResourcePref;
++
+ /* function declarations */
+ static void applyrules(Client *c);
+ static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
+@@ -234,6 +248,8 @@ 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);
++static void load_xresources(void);
++static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -2127,6 +2143,60 @@ zoom(const Arg *arg)
+ pop(c);
+ }
+
++void
++resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
++{
++ char *sdst = NULL;
++ int *idst = NULL;
++ float *fdst = NULL;
++
++ sdst = dst;
++ idst = dst;
++ fdst = dst;
++
++ char fullname[256];
++ char *type;
++ XrmValue ret;
++
++ snprintf(fullname, sizeof(fullname), "%s.%s", "dwm", name);
++ fullname[sizeof(fullname) - 1] = '\0';
++
++ XrmGetResource(db, fullname, "*", &type, &ret);
++ if (!(ret.addr == NULL || strncmp("String", type, 64)))
++ {
++ switch (rtype) {
++ case STRING:
++ strcpy(sdst, ret.addr);
++ break;
++ case INTEGER:
++ *idst = strtoul(ret.addr, NULL, 10);
++ break;
++ case FLOAT:
++ *fdst = strtof(ret.addr, NULL);
++ break;
++ }
++ }
++}
++
++void
++load_xresources(void)
++{
++ Display *display;
++ char *resm;
++ XrmDatabase db;
++ ResourcePref *p;
++
++ display = XOpenDisplay(NULL);
++ resm = XResourceManagerString(display);
++ if (!resm)
++ return;
++
++ db = XrmGetStringDatabase(resm);
++ for (p = resources; p < resources + LENGTH(resources); p++)
++ resource_load(db, p->name, p->type, p->dst);
++ XCloseDisplay(display);
++}
++
+ int
+ main(int argc, char *argv[])
+ {
+@@ -2139,6 +2209,8 @@ main(int argc, char *argv[])
+ if (!(dpy = XOpenDisplay(NULL)))
+ die("dwm: cannot open display");
+ checkotherwm();
++ XrmInitialize();
++ load_xresources();
+ setup();
+ #ifdef __OpenBSD__
+ if (pledge("stdio rpath proc exec", NULL) == -1)
+--
+2.33.0
+
diff --git a/dwm.c b/dwm.c
index a96f33c..4c1efb3 100644
--- a/dwm.c
+++ b/dwm.c
@@ -36,10 +36,12 @@
#include <X11/Xlib.h>
#include <X11/Xproto.h>
#include <X11/Xutil.h>
+#include <X11/Xresource.h>
#ifdef XINERAMA
#include <X11/extensions/Xinerama.h>
#endif /* XINERAMA */
#include <X11/Xft/Xft.h>
+#include <fribidi.h>
#include "drw.h"
#include "util.h"
@@ -47,8 +49,8 @@
/* 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 INTERSECT(x,y,w,h,m) (MAX(0, MIN((x)+(w),(m)->mx+(m)->mw) - MAX((x),(m)->mx)) \
+ * MAX(0, MIN((y)+(h),(m)->my+(m)->mh) - MAX((y),(m)->my)))
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
#define LENGTH(X) (sizeof X / sizeof X[0])
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
@@ -116,7 +118,8 @@ struct Monitor {
float mfact;
int nmaster;
int num;
- int by; /* bar geometry */
+ int by, bh; /* bar geometry */
+ int tx, tw; /* bar tray geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
@@ -129,6 +132,7 @@ struct Monitor {
Client *stack;
Monitor *next;
Window barwin;
+ Window traywin;
const Layout *lt[2];
};
@@ -141,6 +145,19 @@ typedef struct {
int monitor;
} Rule;
+/* Xresources preferences */
+enum resource_type {
+ STRING = 0,
+ INTEGER = 1,
+ FLOAT = 2
+};
+
+typedef struct {
+ char *name;
+ enum resource_type type;
+ void *dst;
+} ResourcePref;
+
/* function declarations */
static void applyrules(Client *c);
static int applysizehints(Client *c, int *x, int *y, int *w, int *h, int interact);
@@ -179,6 +196,8 @@ 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 managealtbar(Window win, XWindowAttributes *wa);
+static void managetray(Window win, XWindowAttributes *wa);
static void mappingnotify(XEvent *e);
static void maprequest(XEvent *e);
static void monocle(Monitor *m);
@@ -195,6 +214,7 @@ static void resizemouse(const Arg *arg);
static void restack(Monitor *m);
static void run(void);
static void scan(void);
+static void scantray(void);
static int sendevent(Client *c, Atom proto);
static void sendmon(Client *c, Monitor *m);
static void setclientstate(Client *c, long state);
@@ -207,6 +227,7 @@ static void seturgent(Client *c, int urg);
static void showhide(Client *c);
static void sigchld(int unused);
static void spawn(const Arg *arg);
+static void spawnbar();
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
static void tile(Monitor *);
@@ -216,6 +237,8 @@ static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unfocus(Client *c, int setfocus);
static void unmanage(Client *c, int destroyed);
+static void unmanagealtbar(Window w);
+static void unmanagetray(Window w);
static void unmapnotify(XEvent *e);
static void updatebarpos(Monitor *m);
static void updatebars(void);
@@ -230,14 +253,18 @@ static void updatewmhints(Client *c);
static void view(const Arg *arg);
static Client *wintoclient(Window w);
static Monitor *wintomon(Window w);
+static int wmclasscontains(Window win, const char *class, const char *name);
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);
+static void load_xresources(void);
+static void resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst);
/* variables */
static const char broken[] = "broken";
static char stext[256];
+static char fribidi_text[BUFSIZ] = "";
static int screen;
static int sw, sh; /* X display screen geometry width, height */
static int bh, blw = 0; /* bar geometry */
@@ -276,6 +303,26 @@ static Window root, wmcheckwin;
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
/* function implementations */
+static void
+apply_fribidi(char const * str)
+{
+ FriBidiStrIndex len = strlen(str);
+ FriBidiChar logical[BUFSIZ];
+ FriBidiChar visual[BUFSIZ];
+ FriBidiParType base = FRIBIDI_PAR_ON;
+ FriBidiCharSet charset;
+ fribidi_boolean result;
+
+ fribidi_text[0] = 0;
+ if (len>0)
+ {
+ charset = fribidi_parse_charset("UTF-8");
+ len = fribidi_charset_to_unicode(charset, str, len, logical);
+ result = fribidi_log2vis(logical, len, &base, visual, NULL, NULL, NULL);
+ len = fribidi_unicode_to_charset(charset, visual, len, fribidi_text);
+ }
+}
+
void
applyrules(Client *c)
{
@@ -505,8 +552,10 @@ cleanupmon(Monitor *mon)
for (m = mons; m && m->next != mon; m = m->next);
m->next = mon->next;
}
- XUnmapWindow(dpy, mon->barwin);
- XDestroyWindow(dpy, mon->barwin);
+ if (!usealtbar) {
+ XUnmapWindow(dpy, mon->barwin);
+ XDestroyWindow(dpy, mon->barwin);
+ }
free(mon);
}
@@ -568,7 +617,7 @@ configurenotify(XEvent *e)
for (c = m->clients; c; c = c->next)
if (c->isfullscreen)
resizeclient(c, m->mx, m->my, m->mw, m->mh);
- XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, bh);
+ XMoveResizeWindow(dpy, m->barwin, m->wx, m->by, m->ww, m->bh);
}
focus(NULL);
arrange(NULL);
@@ -639,6 +688,7 @@ createmon(void)
m->nmaster = nmaster;
m->showbar = showbar;
m->topbar = topbar;
+ m->bh = bh;
m->lt[0] = &layouts[0];
m->lt[1] = &layouts[1 % LENGTH(layouts)];
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
@@ -649,10 +699,15 @@ void
destroynotify(XEvent *e)
{
Client *c;
+ Monitor *m;
XDestroyWindowEvent *ev = &e->xdestroywindow;
if ((c = wintoclient(ev->window)))
unmanage(c, 1);
+ else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
+ unmanagealtbar(ev->window);
+ else if (m->traywin == ev->window)
+ unmanagetray(ev->window);
}
void
@@ -696,6 +751,9 @@ dirtomon(int dir)
void
drawbar(Monitor *m)
{
+ if (usealtbar)
+ return;
+
int x, w, tw = 0;
int boxs = drw->fonts->h / 9;
int boxw = drw->fonts->h / 6 + 2;
@@ -708,8 +766,9 @@ drawbar(Monitor *m)
/* draw status first so it can be overdrawn by tags later */
if (m == selmon) { /* status is only drawn on selected monitor */
drw_setscheme(drw, scheme[SchemeNorm]);
- tw = TEXTW(stext) - lrpad + 2; /* 2px right padding */
- drw_text(drw, m->ww - tw, 0, tw, bh, 0, stext, 0);
+ apply_fribidi(stext);
+ tw = TEXTW(fribidi_text) - lrpad + 2; /* 2px right padding */
+ drw_text(drw, m->ww - tw, 0, tw, bh, 0, fribidi_text, 0);
}
for (c = m->clients; c; c = c->next) {
@@ -719,23 +778,26 @@ drawbar(Monitor *m)
}
x = 0;
for (i = 0; i < LENGTH(tags); i++) {
- w = TEXTW(tags[i]);
+ apply_fribidi(tags[i]);
+ w = TEXTW(fribidi_text);
drw_setscheme(drw, scheme[m->tagset[m->seltags] & 1 << i ? SchemeSel : SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, tags[i], urg & 1 << i);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, urg & 1 << i);
if (occ & 1 << i)
drw_rect(drw, x + boxs, boxs, boxw, boxw,
m == selmon && selmon->sel && selmon->sel->tags & 1 << i,
urg & 1 << i);
x += w;
}
- w = blw = TEXTW(m->ltsymbol);
+ apply_fribidi(m->ltsymbol);
+ w = blw = TEXTW(fribidi_text);
drw_setscheme(drw, scheme[SchemeNorm]);
- x = drw_text(drw, x, 0, w, bh, lrpad / 2, m->ltsymbol, 0);
+ x = drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0);
if ((w = m->ww - tw - x) > bh) {
if (m->sel) {
drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
- drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
+ apply_fribidi(m->sel->name);
+ drw_text(drw, x, 0, w, bh, lrpad / 2, fribidi_text, 0);
if (m->sel->isfloating)
drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
} else {
@@ -1081,6 +1143,45 @@ manage(Window w, XWindowAttributes *wa)
}
void
+managealtbar(Window win, XWindowAttributes *wa)
+{
+ Monitor *m;
+ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
+ return;
+
+ m->barwin = win;
+ m->by = wa->y;
+ bh = m->bh = wa->height;
+ updatebarpos(m);
+ arrange(m);
+ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
+ XMapWindow(dpy, win);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &win, 1);
+}
+
+void
+managetray(Window win, XWindowAttributes *wa)
+{
+ Monitor *m;
+ if (!(m = recttomon(wa->x, wa->y, wa->width, wa->height)))
+ return;
+
+ m->traywin = win;
+ m->tx = wa->x;
+ m->tw = wa->width;
+ updatebarpos(m);
+ arrange(m);
+ XSelectInput(dpy, win, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
+ XMoveResizeWindow(dpy, win, wa->x, wa->y, wa->width, wa->height);
+ XMapWindow(dpy, win);
+ XChangeProperty(dpy, root, netatom[NetClientList], XA_WINDOW, 32, PropModeAppend,
+ (unsigned char *) &win, 1);
+}
+
+
+void
mappingnotify(XEvent *e)
{
XMappingEvent *ev = &e->xmapping;
@@ -1100,7 +1201,9 @@ maprequest(XEvent *e)
return;
if (wa.override_redirect)
return;
- if (!wintoclient(ev->window))
+ if (wmclasscontains(ev->window, altbarclass, ""))
+ managealtbar(ev->window, &wa);
+ else if (!wintoclient(ev->window))
manage(ev->window, &wa);
}
@@ -1396,7 +1499,9 @@ scan(void)
if (!XGetWindowAttributes(dpy, wins[i], &wa)
|| wa.override_redirect || XGetTransientForHint(dpy, wins[i], &d1))
continue;
- if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
+ if (wmclasscontains(wins[i], altbarclass, ""))
+ managealtbar(wins[i], &wa);
+ else if (wa.map_state == IsViewable || getstate(wins[i]) == IconicState)
manage(wins[i], &wa);
}
for (i = 0; i < num; i++) { /* now the transients */
@@ -1412,6 +1517,29 @@ scan(void)
}
void
+scantray(void)
+{
+ unsigned int num;
+ Window d1, d2, *wins = NULL;
+ XWindowAttributes wa;
+
+ if (XQueryTree(dpy, root, &d1, &d2, &wins, &num)) {
+ for (unsigned int i = 0; i < num; i++) {
+ if (wmclasscontains(wins[i], altbarclass, alttrayname)) {
+ if (!XGetWindowAttributes(dpy, wins[i], &wa))
+ break;
+ managetray(wins[i], &wa);
+ }
+ }
+ }
+
+ if (wins)
+ XFree(wins);
+}
+
+
+
+void
sendmon(Client *c, Monitor *m)
{
if (c->mon == m)
@@ -1549,7 +1677,7 @@ setup(void)
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
die("no fonts could be loaded.");
lrpad = drw->fonts->h;
- bh = drw->fonts->h + 2;
+ bh = usealtbar ? 0 : drw->fonts->h + 2;
updategeom();
/* init atoms */
utf8string = XInternAtom(dpy, "UTF8_STRING", False);
@@ -1598,6 +1726,7 @@ setup(void)
XSelectInput(dpy, root, wa.event_mask);
grabkeys();
focus(NULL);
+ spawnbar();
}
@@ -1657,6 +1786,13 @@ spawn(const Arg *arg)
}
void
+spawnbar()
+{
+ if (*altbarcmd)
+ system(altbarcmd);
+}
+
+void
tag(const Arg *arg)
{
if (selmon->sel && arg->ui & TAGMASK) {
@@ -1705,9 +1841,18 @@ tile(Monitor *m)
void
togglebar(const Arg *arg)
{
+ /**
+ * Polybar tray does not raise maprequest event. It must be manually scanned
+ * for. Scanning it too early while the tray is being populated would give
+ * wrong dimensions.
+ */
+ if (!selmon->traywin)
+ scantray();
+
selmon->showbar = !selmon->showbar;
updatebarpos(selmon);
- XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
+ XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, selmon->bh);
+ XMoveResizeWindow(dpy, selmon->traywin, selmon->tx, selmon->by, selmon->tw, selmon->bh);
arrange(selmon);
}
@@ -1791,9 +1936,40 @@ unmanage(Client *c, int destroyed)
}
void
+unmanagealtbar(Window w)
+{
+ Monitor *m = wintomon(w);
+
+ if (!m)
+ return;
+
+ m->barwin = 0;
+ m->by = 0;
+ m->bh = 0;
+ updatebarpos(m);
+ arrange(m);
+}
+
+void
+unmanagetray(Window w)
+{
+ Monitor *m = wintomon(w);
+
+ if (!m)
+ return;
+
+ m->traywin = 0;
+ m->tx = 0;
+ m->tw = 0;
+ updatebarpos(m);
+ arrange(m);
+}
+
+void
unmapnotify(XEvent *e)
{
Client *c;
+ Monitor *m;
XUnmapEvent *ev = &e->xunmap;
if ((c = wintoclient(ev->window))) {
@@ -1801,12 +1977,18 @@ unmapnotify(XEvent *e)
setclientstate(c, WithdrawnState);
else
unmanage(c, 0);
- }
+ } else if ((m = wintomon(ev->window)) && m->barwin == ev->window)
+ unmanagealtbar(ev->window);
+ else if (m->traywin == ev->window)
+ unmanagetray(ev->window);
}
void
updatebars(void)
{
+ if (usealtbar)
+ return;
+
Monitor *m;
XSetWindowAttributes wa = {
.override_redirect = True,
@@ -1832,11 +2014,11 @@ updatebarpos(Monitor *m)
m->wy = m->my;
m->wh = m->mh;
if (m->showbar) {
- m->wh -= bh;
+ m->wh -= m->bh;
m->by = m->topbar ? m->wy : m->wy + m->wh;
- m->wy = m->topbar ? m->wy + bh : m->wy;
+ m->wy = m->topbar ? m->wy + m->bh : m->wy;
} else
- m->by = -bh;
+ m->by = -m->bh;
}
void
@@ -2073,13 +2255,35 @@ wintomon(Window w)
if (w == root && getrootptr(&x, &y))
return recttomon(x, y, 1, 1);
for (m = mons; m; m = m->next)
- if (w == m->barwin)
+ if (w == m->barwin || w == m->traywin)
return m;
if ((c = wintoclient(w)))
return c->mon;
return selmon;
}
+int
+wmclasscontains(Window win, const char *class, const char *name)
+{
+ XClassHint ch = { NULL, NULL };
+ int res = 1;
+
+ if (XGetClassHint(dpy, win, &ch)) {
+ if (ch.res_name && strstr(ch.res_name, name) == NULL)
+ res = 0;
+ if (ch.res_class && strstr(ch.res_class, class) == NULL)
+ res = 0;
+ } else
+ res = 0;
+
+ if (ch.res_class)
+ XFree(ch.res_class);
+ if (ch.res_name)
+ XFree(ch.res_name);
+
+ return res;
+}
+
/* 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. */
@@ -2130,6 +2334,60 @@ zoom(const Arg *arg)
pop(c);
}
+void
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
+{
+ char *sdst = NULL;
+ int *idst = NULL;
+ float *fdst = NULL;
+
+ sdst = dst;
+ idst = dst;
+ fdst = dst;
+
+ char fullname[256];
+ char *type;
+ XrmValue ret;
+
+ snprintf(fullname, sizeof(fullname), "%s.%s", "dwm", name);
+ fullname[sizeof(fullname) - 1] = '\0';
+
+ XrmGetResource(db, fullname, "*", &type, &ret);
+ if (!(ret.addr == NULL || strncmp("String", type, 64)))
+ {
+ switch (rtype) {
+ case STRING:
+ strcpy(sdst, ret.addr);
+ break;
+ case INTEGER:
+ *idst = strtoul(ret.addr, NULL, 10);
+ break;
+ case FLOAT:
+ *fdst = strtof(ret.addr, NULL);
+ break;
+ }
+ }
+}
+
+void
+load_xresources(void)
+{
+ Display *display;
+ char *resm;
+ XrmDatabase db;
+ ResourcePref *p;
+
+ display = XOpenDisplay(NULL);
+ resm = XResourceManagerString(display);
+ if (!resm)
+ return;
+
+ db = XrmGetStringDatabase(resm);
+ for (p = resources; p < resources + LENGTH(resources); p++)
+ resource_load(db, p->name, p->type, p->dst);
+ XCloseDisplay(display);
+}
+
int
main(int argc, char *argv[])
{
@@ -2142,6 +2400,8 @@ main(int argc, char *argv[])
if (!(dpy = XOpenDisplay(NULL)))
die("dwm: cannot open display");
checkotherwm();
+ XrmInitialize();
+ load_xresources();
setup();
#ifdef __OpenBSD__
if (pledge("stdio rpath proc exec", NULL) == -1)