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);
Received on Mon Sep 24 2007 - 15:30:26 UTC
This archive was generated by hypermail 2.2.0 : Sun Jul 13 2008 - 14:55:14 UTC