JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Fix indentation when defining variables.
[spectrwm.git] / scrotwm.c
index 65cd807..d2534d9 100644 (file)
--- a/scrotwm.c
+++ b/scrotwm.c
@@ -124,6 +124,7 @@ static const char   *buildstr = SCROTWM_VERSION;
 #define SWM_D_SPAWN            0x0800
 #define SWM_D_EVENTQ           0x1000
 #define SWM_D_CONF             0x2000
+#define SWM_D_BAR              0x4000
 
 u_int32_t              swm_debug = 0
                            | SWM_D_MISC
@@ -140,6 +141,7 @@ u_int32_t           swm_debug = 0
                            | SWM_D_SPAWN
                            | SWM_D_EVENTQ
                            | SWM_D_CONF
+                           | SWM_D_BAR
                            ;
 #else
 #define DPRINTF(x...)
@@ -214,6 +216,7 @@ struct search_window {
        TAILQ_ENTRY(search_window)      entry;
        int                             idx;
        struct ws_win                   *win;
+       GC                              gc;
        Window                          indicator;
 };
 TAILQ_HEAD(search_winlist, search_window);
@@ -230,16 +233,27 @@ enum {
 };
 
 /* dialog windows */
-double                 dialog_ratio = .6;
+double                 dialog_ratio = 0.6;
 /* status bar */
 #define SWM_BAR_MAX            (256)
 #define SWM_BAR_JUSTIFY_LEFT   (0)
 #define SWM_BAR_JUSTIFY_CENTER (1)
 #define SWM_BAR_JUSTIFY_RIGHT  (2)
 #define SWM_BAR_OFFSET         (4)
+#define SWM_BAR_FONTS          "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*," \
+                               "-*-profont-*-*-*-*-*-*-*-*-*-*-*-*,"       \
+                               "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*,"    \
+                               "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*"
+
+#ifdef X_HAVE_UTF8_STRING
+#define DRAWSTRING(x...)       Xutf8DrawString(x)
+#else
+#define DRAWSTRING(x...)       XmbDrawString(x)
+#endif
+
 char                   *bar_argv[] = { NULL, NULL };
 int                    bar_pipe[2];
-char                   bar_ext[SWM_BAR_MAX];
+unsigned char          bar_ext[SWM_BAR_MAX];
 char                   bar_vertext[SWM_BAR_MAX];
 int                    bar_version = 0;
 sig_atomic_t           bar_alarm = 0;
@@ -264,12 +278,10 @@ int                       disable_border = 0;
 int                    border_width = 1;
 int                    verbose_layout = 0;
 pid_t                  bar_pid;
-GC                     bar_gc;
-XGCValues              bar_gcv;
-int                    bar_fidx = 0;
-XFontStruct            *bar_fs;
-char                   *bar_fonts[] = { NULL, NULL, NULL, NULL };/* XXX Make fully dynamic */
-char                   *spawn_term[] = { NULL, NULL };         /* XXX Make fully dynamic */
+XFontSet               bar_fs;
+XFontSetExtents                *bar_fs_extents;
+char                   *bar_fonts;
+char                   *spawn_term[] = { NULL, NULL }; /* XXX fully dynamic */
 struct passwd          *pwd;
 
 #define SWM_MENU_FN    (2)
@@ -424,6 +436,8 @@ struct swm_screen {
                unsigned long   color;
                char            *name;
        } c[SWM_S_COLOR_MAX];
+
+       GC                      bar_gc;
 };
 struct swm_screen      *screens;
 int                    num_screens;
@@ -535,9 +549,10 @@ struct ewmh_hint {
     {"_NET_WM_ACTION_CLOSE", None},
 };
 
