Re: [dwm] [PATCH] An experiment with X resources

From: Anselm R. Garbe <arg_AT_suckless.org>
Date: Mon, 24 Sep 2007 19:39:08 +0200

Hi Chris,

I'm surprised that this only adds a minor amount of lines, so I
really consider applying your patch to mainstream dwm. Are there
any complains?

The only questionable issue I don't like is the strsep(3) use,
because of portability concerns.

Regards,
        Anselm

On Mon, Sep 24, 2007 at 02:30:23PM +0100, Chris Webb wrote:
> This morning I've been thinking about run time configuration of dwm.
>
> I've never especially liked the compile-time rules table in config.h. The
> fact that one or two programs I use happen to be broken and need a rule
> with isfloating = 1 doesn't seem like something that the dwm binary
> should be cluttered with. Clearly this is a matter of personal taste and
> your mileage will probably vary, but it definitely grates for me. I also
> have a couple of different screens and I'd like to be able to reconfigure
> fonts and colours (depending on the display dwm is managing) without
> keeping multiple dwm binaries in my home directory.
>
> As an experiment, I've added support for customisation with X resources
> in a branch of my own tree. To avoid growing the code too much, I
> completely replaced the hard-coded rules table with a dynamic one
> populated from X resources, but all other settings use config.h values as
> defaults. Key bindings remain a matter for config.h. As far as I can see,
> configuring these at runtime would introduce a big, ugly symbol table
> into dwm for little or no gain.
>
> Doing all this grows dwm.c less than I was originally expecting, as can
> be seen from the patch. Most of the extra code is involved with
> constructing the tag and rule lists rather than just to add simpler
> config options like fonts and colours.
>
> I've ported my patch back to upstream dwm (hg tip) and attached it at the
> end of this message in case anyone else on the list is interested in
> experimenting along the same lines. A sample .Xresources file to merge
> (use xrdb -merge/-load) might be:
>
> Dwm.bar: top
> Dwm.font: -*-terminus-medium-r-*-*-12-*-*-*-*-*-iso10646-*
>
> Dwm.normal.border: #cccccc
> Dwm.normal.background: #ffffff
> Dwm.normal.background: #000000
> Dwm.selected.border: #ff0000
> Dwm.selected.background: #0000ff
> Dwm.selected.foreground: #ffffff
>
> Dwm.tags: 1 2 3 4 5 6 7 8 9
> Dwm.rules: scratchpad browser
>
> Dwm.properties.scratchpad: URxvt:scratch
> Dwm.floating.scratchpad: True
>
> Dwm.properties.browser: Opera
> Dwm.tags.browser: 2
>
> Cheers,
>
> Chris.
>
>
> diff -r 92c19c929a59 config.def.h
> --- a/config.def.h Sun Sep 23 18:50:04 2007 +0200
> +++ b/config.def.h Mon Sep 24 14:28:26 2007 +0100
> @@ -1,4 +1,8 @@
> /* See LICENSE file for copyright and license details. */
> +
> +/* resources */
> +#define RESNAME "dwm"
> +#define RESCLASS "Dwm"
>
> /* appearance */
> #define BARPOS BarTop /* BarBot, BarOff */
> @@ -12,14 +16,7 @@
> #define SELFGCOLOR "#ffffff"
>
> /* tagging */
> -const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "www", NULL };
> -Rule rules[] = {
> - /* class:instance:title regex tags regex isfloating */
> - { "Firefox", "www", False },
> - { "Gimp", NULL, True },
> - { "MPlayer", NULL, True },
> - { "Acroread", NULL, True },
> -};
> +#define TAGS "1 2 3 4 5 6 7 8 9"
>
> /* layout(s) */
> #define ISTILE isarrange(tile) /* || isarrange(<custom>) */
> diff -r 92c19c929a59 dwm.c
> --- a/dwm.c Sun Sep 23 18:50:04 2007 +0200
> +++ b/dwm.c Mon Sep 24 14:28:26 2007 +0100
> @@ -40,6 +40,7 @@
> #include <X11/Xatom.h>
> #include <X11/Xlib.h>
> #include <X11/Xproto.h>
> +#include <X11/Xresource.h>
> #include <X11/Xutil.h>
>
> /* macros */
> @@ -132,6 +133,8 @@ void *emallocz(unsigned int size);
> void *emallocz(unsigned int size);
> void enternotify(XEvent *e);
> void eprint(const char *errstr, ...);
> +void *erealloc(void *res, unsigned int size);
> +char *estrdup(const char *s);
> void expose(XEvent *e);
> void floating(void); /* default floating layout */
> void focus(Client *c);
> @@ -139,7 +142,10 @@ void focusprev(const char *arg);
> void focusprev(const char *arg);
> Client *getclient(Window w);
> unsigned long getcolor(const char *colstr);
> +char *getresource(const char *resource, char *defval);
> +void getrules(void);
> long getstate(Window w);
> +void gettags(void);
> Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
> void grabbuttons(Client *c, Bool focused);
> unsigned int idxoftag(const char *tag);
> @@ -190,11 +196,11 @@ void zoom(const char *arg);
> void zoom(const char *arg);
>
> /* variables */
> -char stext[256];
> +char stext[256], **tags;
> double mwfact;
> int screen, sx, sy, sw, sh, wax, way, waw, wah;
> int (*xerrorxlib)(Display *, XErrorEvent *);
> -unsigned int bh, bpos, ntags;
> +unsigned int bh, bpos, ntags = 0;
> unsigned int blw = 0;
> unsigned int ltidx = 0; /* default */
> unsigned int nlayouts = 0;
> @@ -226,7 +232,9 @@ Display *dpy;
> Display *dpy;
> DC dc = {0};
> Window barwin, root;
> +Rule *rules;
> Regs *regs = NULL;
> +XrmDatabase xrdb;
>
> /* configuration, allows nested code to access above variables */
> #include "config.h"
> @@ -402,7 +410,6 @@ compileregs(void) {
>
> if(regs)
> return;
> - nrules = sizeof rules / sizeof rules[0];
> regs = emallocz(nrules * sizeof(Regs));
> for(i = 0; i < nrules; i++) {
> if(rules[i].prop) {
> @@ -638,6 +645,13 @@ emallocz(unsigned int size) {
> return res;
> }
>
> +void *
> +erealloc(void *res, unsigned int size) {
> + if (!(res = res ? realloc(res, size) : malloc(size)))
> + eprint("fatal: could not realloc() %u bytes\n", size);
> + return res;
> +}
> +
> void
> enternotify(XEvent *e) {
> Client *c;
> @@ -661,6 +675,15 @@ eprint(const char *errstr, ...) {
> vfprintf(stderr, errstr, ap);
> va_end(ap);
> exit(EXIT_FAILURE);
> +}
> +
> +char *
> +estrdup(const char *s) {
> + char *t;
> + t = strdup(s);
> + if (!t)
> + eprint("fatal: strdup failed\n");
> + return t;
> }
>
> void
> @@ -755,6 +778,53 @@ getcolor(const char *colstr) {
> if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
> eprint("error, cannot allocate color '%s'\n", colstr);
> return color.pixel;
> +}
> +
> +char *
> +getresource(const char *resource, char *defval) {
> + static char name[256], class[256], *type;
> + XrmValue value;
> + snprintf(name, sizeof(name), "%s.%s", RESNAME, resource);
> + snprintf(class, sizeof(class), "%s.%s", RESCLASS, resource);
> + XrmGetResource(xrdb, name, class, &type, &value);
> + if(value.addr)
> + return value.addr;
> + return defval;
> +}
> +
> +void
> +getrules(void) {
> + char *line, *p, *rule, *prop, *tags, *floating;
> + static char name[256], class[256], *type;
> + XrmValue value;
> + line = p = estrdup(getresource("rules", ""));
> + while(rule = strsep(&p, " \t\n")) {
> + if(!rule[0])
> + continue;
> + snprintf(name, sizeof(name), "%s.properties.%s", RESNAME, rule);
> + snprintf(class, sizeof(class), "%s.properties.%s", RESCLASS, rule);
> + XrmGetResource(xrdb, name, class, &type, &value);
> + if (!value.addr || !value.addr[0])
> + continue;
> + rules = erealloc(rules, sizeof(Rule) * (++nrules));
> + rules[nrules - 1].prop = estrdup(value.addr);
> + snprintf(name, sizeof(name), "%s.tags.%s", RESNAME, rule);
> + snprintf(class, sizeof(class), "%s.tags.%s", RESCLASS, rule);
> + XrmGetResource(xrdb, name, class, &type, &value);
> + if (value.addr && value.addr[0] && strcasecmp(value.addr, "null"))
> + rules[nrules - 1].tags = estrdup(value.addr);
> + else
> + rules[nrules - 1].tags = NULL;
> + snprintf(name, sizeof(name), "%s.floating.%s", RESNAME, rule);
> + snprintf(class, sizeof(class), "%s.floating.%s", RESCLASS, rule);
> + XrmGetResource(xrdb, name, class, &type, &value);
> + rules[nrules - 1].isfloating = (value.addr && value.addr[0]
> + && strcasecmp(value.addr, "false")
> + && strcasecmp(value.addr, "no")
> + && strcasecmp(value.addr, "off")
> + && strcmp(value.addr, "0"));
> + }
> + free(line);
> }
>
> long
> @@ -773,6 +843,20 @@ getstate(Window w) {
> result = *p;
> XFree(p);
> return result;
> +}
> +
> +void
> +gettags(void) {
> + char *line, *tag;
> + line = estrdup(getresource("tags", TAGS));
> + while(tag = strsep(&line, " \t\n")) {
> + if(!tag[0])
> + continue;
> + tags = erealloc(tags, sizeof(char *) * ++ntags);
> + tags[ntags - 1] = tag;
> + }
> + if (ntags == 0)
> + eprint("dwm: no tags defined\n");
> }
>
> Bool
> @@ -1420,6 +1504,7 @@ setup(void) {
> setup(void) {
> int d;
> unsigned int i, j, mask;
> + char *s;
> Window w;
> XModifierKeymap *modmap;
> XSetWindowAttributes wa;
> @@ -1461,23 +1546,32 @@ setup(void) {
> XChangeWindowAttributes(dpy, root, CWEventMask | CWCursor, &wa);
> XSelectInput(dpy, root, wa.event_mask);
>
> + /* init resource database */
> + XrmInitialize();
> + s = XResourceManagerString(dpy);
> + xrdb = XrmGetStringDatabase(s);
> + free(s);
> +
> + /* init rules */
> + getrules();
> +
> + /* init tags */
> + gettags();
> + compileregs();
> + seltags = emallocz(sizeof(Bool) * ntags);
> + seltags[0] = True;
> +
> /* grab keys */
> keypress(NULL);
>
> - /* init tags */
> - compileregs();
> - for(ntags = 0; tags[ntags]; ntags++);
> - seltags = emallocz(sizeof(Bool) * ntags);
> - seltags[0] = True;
> -
> /* init appearance */
> - dc.norm[ColBorder] = getcolor(NORMBORDERCOLOR);
> - dc.norm[ColBG] = getcolor(NORMBGCOLOR);
> - dc.norm[ColFG] = getcolor(NORMFGCOLOR);
> - dc.sel[ColBorder] = getcolor(SELBORDERCOLOR);
> - dc.sel[ColBG] = getcolor(SELBGCOLOR);
> - dc.sel[ColFG] = getcolor(SELFGCOLOR);
> - initfont(FONT);
> + dc.norm[ColBorder] = getcolor(getresource("normal.border", NORMBORDERCOLOR));
> + dc.norm[ColBG] = getcolor(getresource("normal.background", NORMBGCOLOR));
> + dc.norm[ColFG] = getcolor(getresource("normal.foreground", NORMFGCOLOR));
> + dc.sel[ColBorder] = getcolor(getresource("selected.border", SELBORDERCOLOR));
> + dc.sel[ColBG] = getcolor(getresource("selected.background", SELBGCOLOR));
> + dc.sel[ColFG] = getcolor(getresource("selected.foreground", SELFGCOLOR));
> + initfont(getresource("font", FONT));
> dc.h = bh = dc.font.height + 2;
>
> /* init layouts */
> @@ -1490,7 +1584,15 @@ setup(void) {
> }
>
> /* init bar */
> - bpos = BARPOS;
> + s = getresource("bar", NULL);
> + if(!s || !s[0] || strcasecmp(s, "default"))
> + bpos = BARPOS;
> + else if(strcasecmp(s, "top") == 0)
> + bpos = BarTop;
> + else if(strcasecmp(s, "bottom") == 0)
> + bpos = BarBot;
> + else
> + bpos = BarOff;
> wa.override_redirect = 1;
> wa.background_pixmap = ParentRelative;
> wa.event_mask = ButtonPressMask | ExposureMask;
> @@ -1506,6 +1608,9 @@ setup(void) {
> XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
> if(!dc.font.set)
> XSetFont(dpy, dc.gc, dc.font.xfont->fid);
> +
> + /* free resource database */
> + XrmDestroyDatabase(xrdb);
>
> /* multihead support */
> selscreen = XQueryPointer(dpy, root, &w, &w, &d, &d, &d, &d, &mask);
>

-- 
 Anselm R. Garbe >< http://www.suckless.org/ >< GPG key: 0D73F361
Received on Mon Sep 24 2007 - 19:39:08 UTC

This archive was generated by hypermail 2.2.0 : Sun Jul 13 2008 - 14:55:16 UTC