diff --git a/spectrwm.1 b/spectrwm.1 index 6892daa..1c24dd3 100644 --- a/spectrwm.1 +++ b/spectrwm.1 @@ -211,6 +211,7 @@ It may contain the following character sequences: .It Li "+D" Ta "Workspace name" .It Li "+F" Ta "Floating indicator" .It Li "+I" Ta "Workspace index" +.It Li "+L" Ta "Workspace list indicator" .It Li "+M" Ta "Number of iconic (minimized) windows in workspace" .It Li "+N" Ta "Screen number" .It Li "+P" Ta "Window class and instance separated by a colon" @@ -517,6 +518,36 @@ Enable by setting to 1. Centers the pointer on the focused window when using bindings to change focus, switch workspaces, change regions, etc. Enable by setting to 1. +.It Ic workspace_indicator +Configure the status bar workspace indicator. +One or more of the following options may be specified in a comma-separated +list: +.Pp +.Bl -tag -width "markcurrentXXX" -offset indent -compact +.It Ar listcurrent +Include the current workspace. +.It Ar listactive +Include workspaces with windows. +.It Ar listempty +Include empty workspaces. +.It Ar listnamed +Include named workspaces. +.It Ar listurgent +Include workspaces with urgent window(s). +.It Ar listall +Include all workspaces. +.It Ar hidecurrent +Always exclude the current workspace from the list. +.It Ar markcurrent +Indicate the current workspace if it is in the list. +.It Ar markurgent +Indicate workspaces in the list that contain urgent window(s). +.It Ar printnames +Display the names of named workspaces in the list. +.El +.Pp +The default is +.Ar listcurrent , Ns Ar listactive , Ns Ar markcurrent , Ns Ar printnames .It Ic workspace_limit Set the total number of workspaces available. Minimum is 1, maximum is 22, default is 10. diff --git a/spectrwm.c b/spectrwm.c index a8e661b..dca16f2 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -271,6 +271,19 @@ uint32_t swm_debug = 0 #define SWM_CK_FALLBACK (0x4) #define SWM_CK_REGION (0x8) +#define SWM_WSI_LISTCURRENT (0x001) +#define SWM_WSI_LISTACTIVE (0x002) +#define SWM_WSI_LISTEMPTY (0x004) +#define SWM_WSI_LISTNAMED (0x008) +#define SWM_WSI_LISTURGENT (0x010) +#define SWM_WSI_LISTALL (0x0ff) +#define SWM_WSI_HIDECURRENT (0x100) +#define SWM_WSI_MARKCURRENT (0x200) +#define SWM_WSI_MARKURGENT (0x400) +#define SWM_WSI_PRINTNAMES (0x800) +#define SWM_WSI_DEFAULT (SWM_WSI_LISTCURRENT | SWM_WSI_LISTACTIVE | \ + SWM_WSI_MARKCURRENT | SWM_WSI_PRINTNAMES) + #define SWM_CONF_DEFAULT (0) #define SWM_CONF_KEYMAPPING (1) @@ -386,6 +399,7 @@ char *clock_format = NULL; bool window_class_enabled = false; bool window_instance_enabled = false; bool window_name_enabled = false; +uint32_t workspace_indicator = SWM_WSI_DEFAULT; int focus_mode = SWM_FOCUS_DEFAULT; int focus_close = SWM_STACK_BELOW; bool focus_close_wrap = true; @@ -1007,6 +1021,7 @@ void bar_window_float(char *, size_t, struct swm_region *); void bar_window_instance(char *, size_t, struct swm_region *); void bar_window_name(char *, size_t, struct swm_region *); void bar_window_state(char *, size_t, struct swm_region *); +void bar_workspace_indicator(char *, size_t, struct swm_region *); void bar_workspace_name(char *, size_t, struct swm_region *); int binding_cmp(struct binding *, struct binding *); void binding_insert(uint16_t, enum binding_type, uint32_t, enum actionid, @@ -1146,6 +1161,7 @@ int parse_rgb(const char *, uint16_t *, uint16_t *, uint16_t *); int parsebinding(const char *, uint16_t *, enum binding_type *, uint32_t *, uint32_t *); int parsequirks(const char *, uint32_t *, int *); +int parse_workspace_indicator(const char *, uint32_t *); void pressbutton(struct binding *, struct swm_region *, union arg *); void priorws(struct binding *, struct swm_region *, union arg *); #ifdef SWM_DEBUG @@ -2437,6 +2453,69 @@ bar_urgent(char *s, size_t sz) s[strlen(s) - 1] = 0; } +void +bar_workspace_indicator(char *s, size_t sz, struct swm_region *r) +{ + struct ws_win *w; + struct workspace *ws; + int i, count = 0; + char tmp[SWM_BAR_MAX], *mark; + bool current, active, named, urgent, collapse; + + if (r == NULL) + return; + + for (i = 0; i < workspace_limit; i++) { + ws = &r->s->ws[i]; + + current = (ws == r->ws); + named = (ws->name != NULL); + urgent = false; + active = false; + TAILQ_FOREACH(w, &ws->winlist, entry) { + active = true; + /* Only get urgent if needed. */ + if (!(workspace_indicator & SWM_WSI_LISTURGENT || + workspace_indicator & SWM_WSI_MARKURGENT) || + (urgent = get_urgent(w))) + break; + } + + collapse = !(workspace_indicator & SWM_WSI_MARKCURRENT || + workspace_indicator & SWM_WSI_MARKURGENT); + + if (!(current && workspace_indicator & SWM_WSI_HIDECURRENT) && + ((current && workspace_indicator & SWM_WSI_LISTCURRENT) || + (active && workspace_indicator & SWM_WSI_LISTACTIVE) || + (!active && workspace_indicator & SWM_WSI_LISTEMPTY) || + (urgent && workspace_indicator & SWM_WSI_LISTURGENT) || + (named && workspace_indicator & SWM_WSI_LISTNAMED))) { + if (count > 0) + strlcat(s, " ", sz); + + if (current && + workspace_indicator & SWM_WSI_MARKCURRENT) + mark = "*"; + else if (urgent && workspace_indicator & + SWM_WSI_MARKURGENT) + mark = "!"; + else if (!collapse) + mark = " "; + else + mark = ""; + strlcat(s, mark, sz); + + if (named && workspace_indicator & SWM_WSI_PRINTNAMES) + snprintf(tmp, sizeof tmp, "%d:%s", ws->idx + 1, + ws->name); + else + snprintf(tmp, sizeof tmp, "%d", ws->idx + 1); + strlcat(s, tmp, sz); + count++; + } + } +} + void bar_workspace_name(char *s, size_t sz, struct swm_region *r) { @@ -2581,6 +2660,9 @@ bar_replace_seq(char *fmt, char *fmtrep, struct swm_region *r, size_t *offrep, case 'I': snprintf(tmp, sizeof tmp, "%d", r->ws->idx + 1); break; + case 'L': + bar_workspace_indicator(tmp, sizeof tmp, r); + break; case 'M': count = 0; TAILQ_FOREACH(w, &r->ws->winlist, entry) @@ -8650,6 +8732,62 @@ grabbuttons(void) DNPRINTF(SWM_D_MOUSE, "done\n"); } +struct wsi_flag { + char *name; + uint32_t mask; +} wsiflags[] = { + {"listcurrent", SWM_WSI_LISTCURRENT}, + {"listactive", SWM_WSI_LISTACTIVE}, + {"listempty", SWM_WSI_LISTEMPTY}, + {"listnamed", SWM_WSI_LISTNAMED}, + {"listurgent", SWM_WSI_LISTURGENT}, + {"listall", SWM_WSI_LISTALL}, + {"hidecurrent", SWM_WSI_HIDECURRENT}, + {"markcurrent", SWM_WSI_MARKCURRENT}, + {"markurgent", SWM_WSI_MARKURGENT}, + {"printnames", SWM_WSI_PRINTNAMES}, +}; + +#define SWM_FLAGS_DELIM "," +#define SWM_FLAGS_WHITESPACE " \t\n" +int +parse_workspace_indicator(const char *str, uint32_t *mode) +{ + char *tmp, *cp, *name; + size_t len; + int i; + + if (str == NULL || mode == NULL) + return (1); + + if ((cp = tmp = strdup(str)) == NULL) + err(1, "parse_workspace_indicator: strdup"); + + *mode = 0; + while ((name = strsep(&cp, SWM_FLAGS_DELIM)) != NULL) { + if (cp) + cp += (long)strspn(cp, SWM_FLAGS_WHITESPACE); + name += strspn(name, SWM_FLAGS_WHITESPACE); + len = strcspn(name, SWM_FLAGS_WHITESPACE); + + for (i = 0; i < LENGTH(wsiflags); i++) { + if (strncasecmp(name, wsiflags[i].name, len) == 0) { + DNPRINTF(SWM_D_CONF, "flag: [%s]\n", name); + *mode |= wsiflags[i].mask; + break; + } + } + if (i >= LENGTH(wsiflags)) { + DNPRINTF(SWM_D_CONF, "invalid flag: [%s]\n", name); + free(tmp); + return (1); + } + } + + free(tmp); + return (0); +} + const char *quirkname[] = { "NONE", /* config string for "no value" */ "FLOAT", @@ -9001,6 +9139,7 @@ enum { SWM_S_WINDOW_NAME_ENABLED, SWM_S_WORKSPACE_CLAMP, SWM_S_WORKSPACE_LIMIT, + SWM_S_WORKSPACE_INDICATOR, SWM_S_WORKSPACE_NAME, }; @@ -9229,6 +9368,10 @@ setconfvalue(const char *selector, const char *value, int flags) ewmh_update_desktops(); break; + case SWM_S_WORKSPACE_INDICATOR: + if (parse_workspace_indicator(value, &workspace_indicator)) + errx(1, "invalid workspace_indicator"); + break; case SWM_S_WORKSPACE_NAME: if (getenv("SWM_STARTED") != NULL) return (0); @@ -9576,6 +9719,7 @@ struct config_option configopt[] = { { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, { "workspace_clamp", setconfvalue, SWM_S_WORKSPACE_CLAMP }, { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, + { "workspace_indicator", setconfvalue, SWM_S_WORKSPACE_INDICATOR }, { "name", setconfvalue, SWM_S_WORKSPACE_NAME }, }; diff --git a/spectrwm.conf b/spectrwm.conf index 77e2651..a7e3e6b 100644 --- a/spectrwm.conf +++ b/spectrwm.conf @@ -42,6 +42,7 @@ # bar_action = baraction.sh # bar_justify = left # bar_format = +N:+I +S <+D>+4<%a %b %d %R %Z %Y+8<+A+4<+V +# workspace_indicator = listcurrent,listactive,markcurrent,printnames # bar_at_bottom = 1 # stack_enabled = 1 # clock_enabled = 1