-void   store_float_geom(struct ws_win *, struct swm_region *);
-int    floating_toggle_win(struct ws_win *);
-void   spawn_select(struct swm_region *, union arg *, char *, int *);
+void            store_float_geom(struct ws_win *, struct swm_region *);
+int             floating_toggle_win(struct ws_win *);
+void            spawn_select(struct swm_region *, union arg *, char *, int *);
+unsigned char  *get_win_name(Display *, Window, Atom, Atom, unsigned long *);
 
 int
 get_property(Window id, Atom atom, long count, Atom type,
@@ -1249,31 +1264,33 @@ socket_setnonblock(int fd)
 void
 bar_print(struct swm_region *r, char *s)
 {
-       int                     textwidth, x = 0;
-       size_t          len;
+       int                     x = 0;
+       size_t                  len;
+       XRectangle              ibox, lbox;
 
        XClearWindow(display, r->bar_window);
-       XSetForeground(display, bar_gc, r->s->c[SWM_S_COLOR_BAR_FONT].color);
 
        len = strlen(s);
-       textwidth = XTextWidth(bar_fs, s, len);
+       XmbTextExtents(bar_fs, s, len, &ibox, &lbox);
 
        switch (bar_justify) {
        case SWM_BAR_JUSTIFY_LEFT:
                x = SWM_BAR_OFFSET;
                break;
        case SWM_BAR_JUSTIFY_CENTER:
-               x = (WIDTH(r) - textwidth) / 2;
+               x = (WIDTH(r) - lbox.width) / 2;
                break;
        case SWM_BAR_JUSTIFY_RIGHT:
-               x = WIDTH(r) - textwidth - SWM_BAR_OFFSET;
+               x = WIDTH(r) - lbox.width - SWM_BAR_OFFSET;
                break;
        }
 
        if (x < SWM_BAR_OFFSET)
                x = SWM_BAR_OFFSET;
 
-       XDrawString(display, r->bar_window, bar_gc, x, bar_fs->ascent, s, len);
+       DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc,
+           x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 - 
+           lbox.y, s, len);
 }
 
 void
@@ -1287,7 +1304,7 @@ bar_extra_stop(void)
                kill(bar_pid, SIGTERM);
                bar_pid = 0;
        }
-       strlcpy(bar_ext, "", sizeof bar_ext);
+       strlcpy((char *)bar_ext, "", sizeof bar_ext);
        bar_extra = 0;
 }
 
@@ -1316,21 +1333,28 @@ bar_class_name(char *s, ssize_t sz, struct ws_win *cur_focus)
                strlcat(s, "    ", sz);
        }
 out:
