X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=2ecc60f77162f6fd97c608cac2a15fe4992bff2b;hb=09526664b2bce144ef3cade500a70786a5aeaeff;hp=f6f8c9e1e5832caeef977ff444e2b5e7e8803fb5;hpb=999734e3800aa7448312aa3055780c8915163de2;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index f6f8c9e..2ecc60f 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -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; @@ -475,7 +476,6 @@ struct swm_screen { GC bar_gc; }; struct swm_screen *screens; -int num_screens; /* args to functions */ union arg { @@ -1304,7 +1304,7 @@ 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; @@ -1351,69 +1351,49 @@ 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; - Status status; - XClassHint *xch = 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); +} - if ((title_name_enabled == 1 || title_class_enabled == 1) && - cur_focus != NULL) { - if ((xch = XAllocClassHint()) == NULL) - goto out; - status = XGetClassHint(display, cur_focus->id, xch); - if (status == BadWindow || status == BadAlloc) - goto out; - do_class = (title_class_enabled && xch->res_class != NULL); - do_name = (title_name_enabled && xch->res_name != NULL); - if (do_class) - strlcat(s, xch->res_class, sz); - if (do_class && do_name) - strlcat(s, ":", sz); - if (do_name) - strlcat(s, xch->res_name, sz); - strlcat(s, " ", sz); - } -out: - if (xch) { - XFree(xch->res_name); - XFree(xch->res_class); - XFree(xch); - } +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); + + 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; @@ -1429,7 +1409,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); @@ -1437,22 +1416,237 @@ 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, " ", 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 == 0) + strlcat(fmtnew, " ", 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); + } + + if (window_name_enabled) + strlcat(fmtnew, "+64W ", 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)) */ +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 '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", r->s->idx + 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", *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) { + 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; @@ -1470,52 +1664,11 @@ 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); } void -bar_check_opts(void) -{ - if (title_class_enabled || title_name_enabled || window_name_enabled) - bar_update(); -} - -void bar_signal(int sig) { bar_alarm = 1; @@ -2246,7 +2399,7 @@ focus_win(struct ws_win *win) PropModeReplace, (unsigned char *)&win->id, 1); } - bar_check_opts(); + bar_update(); } void @@ -2298,8 +2451,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) @@ -2592,6 +2743,7 @@ done: winfocus = TAILQ_FIRST(wl); } + kill_refs(win); focus_magic(winfocus); } @@ -2714,7 +2866,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 @@ -3329,6 +3480,7 @@ send_to_ws(struct swm_region *r, union arg *args) } stack(); + bar_update(); } void @@ -4422,7 +4574,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) @@ -4440,8 +4592,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 }; @@ -4465,7 +4617,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 @@ -4833,7 +4985,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"); } @@ -4846,7 +4998,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 @@ -4854,7 +5006,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); @@ -5117,7 +5269,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, @@ -5322,7 +5474,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 @@ -5354,6 +5507,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; @@ -5667,6 +5825,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 }, @@ -6194,8 +6353,6 @@ unmanage_window(struct ws_win *win) TAILQ_REMOVE(&win->ws->winlist, win, entry); TAILQ_INSERT_TAIL(&win->ws->unmanagedlist, win, entry); - - kill_refs(win); } void @@ -6205,7 +6362,7 @@ focus_magic(struct ws_win *win) if (win == NULL) { /* if there are no windows clear the status-bar */ - bar_check_opts(); + bar_update(); return; } @@ -6618,12 +6775,8 @@ propertynotify(XEvent *e) X(win), Y(win), WIDTH(win), HEIGHT(win)); #endif case XA_WM_CLASS: - if (title_name_enabled || title_class_enabled) - bar_update(); - break; case XA_WM_NAME: - if (window_name_enabled) - bar_update(); + bar_update(); break; default: break;