JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Fix status bar flicker by double-buffering the output.
[spectrwm.git] / spectrwm.c
index e2f8670..1115cac 100644 (file)
@@ -292,6 +292,7 @@ int                 bar_extra_running = 0;
 int                    bar_verbose = 1;
 int                    bar_height = 0;
 int                    bar_justify = SWM_BAR_JUSTIFY_LEFT;
+char                   *bar_format = NULL;
 int                    stack_enabled = 1;
 int                    clock_enabled = 1;
 int                    urgent_enabled = 0;
@@ -311,7 +312,6 @@ pid_t                       bar_pid;
 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)
@@ -331,6 +331,12 @@ struct swm_geometry {
 struct swm_screen;
 struct workspace;
 
+struct swm_bar {
+       Window                  id;
+       Pixmap                  buffer;
+       struct swm_geometry     g;
+};
+
 /* virtual "screens" */
 struct swm_region {
        TAILQ_ENTRY(swm_region) entry;
@@ -338,7 +344,7 @@ struct swm_region {
        struct workspace        *ws;    /* current workspace on this region */
        struct workspace        *ws_prior; /* prior workspace on this region */
        struct swm_screen       *s;     /* screen idx */
-       Window                  bar_window;
+       struct swm_bar          *bar;
 };
 TAILQ_HEAD(swm_region_list, swm_region);
 
@@ -452,8 +458,14 @@ struct workspace {
        } l_state;
 };
 
-enum   { SWM_S_COLOR_BAR, SWM_S_COLOR_BAR_BORDER, SWM_S_COLOR_BAR_FONT,
-         SWM_S_COLOR_FOCUS, SWM_S_COLOR_UNFOCUS, SWM_S_COLOR_MAX };
+enum {
+       SWM_S_COLOR_BAR,
+       SWM_S_COLOR_BAR_BORDER,
+       SWM_S_COLOR_BAR_FONT,
+       SWM_S_COLOR_FOCUS,
+       SWM_S_COLOR_UNFOCUS,
+       SWM_S_COLOR_MAX
+};
 
 /* physical screen mapping */
 #define SWM_WS_MAX             (22)    /* hard limit */
@@ -542,17 +554,33 @@ struct quirk_list         quirks = TAILQ_HEAD_INITIALIZER(quirks);
  * Supported EWMH hints should be added to
  * both the enum and the ewmh array
  */
-enum { _NET_ACTIVE_WINDOW, _NET_MOVERESIZE_WINDOW, _NET_CLOSE_WINDOW,
-    _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DOCK,
-    _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_UTILITY,
-    _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_DIALOG,
-    _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_STATE,
-    _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT,
-    _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_SKIP_PAGER,
-    _NET_WM_STATE_HIDDEN, _NET_WM_STATE_ABOVE, _SWM_WM_STATE_MANUAL,
-    _NET_WM_STATE_FULLSCREEN, _NET_WM_ALLOWED_ACTIONS, _NET_WM_ACTION_MOVE,
-    _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_CLOSE,
-    SWM_EWMH_HINT_MAX };
+enum {
+       _NET_ACTIVE_WINDOW,
+       _NET_CLOSE_WINDOW,
+       _NET_MOVERESIZE_WINDOW,
+       _NET_WM_ACTION_CLOSE,
+       _NET_WM_ACTION_FULLSCREEN,
+       _NET_WM_ACTION_MOVE,
+       _NET_WM_ACTION_RESIZE,
+       _NET_WM_ALLOWED_ACTIONS,
+       _NET_WM_STATE,
+       _NET_WM_STATE_ABOVE,
+       _NET_WM_STATE_FULLSCREEN,
+       _NET_WM_STATE_HIDDEN,
+       _NET_WM_STATE_MAXIMIZED_HORZ,
+       _NET_WM_STATE_MAXIMIZED_VERT,
+       _NET_WM_STATE_SKIP_PAGER,
+       _NET_WM_STATE_SKIP_TASKBAR,
+       _NET_WM_WINDOW_TYPE,
+       _NET_WM_WINDOW_TYPE_DIALOG,
+       _NET_WM_WINDOW_TYPE_DOCK,
+       _NET_WM_WINDOW_TYPE_NORMAL,
+       _NET_WM_WINDOW_TYPE_SPLASH,
+       _NET_WM_WINDOW_TYPE_TOOLBAR,
+       _NET_WM_WINDOW_TYPE_UTILITY,
+       _SWM_WM_STATE_MANUAL,
+       SWM_EWMH_HINT_MAX
+};
 
 struct ewmh_hint {
        char    *name;
@@ -560,29 +588,29 @@ struct ewmh_hint {
 } ewmh[SWM_EWMH_HINT_MAX] =    {
     /* must be in same order as in the enum */
     {"_NET_ACTIVE_WINDOW", None},
-    {"_NET_MOVERESIZE_WINDOW", None},
     {"_NET_CLOSE_WINDOW", None},
-    {"_NET_WM_WINDOW_TYPE", None},
-    {"_NET_WM_WINDOW_TYPE_DOCK", None},
-    {"_NET_WM_WINDOW_TYPE_TOOLBAR", None},
-    {"_NET_WM_WINDOW_TYPE_UTILITY", None},
-    {"_NET_WM_WINDOW_TYPE_SPLASH", None},
-    {"_NET_WM_WINDOW_TYPE_DIALOG", None},
-    {"_NET_WM_WINDOW_TYPE_NORMAL", None},
+    {"_NET_MOVERESIZE_WINDOW", None},
+    {"_NET_WM_ACTION_CLOSE", None},
+    {"_NET_WM_ACTION_FULLSCREEN", None},
+    {"_NET_WM_ACTION_MOVE", None},
+    {"_NET_WM_ACTION_RESIZE", None},
+    {"_NET_WM_ALLOWED_ACTIONS", None},
     {"_NET_WM_STATE", None},
+    {"_NET_WM_STATE_ABOVE", None},
+    {"_NET_WM_STATE_FULLSCREEN", None},
+    {"_NET_WM_STATE_HIDDEN", None},
     {"_NET_WM_STATE_MAXIMIZED_HORZ", None},
     {"_NET_WM_STATE_MAXIMIZED_VERT", None},
-    {"_NET_WM_STATE_SKIP_TASKBAR", None},
     {"_NET_WM_STATE_SKIP_PAGER", None},
-    {"_NET_WM_STATE_HIDDEN", None},
-    {"_NET_WM_STATE_ABOVE", None},
+    {"_NET_WM_STATE_SKIP_TASKBAR", None},
+    {"_NET_WM_WINDOW_TYPE", None},
+    {"_NET_WM_WINDOW_TYPE_DIALOG", None},
+    {"_NET_WM_WINDOW_TYPE_DOCK", None},
+    {"_NET_WM_WINDOW_TYPE_NORMAL", None},
+    {"_NET_WM_WINDOW_TYPE_SPLASH", None},
+    {"_NET_WM_WINDOW_TYPE_TOOLBAR", None},
+    {"_NET_WM_WINDOW_TYPE_UTILITY", None},
     {"_SWM_WM_STATE_MANUAL", None},
-    {"_NET_WM_STATE_FULLSCREEN", None},
-    {"_NET_WM_ALLOWED_ACTIONS", None},
-    {"_NET_WM_ACTION_MOVE", None},
-    {"_NET_WM_ACTION_RESIZE", None},
-    {"_NET_WM_ACTION_FULLSCREEN", None},
-    {"_NET_WM_ACTION_CLOSE", None},
 };
 
 void            store_float_geom(struct ws_win *, struct swm_region *);
@@ -1303,14 +1331,12 @@ socket_setnonblock(int fd)
 }
 
 void
-bar_print(struct swm_region *r, char *s)
+bar_print(struct swm_region *r, const char *s)
 {
        int                     x = 0;
        size_t                  len;
        XRectangle              ibox, lbox;
 
-       XClearWindow(display, r->bar_window);
-
        len = strlen(s);
        XmbTextExtents(bar_fs, s, len, &ibox, &lbox);
 
@@ -1329,9 +1355,21 @@ bar_print(struct swm_region *r, char *s)
        if (x < SWM_BAR_OFFSET)
                x = SWM_BAR_OFFSET;
 
-       DRAWSTRING(display, r->bar_window, bar_fs, r->s->bar_gc,
+       /* clear back buffer */
+       XSetForeground(display, r->s->bar_gc, r->s->c[SWM_S_COLOR_BAR].color);
+       XFillRectangle(display, r->bar->buffer, r->s->bar_gc, 0, 0,
+           WIDTH(r->bar), HEIGHT(r->bar));
+
+       /* draw back buffer */
+       XSetForeground(display, r->s->bar_gc,
+           r->s->c[SWM_S_COLOR_BAR_FONT].color);
+       DRAWSTRING(display, r->bar->buffer, bar_fs, r->s->bar_gc,
            x, (bar_fs_extents->max_logical_extent.height - lbox.height) / 2 -
            lbox.y, s, len);
+
+       /* blt */
+       XCopyArea(display, r->bar->buffer, r->bar->id, r->s->bar_gc, 0, 0,
+           WIDTH(r->bar), HEIGHT(r->bar), 0, 0);
 }
 
 void
@@ -1350,61 +1388,66 @@ bar_extra_stop(void)
 }
 
 void
-bar_class_name(char *s, ssize_t sz, struct ws_win *cur_focus)
+bar_class_name(char *s, size_t sz, struct swm_region *r)
 {
-       int                     do_class, do_name;
-       XClassHint              *ch;
+       if (r == NULL || r->ws == NULL || r->ws->focus == NULL)
+               return;
+       if (r->ws->focus->ch.res_class != NULL)
+               strlcat(s, r->ws->focus->ch.res_class, sz);
+}
 
-       if (title_name_enabled == 0 && title_class_enabled == 0)
+void
+bar_title_name(char *s, size_t sz, struct swm_region *r)
+{
+       if (r == NULL || r->ws == NULL || r->ws->focus == NULL)
                return;
-       if (cur_focus == NULL)
+       if (r->ws->focus->ch.res_name != NULL)
+               strlcat(s, r->ws->focus->ch.res_name, sz);
+}
+
+void
+bar_class_title_name(char *s, size_t sz, struct swm_region *r)
+{
+       if (r == NULL || r->ws == NULL || r->ws->focus == NULL)
                return;
 
-       ch = &cur_focus->ch;
-       do_class = (title_class_enabled && ch->res_class != NULL);
-       do_name = (title_name_enabled && ch->res_name != NULL);
+       bar_class_name(s, sz, r);
+       strlcat(s, ":", sz);
+       bar_title_name(s, sz, r);
+}
 
-       if (do_class)
-               strlcat(s, ch->res_class, sz);
-       if (do_class && do_name)
-               strlcat(s, ":", sz);
-       if (do_name)
-               strlcat(s, ch->res_name, sz);
-       strlcat(s, "    ", sz);
+void
+bar_window_float(char *s, size_t sz, struct swm_region *r)
+{
+       if (r == NULL || r ->ws == NULL || r->ws->focus == NULL)
+               return;
+       if (r->ws->focus->floating)
+               strlcat(s, "(f)", sz);
 }
 
 void
-bar_window_name(char *s, ssize_t sz, struct ws_win *cur_focus)
+bar_window_name(char *s, size_t sz, struct swm_region *r)
 {
        unsigned char           *title;
 
-       if (window_name_enabled && cur_focus != NULL) {
-               title = get_win_name(cur_focus->id);
-               if (title != NULL) {
-                       DNPRINTF(SWM_D_BAR, "bar_window_name: title: %s\n",
-                           title);
-
-                       if (cur_focus->floating)
-                               strlcat(s, "(f) ", sz);
-                       strlcat(s, (char *)title, sz);
-                       strlcat(s, " ", sz);
-                       XFree(title);
-               }
-       }
+       if (r == NULL || r->ws == NULL || r->ws->focus == NULL)
+               return;
+       if ((title = get_win_name(r->ws->focus->id)) == NULL)
+               return;
+
+       strlcat(s, (char *)title, sz);
+       XFree(title);
 }
 
 int            urgent[SWM_WS_MAX];
 void
-bar_urgent(char *s, ssize_t sz)
+bar_urgent(char *s, size_t sz)
 {
        XWMHints                *wmh = NULL;
        struct ws_win           *win;
        int                     i, j;
        char                    b[8];
 
-       if (urgent_enabled == 0)
-               return;
-
        for (i = 0; i < workspace_limit; i++)
                urgent[i] = 0;
 
@@ -1420,7 +1463,6 @@ bar_urgent(char *s, ssize_t sz)
                                XFree(wmh);
                        }
 
-       strlcat(s, "* ", sz);
        for (i = 0; i < workspace_limit; i++) {
                if (urgent[i])
                        snprintf(b, sizeof b, "%d ", i + 1);
@@ -1428,22 +1470,254 @@ bar_urgent(char *s, ssize_t sz)
                        snprintf(b, sizeof b, "- ");
                strlcat(s, b, sz);
        }
-       strlcat(s, "*    ", sz);
 }
 
 void