-       if (xch)
+       if (xch) {
+               XFree(xch->res_name);
+               XFree(xch->res_class);
                XFree(xch);
+       }
 }
 
 void
 bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus)
 {
-       char                    *title;
+       unsigned char           *title;
+       unsigned long           len;
 
        if (window_name_enabled && cur_focus != NULL) {
-               XFetchName(display, cur_focus->id, &title);
-               if (title) {
+               if ((title = get_win_name(display, cur_focus->id, a_netwmname,
+                   a_utf8_string, &len)) != NULL) {
+                       DNPRINTF(SWM_D_BAR, "bar_window_name: title: %s\n",
+                           title);
+
                        if (cur_focus->floating)
                                strlcat(s, "(f) ", sz);
-                       strlcat(s, title, sz);
+                       strlcat(s, (char *)title, sz);
                        strlcat(s, " ", sz);
                        XFree(title);
                }
@@ -1385,7 +1409,7 @@ bar_update(void)
        size_t                  len;
        char                    ws[SWM_BAR_MAX];
        char                    s[SWM_BAR_MAX];
-       char                    cn[SWM_BAR_MAX];
+       unsigned char           cn[SWM_BAR_MAX];
        char                    loc[SWM_BAR_MAX];
        char                    *b, *stack = "";
 
@@ -1396,7 +1420,7 @@ bar_update(void)
                while ((b = fgetln(stdin, &len)) != NULL)
                        if (b && b[len - 1] == '\n') {
                                b[len - 1] = '\0';
-                               strlcpy(bar_ext, b, sizeof bar_ext);
+                               strlcpy((char *)bar_ext, b, sizeof bar_ext);
                        }
                if (b == NULL && errno != EAGAIN) {
                        fprintf(stderr, "bar_update: bar_extra failed: "
@@ -1404,7 +1428,7 @@ bar_update(void)
                        bar_extra_stop();
                }
        } else
-               strlcpy(bar_ext, "", sizeof bar_ext);
+               strlcpy((char *)bar_ext, "", sizeof bar_ext);
 
        if (clock_enabled == 0)
                strlcpy(s, "", sizeof s);
@@ -1418,12 +1442,14 @@ bar_update(void)
        for (i = 0; i < ScreenCount(display); i++) {
                x = 1;
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
-                       strlcpy(cn, "", sizeof cn);
+                       strlcpy((char *)cn, "", sizeof cn);
                        strlcpy(ws, "", sizeof ws);
                        if (r && r->ws) {
-                               bar_urgent(cn, sizeof cn);
-                               bar_class_name(cn, sizeof cn, r->ws->focus);
-                               bar_window_name(cn, sizeof cn, r->ws->focus);
+                               bar_urgent((char *)cn, sizeof cn);
+                               bar_class_name((char *)cn, sizeof cn,
+                                   r->ws->focus);
+                               bar_window_name((char *)cn, sizeof cn,
+                                   r->ws->focus);
                                if (r->ws->name)
                                        snprintf(ws, sizeof ws, "<%s>",
                                            r->ws->name);
@@ -1452,7 +1478,7 @@ bar_toggle(struct swm_region *r, union arg *args)
        struct swm_region       *tmpr;
        int                     i, sc = ScreenCount(display);
 
-       DNPRINTF(SWM_D_MISC, "bar_toggle\n");
+       DNPRINTF(SWM_D_BAR, "bar_toggle\n");
 
        if (bar_enabled)
                for (i = 0; i < sc; i++)
@@ -1522,27 +1548,48 @@ bar_refresh(void)
 void
 bar_setup(struct swm_region *r)
 {
+       char                    *default_string;
+       char                    **missing_charsets;
+       int                     num_missing_charsets = 0;
        int                     i, x, y;
 
        if (bar_fs) {
-               XFreeFont(display, bar_fs);
+               XFreeFontSet(display, bar_fs);
                bar_fs = NULL;
        }
 
-       for (i = 0; bar_fonts[i] != NULL; i++) {
-               bar_fs = XLoadQueryFont(display, bar_fonts[i]);
-               if (bar_fs) {
-                       bar_fidx = i;
-                       break;
-               }
+
+       DNPRINTF(SWM_D_BAR, "bar_setup: loading bar_fonts: %s\n", bar_fonts);
+
+       bar_fs = XCreateFontSet(display, bar_fonts, &missing_charsets,
+           &num_missing_charsets, &default_string);
+
+       if (num_missing_charsets > 0) {
+               warnx("Unable to load charset(s):");
+
+               for (i = 0; i < num_missing_charsets; ++i)
+                       warnx("%s", missing_charsets[i]);
+
+               XFreeStringList(missing_charsets);
+
+               if (strcmp(default_string, ""))
+                       warnx("Glyphs from those sets will be replaced "
+                           "by '%s'.", default_string);
+               else
+                       warnx("Glyphs from those sets won't be drawn.");
        }
-       if (bar_fonts[i] == NULL)
-               errx(1, "couldn't load font");
+
        if (bar_fs == NULL)
-               errx(1, "couldn't create font structure");
+               errx(1, "Error creating font set structure.");
+
+       bar_fs_extents = XExtentsOfFontSet(bar_fs);
 
-       bar_height = bar_fs->ascent + bar_fs->descent + 1 +
+       bar_height = bar_fs_extents->max_logical_extent.height +
            2 * bar_border_width;
+
+       if (bar_height < 1)
+               bar_height = 1;
+
        x = X(r);
        y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
 
@@ -1551,12 +1598,10 @@ bar_setup(struct swm_region *r)
            bar_height - 2 * bar_border_width,
            bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
            r->s->c[SWM_S_COLOR_BAR].color);
-       bar_gc = XCreateGC(display, r->bar_window, 0, &bar_gcv);
-       XSetFont(display, bar_gc, bar_fs->fid);
        XSelectInput(display, r->bar_window, VisibilityChangeMask);
        if (bar_enabled)
                XMapRaised(display, r->bar_window);
-       DNPRINTF(SWM_D_MISC, "bar_setup: bar_window: 0x%lx\n", r->bar_window);
+       DNPRINTF(SWM_D_BAR, "bar_setup: bar_window: 0x%lx\n", r->bar_window);
 
        if (signal(SIGALRM, bar_signal) == SIG_ERR)
                err(1, "could not install bar_signal");
@@ -1643,33 +1688,31 @@ config_win(struct ws_win *win, XConfigureRequestEvent  *ev)
        if (win == NULL)
                return;
 
+       /* send notification of unchanged state. */
+       ce.type = ConfigureNotify;
+       ce.x = X(win);
+       ce.y = Y(win);
+       ce.width = WIDTH(win);
+       ce.height = HEIGHT(win);
+       ce.override_redirect = False;
 
        if (ev == NULL) {
                /* EWMH */
-               ce.type = ConfigureNotify;
                ce.display = display;
                ce.event = win->id;
                ce.window = win->id;
-               ce.x = X(win);
-               ce.y = Y(win);
-               ce.width = WIDTH(win);
-               ce.height = HEIGHT(win);
                ce.border_width = border_width;
                ce.above = None;
-               ce.override_redirect = False;
        } else {
                /* normal */
-               ce.type = ConfigureNotify;
                ce.display = ev->display;
                ce.event = ev->window;
                ce.window = ev->window;
-               ce.x = ev->x;
-               ce.y = ev->y;
-               ce.width = ev->width;
-               ce.height = ev->height;
+               /* adjust x and y for requested border_width. */
+               ce.x += border_width - ev->border_width;
+               ce.y += border_width - ev->border_width;
                ce.border_width = ev->border_width;
                ce.above = ev->above;
-               ce.override_redirect = False;
        }
 
        DNPRINTF(SWM_D_MISC, "config_win: ewmh: %s, window: 0x%lx, (x,y) w x h: "
@@ -3363,6 +3406,7 @@ search_win_cleanup(void)
 
        while ((sw = TAILQ_FIRST(&search_wl)) != NULL) {
                XDestroyWindow(display, sw->indicator);
+               XFreeGC(display, sw->gc);
                TAILQ_REMOVE(&search_wl, sw, entry);
                free(sw);
        }
@@ -3374,13 +3418,12 @@ search_win(struct swm_region *r, union arg *args)
        struct ws_win           *win = NULL;
        struct search_window    *sw = NULL;
        Window                  w;
-       GC                      gc;
        XGCValues               gcv;
        int                     i;
        char                    s[8];
        FILE                    *lfile;
        size_t                  len;
-       int                     textwidth;
+       XRectangle              ibox, lbox;
 
        DNPRINTF(SWM_D_MISC, "search_win\n");
 
@@ -3412,23 +3455,25 @@ search_win(struct swm_region *r, union arg *args)
 
                snprintf(s, sizeof s, "%d", i);
                len = strlen(s);
-               textwidth = XTextWidth(bar_fs, s, len);
+
+               XmbTextExtents(bar_fs, s, len, &ibox, &lbox);
 
                w = XCreateSimpleWindow(display,
-                   win->id, 0, 0, textwidth + 12,
-                   bar_fs->ascent + bar_fs->descent + 4, 1,
+                   win->id, 0, 0,lbox.width + 4,
+                   bar_fs_extents->max_logical_extent.height, 1,
                    r->s->c[SWM_S_COLOR_UNFOCUS].color,
                    r->s->c[SWM_S_COLOR_FOCUS].color);
 
                sw->indicator = w;
                TAILQ_INSERT_TAIL(&search_wl, sw, entry);
 
-               gc = XCreateGC(display, w, 0, &gcv);
-               XSetFont(display, gc, bar_fs->fid);
+               sw->gc = XCreateGC(display, w, 0, &gcv);
                XMapRaised(display, w);
-               XSetForeground(display, gc, r->s->c[SWM_S_COLOR_BAR].color);
+               XSetForeground(display, sw->gc, r->s->c[SWM_S_COLOR_BAR].color);
 
-               XDrawString(display, w, gc, 6, bar_fs->ascent + 2, s, len);
+               DRAWSTRING(display, w, bar_fs, sw->gc, 2,
+                   (bar_fs_extents->max_logical_extent.height -
+                   lbox.height) / 2 - lbox.y, s, len);
 
                fprintf(lfile, "%d\n", i);
                i++;
@@ -4228,13 +4273,14 @@ struct keyfunc {
        { "invalid key func",   NULL,           {0} },
 };
 struct key {
+       TAILQ_ENTRY(key)        entry;
        unsigned int            mod;
        KeySym                  keysym;
        enum keyfuncid          funcid;
        char                    *spawn_name;
 };
-int                            keys_size = 0, keys_length = 0;
-struct key                     *keys = NULL;
+TAILQ_HEAD(key_list, key);
+struct key_list                        keys = TAILQ_HEAD_INITIALIZER(keys);
 
 /* mouse */
 enum { client_click, root_click };
@@ -4255,13 +4301,14 @@ void
 update_modkey(unsigned int mod)
 {
        int                     i;
+       struct key              *kp;
 
        mod_key = mod;
-       for (i = 0; i < keys_length; i++)
-               if (keys[i].mod & ShiftMask)
-                       keys[i].mod = mod | ShiftMask;
+       TAILQ_FOREACH(kp, &keys, entry)
+               if (kp->mod & ShiftMask)
+                       kp->mod = mod | ShiftMask;
                else
-                       keys[i].mod = mod;
+                       kp->mod = mod;
 
        for (i = 0; i < LENGTH(buttons); i++)
                if (buttons[i].mask & ShiftMask)
@@ -4320,7 +4367,7 @@ spawn_expand(struct swm_region *r, union arg *args, char *spawn_name,
                            == NULL)
                                err(1, "spawn_custom bar color");
                } else if (!strcasecmp(ap, "$bar_font")) {
-                       if ((real_args[i] = strdup(bar_fonts[bar_fidx]))
+                       if ((real_args[i] = strdup(bar_fonts))
                            == NULL)
                                err(1, "spawn_custom bar fonts");
                } else if (!strcasecmp(ap, "$bar_font_color")) {
@@ -4633,84 +4680,76 @@ strdupsafe(char *str)
 }
 
 void
+key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
+{
+       struct key              *kp;
+
+       DNPRINTF(SWM_D_KEY, "key_insert: enter %s [%s]\n",
+           keyfuncs[kfid].name, spawn_name);
+
+       if ((kp = malloc(sizeof *kp)) == NULL)
+               err(1, "key_insert: malloc");
+
+       kp->mod = mod;
+       kp->keysym = ks;
+       kp->funcid = kfid;
+       kp->spawn_name = strdupsafe(spawn_name);
+       TAILQ_INSERT_TAIL(&keys, kp, entry);
+
+       DNPRINTF(SWM_D_KEY, "key_insert: leave\n");
+}
+
+void
+key_remove(struct key *kp)
+{
+       DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name);
+
+       TAILQ_REMOVE(&keys, kp, entry);
+       free(kp->spawn_name);
+       free(kp);
+
+       DNPRINTF(SWM_D_KEY, "key_remove: leave\n");
+}
+
+void
+key_replace(struct key *kp, unsigned int mod, KeySym ks, enum keyfuncid kfid,
+    char *spawn_name)
+{
+       DNPRINTF(SWM_D_KEY, "key_replace: %s [%s]\n", keyfuncs[kp->funcid].name,
+           spawn_name);
+
+       key_remove(kp);
+       key_insert(mod, ks, kfid, spawn_name);
+
+       DNPRINTF(SWM_D_KEY, "key_replace: leave\n");
+}
+
+void
 setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid,
     char *spawn_name)
 {
-       int                     i, j;
+       struct key              *kp;
+
        DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n",
            keyfuncs[kfid].name, spawn_name);
-       /* find existing */
-       for (i = 0; i < keys_length; i++) {
-               if (keys[i].mod == mod && keys[i].keysym == ks) {
-                       if (kfid == kf_invalid) {
-                               /* found: delete */
-                               DNPRINTF(SWM_D_KEY,
-                                   "setkeybinding: delete #%d %s\n",
-                                   i, keyfuncs[keys[i].funcid].name);
-                               free(keys[i].spawn_name);
-                               j = keys_length - 1;
-                               if (i < j)
-                                       keys[i] = keys[j];
-                               keys_length--;
-                               DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
-                               return;
-                       } else {
-                               /* found: replace */
-                               DNPRINTF(SWM_D_KEY,
-                                   "setkeybinding: replace #%d %s [%s]\n",
-                                   i, keyfuncs[keys[i].funcid].name,
-                                   spawn_name);
-                               free(keys[i].spawn_name);
-                               keys[i].mod = mod;
-                               keys[i].keysym = ks;
-                               keys[i].funcid = kfid;
-                               keys[i].spawn_name = strdupsafe(spawn_name);
-                               DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
-                               return;
-                       }
+
+       TAILQ_FOREACH(kp, &keys, entry) {
+               if (kp->mod == mod && kp->keysym == ks) {
+                       if (kfid == kf_invalid)
+                               key_remove(kp);
+                       else
+                               key_replace(kp, mod, ks, kfid, spawn_name);
+                       DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
+                       return;
                }
        }
        if (kfid == kf_invalid) {
-               fprintf(stderr,
-                   "error: setkeybinding: cannot find mod/key combination");
+               warnx("error: setkeybinding: cannot find mod/key combination");
                DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
                return;
        }
-       /* not found: add */
-       if (keys_size == 0 || keys == NULL) {
-               keys_size = 4;
-               DNPRINTF(SWM_D_KEY, "setkeybinding: init list %d\n", keys_size);
-               keys = malloc((size_t)keys_size * sizeof(struct key));
-               if (keys == NULL) {
-                       fprintf(stderr, "malloc failed\n");
-                       perror(" failed");
-                       quit(NULL, NULL);
-               }
-       } else if (keys_length == keys_size) {
-               keys_size *= 2;
-               DNPRINTF(SWM_D_KEY, "setkeybinding: grow list %d\n", keys_size);
-               keys = realloc(keys, (size_t)keys_size * sizeof(struct key));
-               if (keys == NULL) {
-                       fprintf(stderr, "realloc failed\n");
-                       perror(" failed");
-                       quit(NULL, NULL);
-               }
-       }
-       if (keys_length < keys_size) {
-               j = keys_length++;
-               DNPRINTF(SWM_D_KEY, "setkeybinding: add #%d %s [%s]\n",
-                   j, keyfuncs[kfid].name, spawn_name);
-               keys[j].mod = mod;
-               keys[j].keysym = ks;
-               keys[j].funcid = kfid;
-               keys[j].spawn_name = strdupsafe(spawn_name);
-       } else {
-               fprintf(stderr, "keys array problem?\n");
-               if (keys == NULL) {
-                       fprintf(stderr, "keys array problem\n");
-                       quit(NULL, NULL);
-               }
-       }
+
+       key_insert(mod, ks, kfid, spawn_name);
        DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n");
 }
 
@@ -4843,12 +4882,14 @@ setup_keys(void)
 void
 clear_keys(void)
 {
-       int                     i;
+       struct key              *kp_loop, *kp_next;
 
-       /* clear all key bindings, if any */
-       for (i = 0; i < keys_length; i++)
-               free(keys[i].spawn_name);
-       keys_length = 0;
+       kp_loop = TAILQ_FIRST(&keys);
+       while (kp_loop != NULL) {
+               kp_next = TAILQ_NEXT(kp_loop, entry);
+               key_remove(kp_loop);
+               kp_loop = kp_next;
+       }
 }
 
 int
@@ -4892,10 +4933,11 @@ updatenumlockmask(void)
 void
 grabkeys(void)
 {
-       unsigned int            i, j, k;
+       unsigned int            j, k;
        KeyCode                 code;
        unsigned int            modifiers[] =
            { 0, LockMask, numlockmask, numlockmask | LockMask };
+       struct key              *kp;
 
        DNPRINTF(SWM_D_MISC, "grabkeys\n");
        updatenumlockmask();
@@ -4904,11 +4946,11 @@ grabkeys(void)
                if (TAILQ_EMPTY(&screens[k].rl))
                        continue;
                XUngrabKey(display, AnyKey, AnyModifier, screens[k].root);
-               for (i = 0; i < keys_length; i++) {
-                       if ((code = XKeysymToKeycode(display, keys[i].keysym)))
+               TAILQ_FOREACH(kp, &keys, entry) {
+                       if ((code = XKeysymToKeycode(display, kp->keysym)))
                                for (j = 0; j < LENGTH(modifiers); j++)
                                        XGrabKey(display, code,
-                                           keys[i].mod | modifiers[j],
+                                           kp->mod | modifiers[j],
                                            screens[k].root, True,
                                            GrabModeAsync, GrabModeAsync);
                }
@@ -5115,6 +5157,7 @@ int
 setconfvalue(char *selector, char *value, int flags)
 {
        int     i;
+       char    *b;
 
        switch (flags) {
        case SWM_S_BAR_DELAY:
@@ -5193,9 +5236,12 @@ setconfvalue(char *selector, char *value, int flags)
                border_width = atoi(value);
                break;
        case SWM_S_BAR_FONT:
-               free(bar_fonts[0]);
-               if ((bar_fonts[0] = strdup(value)) == NULL)
-                       err(1, "setconfvalue: bar_font");
+               b = bar_fonts;
+               if (asprintf(&bar_fonts, "%s,%s", value, bar_fonts) == -1)
+                       err(1, "setconfvalue: asprintf: failed to allocate "
+                               "memory for bar_fonts.");
+
+               free(b);
                break;
        case SWM_S_BAR_ACTION:
                free(bar_argv[0]);
@@ -5548,6 +5594,7 @@ conf_load(char *filename, int keymapping)
 out:
        free(line);
        fclose(config);
+       DNPRINTF(SWM_D_CONF, "conf_load: end with error.\n");
 
        return (1);
 }
@@ -5907,6 +5954,8 @@ unmanage_window(struct ws_win *win)
 
        focus_prev(win);
 
+       XFree(win->hints);
+
        TAILQ_REMOVE(&win->ws->winlist, win, entry);
        TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry);
 
@@ -5957,25 +6006,25 @@ expose(XEvent *e)
 void
 keypress(XEvent *e)
 {
-       unsigned int            i;
        KeySym                  keysym;
        XKeyEvent               *ev = &e->xkey;
+       struct key              *kp;
 
        keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0);
-       for (i = 0; i < keys_length; i++)
-               if (keysym == keys[i].keysym
-                   && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)
-                   && keyfuncs[keys[i].funcid].func) {
-                       if (keys[i].funcid == kf_spawn_custom)
+       TAILQ_FOREACH(kp, &keys, entry)
+               if (keysym == kp->keysym
+                   && CLEANMASK(kp->mod) == CLEANMASK(ev->state)
+                   && keyfuncs[kp->funcid].func) {
+                       if (kp->funcid == kf_spawn_custom)
                                spawn_custom(
                                    root_to_region(ev->root),
-                                   &(keyfuncs[keys[i].funcid].args),
-                                   keys[i].spawn_name
+                                   &(keyfuncs[kp->funcid].args),
+                                   kp->spawn_name
                                    );
                        else
-                               keyfuncs[keys[i].funcid].func(
+                               keyfuncs[kp->funcid].func(
                                    root_to_region(ev->root),
-                                   &(keyfuncs[keys[i].funcid].args)
+                                   &(keyfuncs[kp->funcid].args)
                                    );
                }
 }
@@ -6295,9 +6344,13 @@ propertynotify(XEvent *e)
 {
        struct ws_win           *win;
        XPropertyEvent          *ev = &e->xproperty;
-
+#ifdef SWM_DEBUG
+       char                    *name;
+       name = XGetAtomName(display, ev->atom);
        DNPRINTF(SWM_D_EVENT, "propertynotify: window: 0x%lx, atom: %s\n",
-           ev->window, XGetAtomName(display, ev->atom));
+           ev->window, name);
+       XFree(name);
+#endif
 
        win = find_window(ev->window);
        if (win == NULL)
@@ -6694,6 +6747,7 @@ setup_screens(void)
        int                     i, j, k;
        int                     errorbase, major, minor;
        struct workspace        *ws;
+       XGCValues               gcv;
 
        if ((screens = calloc(ScreenCount(display),
             sizeof(struct swm_screen))) == NULL)
@@ -6722,6 +6776,13 @@ setup_screens(void)
                setscreencolor("black", i + 1, SWM_S_COLOR_BAR);
                setscreencolor("rgb:a0/a0/a0", i + 1, SWM_S_COLOR_BAR_FONT);
 
+               /* create graphics context on screen with default font color */
+               screens[i].bar_gc = XCreateGC(display, screens[i].root, 0,
+                   &gcv);
+
+               XSetForeground(display, screens[i].bar_gc,
+                   screens[i].c[SWM_S_COLOR_BAR_FONT].color);
+
                /* set default cursor */
                XDefineCursor(display, screens[i].root,
                    XCreateFontCursor(display, XC_left_ptr));
@@ -6757,19 +6818,14 @@ setup_screens(void)
 void
 setup_globals(void)
 {
-       if ((bar_fonts[0] = strdup("-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*"))
-           == NULL)
-               err(1, "setup_globals: strdup");
-       if ((bar_fonts[1] = strdup("-*-times-medium-r-*-*-*-*-*-*-*-*-*-*"))
-           == NULL)
-               err(1, "setup_globals: strdup");
-       if ((bar_fonts[2] = strdup("-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*"))
-           == NULL)
-               err(1, "setup_globals: strdup");
+       if ((bar_fonts = strdup(SWM_BAR_FONTS)) == NULL)
+               err(1, "setup_globals: strdup: failed to allocate memory.");
+
        if ((spawn_term[0] = strdup("xterm")) == NULL)
-               err(1, "setup_globals: strdup");
+               err(1, "setup_globals: strdup: failed to allocate memory.");
+
        if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL)
-               err(1, "strdup");
+               err(1, "setup_globals: strdup: failed to allocate memory.");
 }
 
 void
@@ -6819,6 +6875,9 @@ main(int argc, char *argv[])
            !XSupportsLocale())
                warnx("no locale support");
 
+       if (!X_HAVE_UTF8_STRING)
+               warnx("no UTF-8 support");
+
        if (!(display = XOpenDisplay(0)))
                errx(1, "can not open display");
 
@@ -6854,8 +6913,8 @@ main(int argc, char *argv[])
        if (pwd == NULL)
                errx(1, "invalid user: %d", getuid());
 
-       setup_screens();
        setup_globals();
+       setup_screens();
        setup_keys();
        setup_quirks();
        setup_spawn();
@@ -6872,8 +6931,12 @@ main(int argc, char *argv[])
                        if (S_ISREG(sb.st_mode))
                                cfile = conf;
        }
-       if (cfile)
-               conf_load(cfile, SWM_CONF_DEFAULT);
+
+       /* load conf (if any) and refresh font color in bar graphics contexts */
+       if (cfile && conf_load(cfile, SWM_CONF_DEFAULT) == 0)
+               for (i = 0; i < ScreenCount(display); ++i)
+                       XSetForeground(display, screens[i].bar_gc,
+                           screens[i].c[SWM_S_COLOR_BAR_FONT].color);
 
        setup_ewmh();
        /* set some values to work around bad programs */
@@ -6970,7 +7033,12 @@ main(int argc, char *argv[])
 done:
        teardown_ewmh();
        bar_extra_stop();
-       XFreeGC(display, bar_gc);
+
+       for (i = 0; i < ScreenCount(display); ++i)
+               if (screens[i].bar_gc != NULL)
+                       XFreeGC(display, screens[i].bar_gc);
+
+       XFreeFontSet(display, bar_fs);
        XCloseDisplay(display);
 
        return (0);