aboutsummaryrefslogtreecommitdiffstats
path: root/dwm.c
diff options
context:
space:
mode:
authorterminaldweller <thabogre@gmail.com>2022-07-04 18:44:40 +0000
committerterminaldweller <thabogre@gmail.com>2022-07-04 18:44:40 +0000
commitd7f50d26e3207136234adfae6965dcee749674fc (patch)
tree77db6903b92639bbd061dcbce16152ab48665fb0 /dwm.c
parentfirst commit (diff)
downloaddwm-main.tar.gz
dwm-main.zip
added 3 patchesHEADmain
Diffstat (limited to '')
-rw-r--r--dwm.c304
1 files changed, 282 insertions, 22 deletions
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)