JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Add the ability to format the status-bar output.
authorTiago Cunha <tcunha@gmx.com>
Sun, 13 May 2012 00:33:38 +0000 (01:33 +0100)
committerTiago Cunha <tcunha@gmx.com>
Tue, 5 Jun 2012 21:32:01 +0000 (22:32 +0100)
Introduced the new bar_format configuration file keyword that allows to
customize the status-bar by providing character sequences that are
replaced accordingly, effectively supplanting the enabled options. The
default output is retained, though.

Idea taken from tmux(1).

spectrwm.1
spectrwm.c
spectrwm.conf

index 778ec69..1d14842 100644 (file)
@@ -103,6 +103,30 @@ Status bar font.
 .It Ic bar_font_color Ns Bq Ar x
 Color of the font in status bar in screen
 .Ar x .
+.It Ic bar_format
+Set the bar_format string and override all of the
+.Ic enabled
+options.
+The format is passed through
+.Xr strftime 3
+before being used.
+It may contain the following character sequences:
+.Bl -column "Character sequence" "Replaced with" -offset indent
+.It Sy "Character sequence" Ta Sy "Replaced with"
+.It Li "+A" Ta "Output of the external script"
+.It Li "+C" Ta "Window class"
+.It Li "+D" Ta "Workspace name"
+.It Li "+I" Ta "Workspace index"
+.It Li "+N" Ta "Screen number"
+.It Li "+S" Ta "Stacking algorithm"
+.It Li "+T" Ta "Window title"
+.It Li "+U" Ta "Urgency hint"
+.It Li "+V" Ta "Program version"
+.It Li "+W" Ta "Window name"
+.It Li "++" Ta "A literal" Ql +
+.El
+.Pp
+Any characters that don't match the specification are copied as-is.
 .It Ic bar_justify
 Justify the status bar text. Possible values are
 .Pa left ,
index 7f2123d..7a0ccf2 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;
@@ -1350,61 +1351,50 @@ 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 (title_name_enabled == 0 && title_class_enabled == 0)
-               return;
-       if (cur_focus == NULL)
+       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);
+}
 
-       ch = &cur_focus->ch;
-       do_class = (title_class_enabled && ch->res_class != NULL);
-       do_name = (title_name_enabled && ch->res_name != NULL);
-
-       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_title_name(char *s, size_t sz, struct swm_region *r)
+{
+       if (r == NULL || r->ws == NULL || r->ws->focus == NULL)
+               return;
+       if (r->ws->focus->ch.res_name != NULL)
+               strlcat(s, r->ws->focus->ch.res_name, 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;
+
+       if (r->ws->focus->floating)
+               strlcat(s, "(f) ", sz);
+       strlcat(s, (char *)title, sz);
+       strlcat(s, " ", 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 +1410,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 +1417,195 @@ 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(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, "   ", sz);
+
+       if (clock_enabled) {
+               strlcat(fmtnew, fmtexp, sz);
+               strlcat(fmtnew, "    ", sz);
+       }
+
+       /* bar_urgent already adds the space before the last asterisk */
+       if (urgent_enabled)
+               strlcat(fmtnew, "* +U*    ", sz);
+
+       if (title_class_enabled)
+               strlcat(fmtnew, "+C", sz);
+       if (title_name_enabled) {
+               /* add a colon if showing the class and something is focused */
+               if (title_class_enabled && r != NULL && r->ws != NULL &&
+                   r->ws->focus != NULL)
+                       strlcat(fmtnew, ":", sz);
+               strlcat(fmtnew, "+T", sz);
+       }
+
+       strlcat(fmtnew, "    ", sz);
+       if (window_name_enabled)
+               strlcat(fmtnew, "+W", sz);
+
+       /* finally add the action script output and the version */
+       strlcat(fmtnew, "     +A    +V", sz);
+}
+
+/* replaces the bar format character sequences (like in tmux(1)) */
+void
+bar_replace(char *fmt, char *fmtrep, int nscreen, struct swm_region *r,
+    size_t sz)
+{
+       char                    *ptr;
+       char                    tmp[SWM_BAR_MAX];
+       size_t                  off;
+
+       off = 0;
+       ptr = fmt;
+       while (*ptr != '\0') {
+               if (*ptr != '+') {
+                       /* skip ordinary characters */
+                       if (off >= sz - 1)
+                               break;
+                       fmtrep[off++] = *ptr++;
+                       continue;
+               }
+
+               /* character sequence found; replace it */
+               *tmp = '\0';
+
+               switch (*++ptr) {
+               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 'I':
+                       snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1);
+                       break;
+               case 'N':
+                       snprintf(tmp, sizeof tmp, "%d", nscreen + 1);
+                       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", *ptr);
+                       break;
+               }
+
+               off += snprintf(fmtrep + off, sz - off, "%s", tmp);
+               if (off >= sz - 1) {
+                       off = sz;
+                       break;
+               }
+               ptr++;
+       }
+
+       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
+       len = strftime(fmtexp, sz, fmt, &tm);
+       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) {
+                       bar_fmt(fmtexp, fmtnew, r, sizeof fmtnew);
+                       bar_replace(fmtnew, fmtrep, i, 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 +1623,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);
 }
 
@@ -5305,7 +5433,8 @@ enum      { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH,
          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
+         SWM_S_BAR_AT_BOTTOM, SWM_S_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY,
+         SWM_S_BAR_FORMAT
        };
 
 int
@@ -5337,6 +5466,11 @@ setconfvalue(char *selector, char *value, int flags)
                else
                        errx(1, "invalid bar_justify");
                break;
+       case SWM_S_BAR_FORMAT:
+               free(bar_format);
+               if ((bar_format = strdup(value)) == NULL)
+                       err(1, "setconfvalue: bar_format");
+               break;
        case SWM_S_STACK_ENABLED:
                stack_enabled = atoi(value);
                break;
@@ -5650,6 +5784,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 },
index 1207290..acdfb2d 100644 (file)
@@ -27,6 +27,7 @@
 # bar_action           = baraction.sh
 # bar_delay            = 1
 # bar_justify          = left
+# bar_format           = +N:+I +S <+D>   %a %b %d %R %Z %Y             +A    +V
 # bar_at_bottom                = 1
 # stack_enabled                = 1
 # clock_enabled                = 1