-bar_update(void)
+bar_workspace_name(char *s, size_t sz, struct swm_region *r)
 {
-       time_t                  tmt;
+       if (r == NULL || r->ws == NULL)
+               return;
+       if (r->ws->name != NULL)
+               strlcat(s, r->ws->name, sz);
+}
+
+/* build the default bar format according to the defined enabled options */
+void
+bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
+{
+       /* if format provided, just copy the buffers */
+       if (bar_format != NULL) {
+               strlcpy(fmtnew, fmtexp, sz);
+               return;
+       }
+
+       /* reset the output buffer */
+       *fmtnew = '\0';
+
+       strlcat(fmtnew, "+N:+I ", sz);
+       if (stack_enabled)
+               strlcat(fmtnew, "+S", sz);
+       strlcat(fmtnew, " ", sz);
+
+       /* only show the workspace name if there's actually one */
+       if (r != NULL && r->ws != NULL && r->ws->name != NULL)
+               strlcat(fmtnew, "<+D>", sz);
+       strlcat(fmtnew, "+3<", sz);
+
+       if (clock_enabled) {
+               strlcat(fmtnew, fmtexp, sz);
+               strlcat(fmtnew, "+4<", sz);
+       }
+
+       /* bar_urgent already adds the space before the last asterisk */
+       if (urgent_enabled)
+               strlcat(fmtnew, "* +U*+4<", sz);
+
+       if (title_class_enabled) {
+               strlcat(fmtnew, "+C", sz);
+               if (title_name_enabled == 0)
+                       strlcat(fmtnew, "+4<", sz);
+       }
+
+       /* checks needed by the colon and floating strlcat(3) calls below */
+       if (r != NULL && r->ws != NULL && r->ws->focus != NULL) {
+               if (title_name_enabled) {
+                       if (title_class_enabled)
+                               strlcat(fmtnew, ":", sz);
+                       strlcat(fmtnew, "+T+4<", sz);
+               }
+               if (window_name_enabled) {
+                       if (r->ws->focus->floating)
+                               strlcat(fmtnew, "+F ", sz);
+                       strlcat(fmtnew, "+64W ", sz);
+               }
+       }
+
+       /* finally add the action script output and the version */
+       strlcat(fmtnew, "+4<+A+4<+V", sz);
+}
+
+/* replaces the bar format character sequences (like in tmux(1)) */
+char *
+bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep,
+    size_t sz)
+{
+       char                    *ptr;
+       char                    num[8], tmp[SWM_BAR_MAX];
+       int                     limit;
+       size_t                  len, numoff = 0;
+
+       /* reset strlcat(3) buffer */
+       *tmp = '\0';
+
+       /* get number, if any */
+       fmt++;
+       while (*fmt != '\0' && isdigit((unsigned char) *fmt)) {
+               if (numoff >= sizeof num - 1)
+                       break;
+               num[numoff++] = *fmt++;
+       }
+       num[numoff] = '\0';
+
+       if ((limit = strtonum(num, 1, sizeof tmp - 1, NULL)) == 0)
+               limit = sizeof tmp - 1;
+
+       /* if number is too big, skip to the first non-digit */
+       if (numoff >= sizeof num - 1) {
+               while (*fmt != '\0' && isdigit((unsigned char) *fmt))
+                       fmt++;
+       }
+       /* there is nothing to replace (ie EOL) */
+       if (*fmt == '\0')
+               return (fmt);
+
+       switch (*fmt) {
+       case '<':
+               /* special case; no limit given, pad one space, instead */
+               if (limit == sizeof tmp - 1)
+                       limit = 1;
+               snprintf(tmp, sizeof tmp, "%*s", limit, " ");
+               break;
+       case 'A':
+               snprintf(tmp, sizeof tmp, "%s", bar_ext);
+               break;
+       case 'C':
+               bar_class_name(tmp, sizeof tmp, r);
+               break;
+       case 'D':
+               bar_workspace_name(tmp, sizeof tmp, r);
+               break;
+       case 'F':
+               bar_window_float(tmp, sizeof tmp, r);
+               break;
+       case 'I':
+               snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1);
+               break;
+       case 'N':
+               snprintf(tmp, sizeof tmp, "%d", r->s->idx + 1);
+               break;
+       case 'P':
+               bar_class_title_name(tmp, sizeof tmp, r);
+               break;
+       case 'S':
+               snprintf(tmp, sizeof tmp, "%s", r->ws->stacker);
+               break;
+       case 'T':
+               bar_title_name(tmp, sizeof tmp, r);
+               break;
+       case 'U':
+               bar_urgent(tmp, sizeof tmp);
+               break;
+       case 'V':
+               snprintf(tmp, sizeof tmp, "%s", bar_vertext);
+               break;
+       case 'W':
+               bar_window_name(tmp, sizeof tmp, r);
+               break;
+       default:
+               /* unknown character sequence; copy as-is */
+               snprintf(tmp, sizeof tmp, "+%c", *fmt);
+               break;
+       }
+
+       len = strlen(tmp);
+       ptr = tmp;
+       if (len < limit)
+               limit = len;
+       while (limit-- > 0) {
+               if (*offrep >= sz - 1)
+                       break;
+               fmtrep[(*offrep)++] = *ptr++;
+       }
+
+       fmt++;
+       return (fmt);
+}
+
+void
+bar_replace(char *fmt, char *fmtrep, struct swm_region *r, size_t sz)
+{
+       size_t                  off;
+
+       off = 0;
+       while (*fmt != '\0') {
+               if (*fmt != '+') {
+                       /* skip ordinary characters */
+                       if (off >= sz - 1)
+                               break;
+                       fmtrep[off++] = *fmt++;
+                       continue;
+               }
+
+               /* character sequence found; replace it */
+               fmt = bar_replace_seq(fmt, fmtrep, r, &off, sz);
+               if (off >= sz - 1)
+                       break;
+       }
+
+       fmtrep[off] = '\0';
+}
+
+void
+bar_fmt_expand(char *fmtexp, size_t sz)
+{
+       char                    *fmt = NULL;
+       size_t                  len;
        struct tm               tm;
+       time_t                  tmt;
+
+       /* start by grabbing the current time and date */
+       time(&tmt);
+       localtime_r(&tmt, &tm);
+
+       /* figure out what to expand */
+       if (bar_format != NULL)
+               fmt = bar_format;
+       else if (bar_format == NULL && clock_enabled)
+               fmt = clock_format;
+       /* if nothing to expand bail out */
+       if (fmt == NULL) {
+               *fmtexp = '\0';
+               return;
+       }
+
+       /* copy as-is, just in case the format shouldn't be expanded below */
+       strlcpy(fmtexp, fmt, sz);
+       /* finally pass the string through strftime(3) */
+#ifndef SWM_DENY_CLOCK_FORMAT
+       if ((len = strftime(fmtexp, sz, fmt, &tm)) == 0)
+               warnx("format too long");
+       fmtexp[len] = '\0';
+#endif
+}
+
+void
+bar_fmt_print(void)
+{
+       char                    fmtexp[SWM_BAR_MAX], fmtnew[SWM_BAR_MAX];
+       char                    fmtrep[SWM_BAR_MAX];
+       int                     i;
        struct swm_region       *r;
-       int                     i, x;
+
+       /* expand the format by first passing it through strftime(3) */
+       bar_fmt_expand(fmtexp, sizeof fmtexp);
+
+       for (i = 0; i < ScreenCount(display); i++) {
+               TAILQ_FOREACH(r, &screens[i].rl, entry) {
+                       if (r->bar == NULL)
+                               continue;
+                       bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew);
+                       bar_replace(fmtnew, fmtrep, r, sizeof fmtrep);
+                       bar_print(r, fmtrep);
+               }
+       }
+}
+
+void
+bar_update(void)
+{
        size_t                  len;
-       char                    ws[SWM_BAR_MAX];
-       char                    s[SWM_BAR_MAX];
-       unsigned char           cn[SWM_BAR_MAX];
-       char                    loc[SWM_BAR_MAX];
-       char                    *b, *stack = "";
+       char                    *b;
 
        if (bar_enabled == 0)
                return;
@@ -1461,41 +1735,7 @@ bar_update(void)
        } else
                strlcpy((char *)bar_ext, "", sizeof bar_ext);
 
