X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=1115cacddf0d5c67f6e028466ded27f9876cc7f6;hb=d66a94fce3a9836fc2f86a111ac55c6b761411ae;hp=038b1b00ce9413c55c228cf0563fdfb0e3587f0e;hpb=a7cda44d814729d4469234c9c6ca3d5e72947a4c;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 038b1b0..1115cac 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; @@ -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) @@ -2576,6 +2829,7 @@ done: winfocus = TAILQ_FIRST(wl); } + kill_refs(win); focus_magic(winfocus); } @@ -2698,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 @@ -3313,6 +3566,7 @@ send_to_ws(struct swm_region *r, union arg *args) } stack(); + bar_update(); } void @@ -4199,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, @@ -4258,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, @@ -4290,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 *); @@ -4315,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} }, @@ -4374,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} }, @@ -4406,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) @@ -4424,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 }; @@ -4449,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 @@ -4817,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"); } @@ -4830,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 @@ -4838,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); @@ -4949,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); @@ -5101,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, @@ -5297,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) @@ -5316,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")) @@ -5338,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); @@ -5357,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")) @@ -5415,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; @@ -5427,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); @@ -5467,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); } @@ -5571,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; @@ -5591,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, "horizontal_flip")) { st = SWM_H_STACK; - else if (!strcasecmp(s, "fullscreen")) + f = 1; + } else if (!strcasecmp(s, "fullscreen")) st = SWM_MAX_STACK; else errx(1, "invalid layout entry, should be 'ws[]:" @@ -5629,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); @@ -5651,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 }, @@ -6178,8 +6459,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 @@ -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 */