-       if (clock_enabled == 0)
-               strlcpy(s, "", sizeof s);
-       else {
-               time(&tmt);
-               localtime_r(&tmt, &tm);
-               len = strftime(s, sizeof s, clock_format, &tm);
-               s[len] = '\0';
-               strlcat(s, "    ", sizeof s);
-       }
-
-       for (i = 0; i < ScreenCount(display); i++) {
-               x = 1;
-               TAILQ_FOREACH(r, &screens[i].rl, entry) {
-                       strlcpy((char *)cn, "", sizeof cn);
-                       strlcpy(ws, "", sizeof ws);
-                       if (r && r->ws) {
-                               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);
-                               if (stack_enabled)
-                                       stack = r->ws->stacker;
-
-                               snprintf(loc, sizeof loc,
-                                   "%d:%d %s %s   %s%s    %s    %s",
-                                   x++, r->ws->idx + 1, stack, ws, s, cn,
-                                   bar_ext, bar_vertext);
-                               bar_print(r, loc);
-                       }
-               }
-       }
+       bar_fmt_print();
        alarm(bar_delay);
 }
 
@@ -1513,14 +1753,17 @@ bar_toggle(struct swm_region *r, union arg *args)
 
        DNPRINTF(SWM_D_BAR, "bar_toggle\n");
 
-       if (bar_enabled)
+       if (bar_enabled) {
                for (i = 0; i < sc; i++)
                        TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
-                               XUnmapWindow(display, tmpr->bar_window);
-       else
+                               if (tmpr->bar)
+                                       XUnmapWindow(display, tmpr->bar->id);
+       } else {
                for (i = 0; i < sc; i++)
                        TAILQ_FOREACH(tmpr, &screens[i].rl, entry)
-                               XMapRaised(display, tmpr->bar_window);
+                               if (tmpr->bar)
+                                       XMapRaised(display, tmpr->bar->id);
+       }
 
        bar_enabled = !bar_enabled;
 
@@ -1568,11 +1811,13 @@ bar_refresh(void)
        bzero(&wa, sizeof wa);
        for (i = 0; i < ScreenCount(display); i++)
                TAILQ_FOREACH(r, &screens[i].rl, entry) {
+                       if (r->bar == NULL)
+                               continue;
                        wa.border_pixel =
                            screens[i].c[SWM_S_COLOR_BAR_BORDER].color;
                        wa.background_pixel =
                            screens[i].c[SWM_S_COLOR_BAR].color;
-                       XChangeWindowAttributes(display, r->bar_window,
+                       XChangeWindowAttributes(display, r->bar->id,
                            CWBackPixel | CWBorderPixel, &wa);
                }
        bar_update();
@@ -1584,13 +1829,15 @@ bar_setup(struct swm_region *r)
        char                    *default_string;
        char                    **missing_charsets;
        int                     num_missing_charsets = 0;
-       int                     i, x, y;
+       int                     i;
 
        if (bar_fs) {
                XFreeFontSet(display, bar_fs);
                bar_fs = NULL;
        }
 
+       if ((r->bar = calloc(1, sizeof(struct swm_bar))) == NULL)
+               err(1, "bar_setup: calloc: failed to allocate memory.");
 
        DNPRINTF(SWM_D_BAR, "bar_setup: loading bar_fonts: %s\n", bar_fonts);
 
@@ -1623,18 +1870,27 @@ bar_setup(struct swm_region *r)
        if (bar_height < 1)
                bar_height = 1;
 
-       x = X(r);
-       y = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
+       X(r->bar) = X(r);
+       Y(r->bar) = bar_at_bottom ? (Y(r) + HEIGHT(r) - bar_height) : Y(r);
+       WIDTH(r->bar) = WIDTH(r) - 2 * bar_border_width;
+       HEIGHT(r->bar) = bar_height - 2 * bar_border_width;
 
-       r->bar_window = XCreateSimpleWindow(display,
-           r->s->root, x, y, WIDTH(r) - 2 * bar_border_width,
-           bar_height - 2 * bar_border_width,
+       r->bar->id = XCreateSimpleWindow(display,
+           r->s->root, X(r->bar), Y(r->bar), WIDTH(r->bar), HEIGHT(r->bar),
            bar_border_width, r->s->c[SWM_S_COLOR_BAR_BORDER].color,
            r->s->c[SWM_S_COLOR_BAR].color);
-       XSelectInput(display, r->bar_window, VisibilityChangeMask);
+
+       r->bar->buffer = XCreatePixmap(display, r->bar->id, WIDTH(r->bar),
+           HEIGHT(r->bar), DefaultDepth(display, r->s->idx));
+
+       XSelectInput(display, r->bar->id, VisibilityChangeMask);
+
        if (bar_enabled)
-               XMapRaised(display, r->bar_window);
-       DNPRINTF(SWM_D_BAR, "bar_setup: bar_window: 0x%lx\n", r->bar_window);
+               XMapRaised(display, r->bar->id);
+
+       DNPRINTF(SWM_D_BAR, "bar_setup: window: 0x%lx, (x,y) w x h: (%d,%d) "
+           "%d x %d\n", WINID(r->bar), X(r->bar), Y(r->bar), WIDTH(r->bar),
+           HEIGHT(r->bar));
 
        if (signal(SIGALRM, bar_signal) == SIG_ERR)
                err(1, "could not install bar_signal");
@@ -1642,6 +1898,17 @@ bar_setup(struct swm_region *r)
 }
 
 void
+bar_cleanup(struct swm_region *r)
+{
+       if (r->bar == NULL)
+               return;
+       XDestroyWindow(display, r->bar->id);
+       XFreePixmap(display, r->bar->buffer);
+       free(r->bar);
+       r->bar = NULL;
+}
+
+void
 drain_enter_notify(void)
 {
        int                     i = 0;
@@ -2031,18 +2298,6 @@ spawn(int ws_idx, union arg *args, int close_fd)
 }
 
 void
-spawnterm(struct swm_region *r, union arg *args)
-{
-       DNPRINTF(SWM_D_MISC, "spawnterm\n");
-
-       if (fork() == 0) {
-               if (term_width)
-                       setenv("_SWM_XTERM_FONTADJ", "", 1);
-               spawn(r->ws->idx, args, 1);
-       }
-}
-
-void
 kill_refs(struct ws_win *win)
 {
        int                     i, x;
@@ -2282,8 +2537,6 @@ switchws(struct swm_region *r, union arg *args)
        a.id = SWM_ARG_ID_FOCUSCUR;
        focus(new_ws->r, &a);
 
-       bar_update();
-
        /* unmap old windows */
        if (unmap_old)
                TAILQ_FOREACH(win, &old_ws->winlist, entry)
@@ -2699,7 +2952,6 @@ cycle_layout(struct swm_region *r, union arg *args)
                drain_enter_notify();
        a.id = SWM_ARG_ID_FOCUSCUR;
        focus(r, &a);
-       bar_update();
 }
 
 void
@@ -4201,8 +4453,6 @@ enum keyfuncid {
        kf_focus_prev,
        kf_swap_next,
        kf_swap_prev,
-       kf_spawn_term,
-       kf_spawn_menu,
        kf_quit,
        kf_restart,
        kf_focus_main,
@@ -4260,12 +4510,8 @@ enum keyfuncid {
        kf_bar_toggle,
        kf_wind_kill,
        kf_wind_del,
-       kf_screenshot_all,
-       kf_screenshot_wind,
        kf_float_toggle,
        kf_version,
-       kf_spawn_lock,
-       kf_spawn_initscr,
        kf_spawn_custom,
        kf_iconify,
        kf_uniconify,
@@ -4292,11 +4538,6 @@ dummykeyfunc(struct swm_region *r, union arg *args)
 {
 };
 
-void
-legacyfunc(struct swm_region *r, union arg *args)
-{
-};
-
 struct keyfunc {
        char                    name[SWM_FUNCNAME_LEN];
        void                    (*func)(struct swm_region *r, union arg *);
@@ -4317,8 +4558,6 @@ struct keyfunc {
        { "focus_prev",         focus,          {.id = SWM_ARG_ID_FOCUSPREV} },
        { "swap_next",          swapwin,        {.id = SWM_ARG_ID_SWAPNEXT} },
        { "swap_prev",          swapwin,        {.id = SWM_ARG_ID_SWAPPREV} },
-       { "spawn_term",         spawnterm,      {.argv = spawn_term} },
-       { "spawn_menu",         legacyfunc,     {0} },
        { "quit",               quit,           {0} },
        { "restart",            restart,        {0} },
        { "focus_main",         focus,          {.id = SWM_ARG_ID_FOCUSMAIN} },
@@ -4376,12 +4615,8 @@ struct keyfunc {
        { "bar_toggle",         bar_toggle,     {0} },
        { "wind_kill",          wkill,          {.id = SWM_ARG_ID_KILLWINDOW} },
        { "wind_del",           wkill,          {.id = SWM_ARG_ID_DELETEWINDOW} },
-       { "screenshot_all",     legacyfunc,     {0} },
-       { "screenshot_wind",    legacyfunc,     {0} },
        { "float_toggle",       floating_toggle,{0} },
        { "version",            version,        {0} },
-       { "spawn_lock",         legacyfunc,     {0} },
-       { "spawn_initscr",      legacyfunc,     {0} },
        { "spawn_custom",       dummykeyfunc,   {0} },
        { "iconify",            iconify,        {0} },
        { "uniconify",          uniconify,      {0} },
@@ -4408,7 +4643,7 @@ struct key {
        enum keyfuncid          funcid;
        char                    *spawn_name;
 };
-RB_HEAD(key_list, key);
+RB_HEAD(key_tree, key);
 
 int
 key_cmp(struct key *kp1, struct key *kp2)
@@ -4426,8 +4661,8 @@ key_cmp(struct key *kp1, struct key *kp2)
        return (0);
 }
 
-RB_GENERATE_STATIC(key_list, key, entry, key_cmp);
-struct key_list                        keys;
+RB_GENERATE(key_tree, key, entry, key_cmp);
+struct key_tree                        keys;
 
 /* mouse */
 enum { client_click, root_click };
@@ -4451,7 +4686,7 @@ update_modkey(unsigned int mod)
        struct key              *kp;
 
        mod_key = mod;
-       RB_FOREACH(kp, key_list, &keys)
+       RB_FOREACH(kp, key_tree, &keys)
                if (kp->mod & ShiftMask)
                        kp->mod = mod | ShiftMask;
                else
@@ -4819,7 +5054,7 @@ key_insert(unsigned int mod, KeySym ks, enum keyfuncid kfid, char *spawn_name)
        kp->keysym = ks;
        kp->funcid = kfid;
        kp->spawn_name = strdupsafe(spawn_name);
-       RB_INSERT(key_list, &keys, kp);
+       RB_INSERT(key_tree, &keys, kp);
 
        DNPRINTF(SWM_D_KEY, "key_insert: leave\n");
 }
@@ -4832,7 +5067,7 @@ key_lookup(unsigned int mod, KeySym ks)
        kp.keysym = ks;
        kp.mod = mod;
 
-       return (RB_FIND(key_list, &keys, &kp));
+       return (RB_FIND(key_tree, &keys, &kp));
 }
 
 void
@@ -4840,7 +5075,7 @@ key_remove(struct key *kp)
 {
        DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name);
 
-       RB_REMOVE(key_list, &keys, kp);
+       RB_REMOVE(key_tree, &keys, kp);
        free(kp->spawn_name);
        free(kp);
 
@@ -4951,7 +5186,7 @@ setup_keys(void)
        setkeybinding(MODKEY,           XK_k,           kf_focus_prev,  NULL);
        setkeybinding(MODKEY|ShiftMask, XK_j,           kf_swap_next,   NULL);
        setkeybinding(MODKEY|ShiftMask, XK_k,           kf_swap_prev,   NULL);
-       setkeybinding(MODKEY|ShiftMask, XK_Return,      kf_spawn_term,  NULL);
+       setkeybinding(MODKEY|ShiftMask, XK_Return,      kf_spawn_custom,"term");
        setkeybinding(MODKEY,           XK_p,           kf_spawn_custom,"menu");
        setkeybinding(MODKEY|ShiftMask, XK_q,           kf_quit,        NULL);
        setkeybinding(MODKEY,           XK_q,           kf_restart,     NULL);
@@ -5103,7 +5338,7 @@ grabkeys(void)
                if (TAILQ_EMPTY(&screens[k].rl))
                        continue;
                XUngrabKey(display, AnyKey, AnyModifier, screens[k].root);
-               RB_FOREACH(kp, key_list, &keys) {
+               RB_FOREACH(kp, key_tree, &keys) {
                        if ((code = XKeysymToKeycode(display, kp->keysym)))
                                for (j = 0; j < LENGTH(modifiers); j++)
                                        XGrabKey(display, code,
@@ -5299,17 +5534,39 @@ setup_quirks(void)
 #define SWM_CONF_FILE          "spectrwm.conf"
 #define SWM_CONF_FILE_OLD      "scrotwm.conf"
 
-enum   { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH,
-         SWM_S_STACK_ENABLED, SWM_S_CLOCK_ENABLED, SWM_S_CLOCK_FORMAT,
-         SWM_S_CYCLE_EMPTY, SWM_S_CYCLE_VISIBLE, SWM_S_WORKSPACE_LIMIT,
-         SWM_S_SS_ENABLED, SWM_S_TERM_WIDTH, SWM_S_TITLE_CLASS_ENABLED,
-         SWM_S_TITLE_NAME_ENABLED, SWM_S_WINDOW_NAME_ENABLED,
-         SWM_S_URGENT_ENABLED, SWM_S_FOCUS_MODE, SWM_S_FOCUS_CLOSE,
-         SWM_S_FOCUS_CLOSE_WRAP, SWM_S_FOCUS_DEFAULT, SWM_S_SPAWN_ORDER,
-         SWM_S_DISABLE_BORDER, SWM_S_BORDER_WIDTH, SWM_S_BAR_FONT,
-         SWM_S_BAR_ACTION, SWM_S_SPAWN_TERM, SWM_S_SS_APP, SWM_S_DIALOG_RATIO,
-         SWM_S_BAR_AT_BOTTOM, SWM_S_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY
-       };
+enum {
+       SWM_S_BAR_ACTION,
+       SWM_S_BAR_AT_BOTTOM,
+       SWM_S_BAR_BORDER_WIDTH,
+       SWM_S_BAR_DELAY,
+       SWM_S_BAR_ENABLED,
+       SWM_S_BAR_FONT,
+       SWM_S_BAR_FORMAT,
+       SWM_S_BAR_JUSTIFY,
+       SWM_S_BORDER_WIDTH,
+       SWM_S_CLOCK_ENABLED,
+       SWM_S_CLOCK_FORMAT,
+       SWM_S_CYCLE_EMPTY,
+       SWM_S_CYCLE_VISIBLE,
+       SWM_S_DIALOG_RATIO,
+       SWM_S_DISABLE_BORDER,
+       SWM_S_FOCUS_CLOSE,
+       SWM_S_FOCUS_CLOSE_WRAP,
+       SWM_S_FOCUS_DEFAULT,
+       SWM_S_FOCUS_MODE,
+       SWM_S_SPAWN_ORDER,
+       SWM_S_SPAWN_TERM,
+       SWM_S_SS_APP,
+       SWM_S_SS_ENABLED,
+       SWM_S_STACK_ENABLED,
+       SWM_S_TERM_WIDTH,
+       SWM_S_TITLE_CLASS_ENABLED,
+       SWM_S_TITLE_NAME_ENABLED,
+       SWM_S_URGENT_ENABLED,
+       SWM_S_VERBOSE_LAYOUT,
+       SWM_S_WINDOW_NAME_ENABLED,
+       SWM_S_WORKSPACE_LIMIT
+};
 
 int
 setconfvalue(char *selector, char *value, int flags)
@@ -5318,17 +5575,37 @@ setconfvalue(char *selector, char *value, int flags)
        char    *b;
 
        switch (flags) {
+       case SWM_S_BAR_ACTION:
+               free(bar_argv[0]);
+               if ((bar_argv[0] = strdup(value)) == NULL)
+                       err(1, "setconfvalue: bar_action");
+               break;
+       case SWM_S_BAR_AT_BOTTOM:
+               bar_at_bottom = atoi(value);
+               break;
+       case SWM_S_BAR_BORDER_WIDTH:
+               bar_border_width = atoi(value);
+               if (bar_border_width < 0)
+                       bar_border_width = 0;
+               break;
        case SWM_S_BAR_DELAY:
                bar_delay = atoi(value);
                break;
        case SWM_S_BAR_ENABLED:
                bar_enabled = atoi(value);
                break;
-       case SWM_S_BAR_BORDER_WIDTH:
-               bar_border_width = atoi(value);
+       case SWM_S_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_AT_BOTTOM:
-               bar_at_bottom = atoi(value);
+       case SWM_S_BAR_FORMAT:
+               free(bar_format);
+               if ((bar_format = strdup(value)) == NULL)
+                       err(1, "setconfvalue: bar_format");
                break;
        case SWM_S_BAR_JUSTIFY:
                if (!strcmp(value, "left"))
@@ -5340,8 +5617,10 @@ setconfvalue(char *selector, char *value, int flags)
                else
                        errx(1, "invalid bar_justify");
                break;
-       case SWM_S_STACK_ENABLED:
-               stack_enabled = atoi(value);
+       case SWM_S_BORDER_WIDTH:
+               border_width = atoi(value);
+               if (border_width < 0)
+                       border_width = 0;
                break;
        case SWM_S_CLOCK_ENABLED:
                clock_enabled = atoi(value);
@@ -5359,40 +5638,13 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_CYCLE_VISIBLE:
                cycle_visible = atoi(value);
                break;
-       case SWM_S_WORKSPACE_LIMIT:
-               workspace_limit = atoi(value);
-               if (workspace_limit > SWM_WS_MAX)
-                       workspace_limit = SWM_WS_MAX;
-               else if (workspace_limit < 1)
-                       workspace_limit = 1;
-               break;
-       case SWM_S_SS_ENABLED:
-               ss_enabled = atoi(value);
-               break;
-       case SWM_S_TERM_WIDTH:
-               term_width = atoi(value);
-               break;
-       case SWM_S_TITLE_CLASS_ENABLED:
-               title_class_enabled = atoi(value);
-               break;
-       case SWM_S_WINDOW_NAME_ENABLED:
-               window_name_enabled = atoi(value);
-               break;
-       case SWM_S_TITLE_NAME_ENABLED:
-               title_name_enabled = atoi(value);
-               break;
-       case SWM_S_URGENT_ENABLED:
-               urgent_enabled = atoi(value);
+       case SWM_S_DIALOG_RATIO:
+               dialog_ratio = atof(value);
+               if (dialog_ratio > 1.0 || dialog_ratio <= .3)
+                       dialog_ratio = .6;
                break;
-       case SWM_S_FOCUS_MODE:
-               if (!strcmp(value, "default"))
-                       focus_mode = SWM_FOCUS_DEFAULT;
-               else if (!strcmp(value, "follow_cursor"))
-                       focus_mode = SWM_FOCUS_FOLLOW;
-               else if (!strcmp(value, "synergy"))
-                       focus_mode = SWM_FOCUS_SYNERGY;
-               else
-                       errx(1, "focus_mode");
+       case SWM_S_DISABLE_BORDER:
+               disable_border = atoi(value);
                break;
        case SWM_S_FOCUS_CLOSE:
                if (!strcmp(value, "first"))
@@ -5417,6 +5669,16 @@ setconfvalue(char *selector, char *value, int flags)
                else
                        errx(1, "focus_default");
                break;
+       case SWM_S_FOCUS_MODE:
+               if (!strcmp(value, "default"))
+                       focus_mode = SWM_FOCUS_DEFAULT;
+               else if (!strcmp(value, "follow_cursor"))
+                       focus_mode = SWM_FOCUS_FOLLOW;
+               else if (!strcmp(value, "synergy"))
+                       focus_mode = SWM_FOCUS_SYNERGY;
+               else
+                       errx(1, "focus_mode");
+               break;
        case SWM_S_SPAWN_ORDER:
                if (!strcmp(value, "first"))
                        spawn_position = SWM_STACK_BOTTOM;
@@ -5429,36 +5691,30 @@ setconfvalue(char *selector, char *value, int flags)
                else
                        errx(1, "spawn_position");
                break;
-       case SWM_S_DISABLE_BORDER:
-               disable_border = atoi(value);
+       case SWM_S_SPAWN_TERM:
+               setconfspawn("term", value, 0);
                break;
-       case SWM_S_BORDER_WIDTH:
-               border_width = atoi(value);
+       case SWM_S_SS_APP:
                break;
-       case SWM_S_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);
+       case SWM_S_SS_ENABLED:
+               ss_enabled = atoi(value);
                break;
-       case SWM_S_BAR_ACTION:
-               free(bar_argv[0]);
-               if ((bar_argv[0] = strdup(value)) == NULL)
-                       err(1, "setconfvalue: bar_action");
+       case SWM_S_STACK_ENABLED:
+               stack_enabled = atoi(value);
                break;
-       case SWM_S_SPAWN_TERM:
-               free(spawn_term[0]);
-               if ((spawn_term[0] = strdup(value)) == NULL)
-                       err(1, "setconfvalue: spawn_term");
+       case SWM_S_TERM_WIDTH:
+               term_width = atoi(value);
+               if (term_width < 0)
+                       term_width = 0;
                break;
-       case SWM_S_SS_APP:
+       case SWM_S_TITLE_CLASS_ENABLED:
+               title_class_enabled = atoi(value);
                break;
-       case SWM_S_DIALOG_RATIO:
-               dialog_ratio = atof(value);
-               if (dialog_ratio > 1.0 || dialog_ratio <= .3)
-                       dialog_ratio = .6;
+       case SWM_S_TITLE_NAME_ENABLED:
+               title_name_enabled = atoi(value);
+               break;
+       case SWM_S_URGENT_ENABLED:
+               urgent_enabled = atoi(value);
                break;
        case SWM_S_VERBOSE_LAYOUT:
                verbose_layout = atoi(value);
@@ -5469,6 +5725,16 @@ setconfvalue(char *selector, char *value, int flags)
                                layouts[i].l_string = plain_stacker;
                }
                break;
+       case SWM_S_WINDOW_NAME_ENABLED:
+               window_name_enabled = atoi(value);
+               break;
+       case SWM_S_WORKSPACE_LIMIT:
+               workspace_limit = atoi(value);
+               if (workspace_limit > SWM_WS_MAX)
+                       workspace_limit = SWM_WS_MAX;
+               else if (workspace_limit < 1)
+                       workspace_limit = 1;
+               break;
        default:
                return (1);
        }
@@ -5573,7 +5839,7 @@ setautorun(char *selector, char *value, int flags)
 int
 setlayout(char *selector, char *value, int flags)
 {
-       int                     ws_id, i, x, mg, ma, si, raise;
+       int                     ws_id, i, x, mg, ma, si, raise, f = 0;
        int                     st = SWM_V_STACK;
        char                    s[1024];
        struct workspace        *ws;
@@ -5593,9 +5859,15 @@ setlayout(char *selector, char *value, int flags)
 
        if (!strcasecmp(s, "vertical"))
                st = SWM_V_STACK;
-       else if (!strcasecmp(s, "horizontal"))
+       else if (!strcasecmp(s, "vertical_flip")) {
+               st = SWM_V_STACK;
+               f = 1;
+       } else if (!strcasecmp(s, "horizontal"))
                st = SWM_H_STACK;
-       else if (!strcasecmp(s, "fullscreen"))
+       else if (!strcasecmp(s, "horizontal_flip")) {
+               st = SWM_H_STACK;
+               f = 1;
+       } else if (!strcasecmp(s, "fullscreen"))
                st = SWM_MAX_STACK;
        else
                errx(1, "invalid layout entry, should be 'ws[<idx>]:"
@@ -5631,6 +5903,12 @@ setlayout(char *selector, char *value, int flags)
                            SWM_ARG_ID_STACKDEC);
                        stack();
                }
+               /* Apply flip */
+               if (f) {
+                       ws[ws_id].cur_layout->l_config(&ws[ws_id],
+                           SWM_ARG_ID_FLIPLAYOUT);
+                       stack();
+               }
        }
 
        return (0);
@@ -5653,6 +5931,7 @@ struct config_option configopt[] = {
        { "bar_action",                 setconfvalue,   SWM_S_BAR_ACTION },
        { "bar_delay",                  setconfvalue,   SWM_S_BAR_DELAY },
        { "bar_justify",                setconfvalue,   SWM_S_BAR_JUSTIFY },
+       { "bar_format",                 setconfvalue,   SWM_S_BAR_FORMAT },
        { "keyboard_mapping",           setkeymapping,  0 },
        { "bind",                       setconfbinding, 0 },
        { "stack_enabled",              setconfvalue,   SWM_S_STACK_ENABLED },
@@ -6657,7 +6936,7 @@ visibilitynotify(XEvent *e)
        if (e->xvisibility.state == VisibilityUnobscured)
                for (i = 0; i < ScreenCount(display); i++)
                        TAILQ_FOREACH(r, &screens[i].rl, entry)
-                               if (e->xvisibility.window == r->bar_window)
+                               if (e->xvisibility.window == WINID(r->bar))
                                        bar_update();
 }
 
@@ -6773,7 +7052,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h)
                        if (r->ws->r != NULL)
                                r->ws->old_r = r->ws->r;
                        r->ws->r = NULL;
-                       XDestroyWindow(display, r->bar_window);
+                       bar_cleanup(r);
                        TAILQ_REMOVE(&s->rl, r, entry);
                        TAILQ_INSERT_TAIL(&s->orl, r, entry);
                }
@@ -6844,7 +7123,7 @@ scan_xrandr(int i)
        /* remove any old regions */
        while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) {
                r->ws->old_r = r->ws->r = NULL;
-               XDestroyWindow(display, r->bar_window);
+               bar_cleanup(r);
                TAILQ_REMOVE(&screens[i].rl, r, entry);
                TAILQ_INSERT_TAIL(&screens[i].orl, r, entry);
        }
@@ -6995,12 +7274,10 @@ 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);
+               /* create graphics context on screen */
+               gcv.graphics_exposures = 0;
+               screens[i].bar_gc = XCreateGC(display, screens[i].root,
+                   GCGraphicsExposures, &gcv);
 
                /* set default cursor */
                XDefineCursor(display, screens[i].root,
@@ -7040,9 +7317,6 @@ setup_globals(void)
        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: failed to allocate memory.");
-
        if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL)
                err(1, "setup_globals: strdup: failed to allocate memory.");
 }
@@ -7173,11 +7447,9 @@ main(int argc, char *argv[])
        }
 noconfig:
 
-       /* 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);
+       /* load conf (if any) */
+       if (cfile)
+               conf_load(cfile, SWM_CONF_DEFAULT);
 
        setup_ewmh();
        /* set some values to work around bad programs */