X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=spectrwm.c;h=51f2f9a6ebf60811d5b6b4113a79320a35737500;hb=98fcba2bdb01c5950e75ce37fba4a42ea88f8031;hp=02be1c50df35a78d36d85a13228a395e09a3fe48;hpb=0cf556e88932d5f98b79f9e4cce54a6ebb3f17a9;p=spectrwm.git diff --git a/spectrwm.c b/spectrwm.c index 02be1c5..51f2f9a 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -88,6 +88,7 @@ #include #include +#include #include #include #include @@ -240,8 +241,7 @@ struct search_window { Window indicator; }; TAILQ_HEAD(search_winlist, search_window); - -struct search_winlist search_wl; +struct search_winlist search_wl; /* search actions */ enum { @@ -252,6 +252,11 @@ enum { SWM_SEARCH_SEARCH_WINDOW }; +#define SWM_STACK_TOP (0) +#define SWM_STACK_BOTTOM (1) +#define SWM_STACK_ABOVE (2) +#define SWM_STACK_BELOW (3) + /* dialog windows */ double dialog_ratio = 0.6; /* status bar */ @@ -263,7 +268,8 @@ double dialog_ratio = 0.6; #define SWM_BAR_FONTS "-*-terminus-medium-*-*-*-*-*-*-*-*-*-*-*," \ "-*-profont-*-*-*-*-*-*-*-*-*-*-*-*," \ "-*-times-medium-r-*-*-*-*-*-*-*-*-*-*," \ - "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*" + "-misc-fixed-medium-r-*-*-*-*-*-*-*-*-*-*," \ + "-*-*-*-r-*--*-*-*-*-*-*-*-*" #ifdef X_HAVE_UTF8_STRING #define DRAWSTRING(x...) Xutf8DrawString(x) @@ -286,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; @@ -294,6 +301,10 @@ int title_name_enabled = 0; int title_class_enabled = 0; int window_name_enabled = 0; int focus_mode = SWM_FOCUS_DEFAULT; +int focus_close = SWM_STACK_BELOW; +int focus_close_wrap = 1; +int focus_default = SWM_STACK_TOP; +int spawn_position = SWM_STACK_TOP; int disable_border = 0; int border_width = 1; int verbose_layout = 0; @@ -446,7 +457,9 @@ 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 (10) +#define SWM_WS_MAX (22) /* hard limit */ +int workspace_limit = 10; /* soft limit */ + struct swm_screen { int idx; /* screen index */ struct swm_region_list rl; /* list of regions on this screen */ @@ -463,7 +476,6 @@ struct swm_screen { GC bar_gc; }; struct swm_screen *screens; -int num_screens; /* args to functions */ union arg { @@ -595,11 +607,11 @@ get_property(Window id, Atom atom, long count, Atom type, unsigned long *nitems, &real, &format, nitems_ret, nbytes_ret, data); if (status != Success) - return False; + return (False); if (real != type) - return False; + return (False); - return True; + return (True); } void @@ -667,7 +679,7 @@ setup_ewmh(void) for (j = 0; j < LENGTH(ewmh); j++) XChangeProperty(display, screens[i].root, sup_list, XA_ATOM, 32, - PropModeAppend, (unsigned char *)&ewmh[j].atom,1); + PropModeAppend, (unsigned char *)&ewmh[j].atom, 1); } } @@ -750,10 +762,10 @@ ewmh_set_win_fullscreen(struct ws_win *win, int fs) struct swm_geometry rg; if (!win->ws->r) - return 0; + return (0); if (!win->floating) - return 0; + return (0); DNPRINTF(SWM_D_MISC, "ewmh_set_win_fullscreen: window: 0x%lx, " "fullscreen %s\n", win->id, YESNO(fs)); @@ -774,7 +786,7 @@ ewmh_set_win_fullscreen(struct ws_win *win, int fs) } } - return 1; + return (1); } void @@ -1015,7 +1027,7 @@ geteventname(XEvent *e) name = "Unknown"; } - return name; + return (name); } char * @@ -1031,7 +1043,7 @@ xrandr_geteventname(XEvent *e) name = "Unknown"; } - return name; + return (name); } void @@ -1339,74 +1351,55 @@ 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); + 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 < SWM_WS_MAX; i++) + for (i = 0; i < workspace_limit; i++) urgent[i] = 0; for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { wmh = XGetWMHints(display, win->id); if (wmh == NULL) @@ -1417,30 +1410,241 @@ bar_urgent(char *s, ssize_t sz) XFree(wmh); } - strlcat(s, "* ", sz); - for (i = 0; i < SWM_WS_MAX; i++) { + for (i = 0; i < workspace_limit; i++) { if (urgent[i]) snprintf(b, sizeof b, "%d ", i + 1); else 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)) */ +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; @@ -1458,52 +1662,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; @@ -1847,7 +2010,7 @@ unmap_all(void) int i, j; for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) unmap_window(win); } @@ -1936,7 +2099,7 @@ find_unmanaged_window(Window id) int i, j; for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].unmanagedlist, entry) if (id == win->id) @@ -1953,7 +2116,7 @@ find_window(Window id) unsigned int nc; for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) if (id == win->id) return (win); @@ -1970,7 +2133,7 @@ find_window(Window id) /* look for parent */ for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) if (wpr == win->id) return (win); @@ -2058,7 +2221,7 @@ kill_refs(struct ws_win *win) for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { + for (x = 0; x < workspace_limit; x++) { ws = &r->s->ws[x]; if (win == ws->focus) ws->focus = NULL; @@ -2080,7 +2243,7 @@ validate_win(struct ws_win *testwin) for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { + for (x = 0; x < workspace_limit; x++) { ws = &r->s->ws[x]; TAILQ_FOREACH(win, &ws->winlist, entry) if (win == testwin) @@ -2099,7 +2262,7 @@ validate_ws(struct workspace *testws) /* validate all ws */ for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) - for (x = 0; x < SWM_WS_MAX; x++) { + for (x = 0; x < workspace_limit; x++) { ws = &r->s->ws[x]; if (ws == testws) return (0); @@ -2155,7 +2318,7 @@ unfocus_win(struct ws_win *win) XChangeProperty(display, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&none,1); + PropModeReplace, (unsigned char *)&none, 1); } void @@ -2167,7 +2330,7 @@ unfocus_all(void) DNPRINTF(SWM_D_FOCUS, "unfocus_all\n"); for (i = 0; i < ScreenCount(display); i++) - for (j = 0; j < SWM_WS_MAX; j++) + for (j = 0; j < workspace_limit; j++) TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) unfocus_win(win); } @@ -2231,10 +2394,10 @@ focus_win(struct ws_win *win) XChangeProperty(display, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win->id,1); + PropModeReplace, (unsigned char *)&win->id, 1); } - bar_check_opts(); + bar_update(); } void @@ -2249,6 +2412,9 @@ switchws(struct swm_region *r, union arg *args) if (!(r && r->s)) return; + if (wsid >= workspace_limit) + return; + this_r = r; old_ws = this_r->ws; new_ws = &this_r->s->ws[wsid]; @@ -2283,8 +2449,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) @@ -2311,7 +2475,7 @@ cyclews(struct swm_region *r, union arg *args) cycle_all = 1; /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_UP: - if (a.id < SWM_WS_MAX - 1) + if (a.id < workspace_limit - 1) a.id++; else a.id = 0; @@ -2323,7 +2487,7 @@ cyclews(struct swm_region *r, union arg *args) if (a.id > 0) a.id--; else - a.id = SWM_WS_MAX - 1; + a.id = workspace_limit - 1; break; default: return; @@ -2469,7 +2633,6 @@ swapwin(struct swm_region *r, union arg *args) if (target == source) { if (source->ws->focus_prev != NULL && source->ws->focus_prev != target) - source = source->ws->focus_prev; else return; @@ -2504,8 +2667,6 @@ focus_prev(struct ws_win *win) struct ws_win_list *wl = NULL; struct workspace *ws = NULL; - DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%lx\n", WINID(win)); - if (!(win && win->ws)) return; @@ -2513,14 +2674,15 @@ focus_prev(struct ws_win *win) wl = &ws->winlist; cur_focus = ws->focus; + DNPRINTF(SWM_D_FOCUS, "focus_prev: window: 0x%lx, cur_focus: 0x%lx\n", + WINID(win), WINID(cur_focus)); + /* pickle, just focus on whatever */ if (cur_focus == NULL) { /* use prev_focus if valid */ if (ws->focus_prev && ws->focus_prev != cur_focus && find_window(WINID(ws->focus_prev))) winfocus = ws->focus_prev; - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); goto done; } @@ -2541,14 +2703,45 @@ focus_prev(struct ws_win *win) goto done; } - if (cur_focus == win) - winfocus = TAILQ_PREV(win, ws_win_list, entry); - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); - if (winfocus == NULL || winfocus == win) - winfocus = TAILQ_NEXT(cur_focus, entry); + DNPRINTF(SWM_D_FOCUS, "focus_prev: focus_close: %d\n", focus_close); + if (winfocus == NULL || winfocus == win) { + switch (focus_close) { + case SWM_STACK_BOTTOM: + winfocus = TAILQ_FIRST(wl); + break; + case SWM_STACK_TOP: + winfocus = TAILQ_LAST(wl, ws_win_list); + break; + case SWM_STACK_ABOVE: + if ((winfocus = TAILQ_NEXT(cur_focus, entry)) == NULL) { + if (focus_close_wrap) + winfocus = TAILQ_FIRST(wl); + else + winfocus = TAILQ_PREV(cur_focus, + ws_win_list, entry); + } + break; + case SWM_STACK_BELOW: + if ((winfocus = TAILQ_PREV(cur_focus, ws_win_list, + entry)) == NULL) { + if (focus_close_wrap) + winfocus = TAILQ_LAST(wl, ws_win_list); + else + winfocus = TAILQ_NEXT(cur_focus, entry); + } + break; + } + } done: + if (winfocus == NULL) { + if (focus_default == SWM_STACK_TOP) + winfocus = TAILQ_LAST(wl, ws_win_list); + else + winfocus = TAILQ_FIRST(wl); + } + + kill_refs(win); focus_magic(winfocus); } @@ -2671,7 +2864,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 @@ -2918,9 +3110,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip) if (w_inc > 1 && w_inc < v_slice) { /* adjust for window's requested size increment */ remain = (win_g.w - w_base) % w_inc; - missing = w_inc - remain; win_g.w -= remain; - extra += remain; } msize = win_g.w; @@ -3241,6 +3431,9 @@ send_to_ws(struct swm_region *r, union arg *args) unsigned char ws_idx_str[SWM_PROPLEN]; union arg a; + if (wsid >= workspace_limit) + return; + if (r && r->ws && r->ws->focus) win = r->ws->focus; else @@ -3285,6 +3478,7 @@ send_to_ws(struct swm_region *r, union arg *args) } stack(); + bar_update(); } void @@ -3297,7 +3491,7 @@ pressbutton(struct swm_region *r, union arg *args) void raise_toggle(struct swm_region *r, union arg *args) { - if (r && r->ws == NULL) + if (r == NULL || r->ws == NULL) return; r->ws->always_raise = !r->ws->always_raise; @@ -3359,7 +3553,7 @@ uniconify(struct swm_region *r, union arg *args) DNPRINTF(SWM_D_MISC, "uniconify\n"); - if (r && r->ws == NULL) + if (r == NULL || r->ws == NULL) return; /* make sure we have anything to uniconify */ @@ -3439,7 +3633,7 @@ search_workspace(struct swm_region *r, union arg *args) if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) return; - for (i = 0; i < SWM_WS_MAX; i++) { + for (i = 0; i < workspace_limit; i++) { ws = &r->s->ws[i]; if (ws == NULL) continue; @@ -3607,7 +3801,7 @@ search_resp_search_workspace(char *resp, unsigned long len) p = strchr(q, ':'); if (p != NULL) *p = '\0'; - ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr); + ws_idx = strtonum(q, 1, workspace_limit, &errstr); if (errstr) { DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s", errstr, q); @@ -3731,16 +3925,16 @@ floating_toggle_win(struct ws_win *win) struct swm_region *r; if (win == NULL) - return 0; + return (0); if (!win->ws->r) - return 0; + return (0); r = win->ws->r; /* reject floating toggles in max stack mode */ if (win->ws->cur_layout == &layouts[SWM_MAX_STACK]) - return 0; + return (0); if (win->floating) { if (!win->floatmaxed) { @@ -3761,7 +3955,7 @@ floating_toggle_win(struct ws_win *win) ewmh_update_actions(win); - return 1; + return (1); } void @@ -4186,6 +4380,18 @@ enum keyfuncid { kf_ws_8, kf_ws_9, kf_ws_10, + kf_ws_11, + kf_ws_12, + kf_ws_13, + kf_ws_14, + kf_ws_15, + kf_ws_16, + kf_ws_17, + kf_ws_18, + kf_ws_19, + kf_ws_20, + kf_ws_21, + kf_ws_22, kf_ws_next, kf_ws_prev, kf_ws_next_all, @@ -4203,6 +4409,18 @@ enum keyfuncid { kf_mvws_8, kf_mvws_9, kf_mvws_10, + kf_mvws_11, + kf_mvws_12, + kf_mvws_13, + kf_mvws_14, + kf_mvws_15, + kf_mvws_16, + kf_mvws_17, + kf_mvws_18, + kf_mvws_19, + kf_mvws_20, + kf_mvws_21, + kf_mvws_22, kf_bar_toggle, kf_wind_kill, kf_wind_del, @@ -4278,6 +4496,18 @@ struct keyfunc { { "ws_8", switchws, {.id = 7} }, { "ws_9", switchws, {.id = 8} }, { "ws_10", switchws, {.id = 9} }, + { "ws_11", switchws, {.id = 10} }, + { "ws_12", switchws, {.id = 11} }, + { "ws_13", switchws, {.id = 12} }, + { "ws_14", switchws, {.id = 13} }, + { "ws_15", switchws, {.id = 14} }, + { "ws_16", switchws, {.id = 15} }, + { "ws_17", switchws, {.id = 16} }, + { "ws_18", switchws, {.id = 17} }, + { "ws_19", switchws, {.id = 18} }, + { "ws_20", switchws, {.id = 19} }, + { "ws_21", switchws, {.id = 20} }, + { "ws_22", switchws, {.id = 21} }, { "ws_next", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP} }, { "ws_prev", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN} }, { "ws_next_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_UP_ALL} }, @@ -4295,6 +4525,18 @@ struct keyfunc { { "mvws_8", send_to_ws, {.id = 7} }, { "mvws_9", send_to_ws, {.id = 8} }, { "mvws_10", send_to_ws, {.id = 9} }, + { "mvws_11", send_to_ws, {.id = 10} }, + { "mvws_12", send_to_ws, {.id = 11} }, + { "mvws_13", send_to_ws, {.id = 12} }, + { "mvws_14", send_to_ws, {.id = 13} }, + { "mvws_15", send_to_ws, {.id = 14} }, + { "mvws_16", send_to_ws, {.id = 15} }, + { "mvws_17", send_to_ws, {.id = 16} }, + { "mvws_18", send_to_ws, {.id = 17} }, + { "mvws_19", send_to_ws, {.id = 18} }, + { "mvws_20", send_to_ws, {.id = 19} }, + { "mvws_21", send_to_ws, {.id = 20} }, + { "mvws_22", send_to_ws, {.id = 21} }, { "bar_toggle", bar_toggle, {0} }, { "wind_kill", wkill, {.id = SWM_ARG_ID_KILLWINDOW} }, { "wind_del", wkill, {.id = SWM_ARG_ID_DELETEWINDOW} }, @@ -4888,6 +5130,18 @@ setup_keys(void) setkeybinding(MODKEY, XK_8, kf_ws_8, NULL); setkeybinding(MODKEY, XK_9, kf_ws_9, NULL); setkeybinding(MODKEY, XK_0, kf_ws_10, NULL); + setkeybinding(MODKEY, XK_F1, kf_ws_11, NULL); + setkeybinding(MODKEY, XK_F2, kf_ws_12, NULL); + setkeybinding(MODKEY, XK_F3, kf_ws_13, NULL); + setkeybinding(MODKEY, XK_F4, kf_ws_14, NULL); + setkeybinding(MODKEY, XK_F5, kf_ws_15, NULL); + setkeybinding(MODKEY, XK_F6, kf_ws_16, NULL); + setkeybinding(MODKEY, XK_F7, kf_ws_17, NULL); + setkeybinding(MODKEY, XK_F8, kf_ws_18, NULL); + setkeybinding(MODKEY, XK_F9, kf_ws_19, NULL); + setkeybinding(MODKEY, XK_F10, kf_ws_20, NULL); + setkeybinding(MODKEY, XK_F11, kf_ws_21, NULL); + setkeybinding(MODKEY, XK_F12, kf_ws_22, NULL); setkeybinding(MODKEY, XK_Right, kf_ws_next, NULL); setkeybinding(MODKEY, XK_Left, kf_ws_prev, NULL); setkeybinding(MODKEY, XK_Up, kf_ws_next_all, NULL); @@ -4905,6 +5159,18 @@ setup_keys(void) setkeybinding(MODKEY|ShiftMask, XK_8, kf_mvws_8, NULL); setkeybinding(MODKEY|ShiftMask, XK_9, kf_mvws_9, NULL); setkeybinding(MODKEY|ShiftMask, XK_0, kf_mvws_10, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F1, kf_mvws_11, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F2, kf_mvws_12, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F3, kf_mvws_13, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F4, kf_mvws_14, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F5, kf_mvws_15, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F6, kf_mvws_16, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F7, kf_mvws_17, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F8, kf_mvws_18, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F9, kf_mvws_19, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F10, kf_mvws_20, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F11, kf_mvws_21, NULL); + setkeybinding(MODKEY|ShiftMask, XK_F12, kf_mvws_22, NULL); setkeybinding(MODKEY, XK_b, kf_bar_toggle, NULL); setkeybinding(MODKEY, XK_Tab, kf_focus_next, NULL); setkeybinding(MODKEY|ShiftMask, XK_Tab, kf_focus_prev, NULL); @@ -5199,13 +5465,15 @@ setup_quirks(void) 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_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_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_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, + SWM_S_BAR_FORMAT }; int @@ -5237,6 +5505,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; @@ -5256,6 +5529,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; @@ -5284,6 +5564,41 @@ setconfvalue(char *selector, char *value, int flags) else errx(1, "focus_mode"); break; + case SWM_S_FOCUS_CLOSE: + if (!strcmp(value, "first")) + focus_close = SWM_STACK_BOTTOM; + else if (!strcmp(value, "last")) + focus_close = SWM_STACK_TOP; + else if (!strcmp(value, "next")) + focus_close = SWM_STACK_ABOVE; + else if (!strcmp(value, "previous")) + focus_close = SWM_STACK_BELOW; + else + errx(1, "focus_close"); + break; + case SWM_S_FOCUS_CLOSE_WRAP: + focus_close_wrap = atoi(value); + break; + case SWM_S_FOCUS_DEFAULT: + if (!strcmp(value, "last")) + focus_default = SWM_STACK_TOP; + else if (!strcmp(value, "first")) + focus_default = SWM_STACK_BOTTOM; + else + errx(1, "focus_default"); + break; + case SWM_S_SPAWN_ORDER: + if (!strcmp(value, "first")) + spawn_position = SWM_STACK_BOTTOM; + else if (!strcmp(value, "last")) + spawn_position = SWM_STACK_TOP; + else if (!strcmp(value, "next")) + spawn_position = SWM_STACK_ABOVE; + else if (!strcmp(value, "previous")) + spawn_position = SWM_STACK_BELOW; + else + errx(1, "spawn_position"); + break; case SWM_S_DISABLE_BORDER: disable_border = atoi(value); break; @@ -5378,7 +5693,7 @@ setautorun(char *selector, char *value, int flags) if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) errx(1, "invalid autorun entry, should be 'ws[]:command'"); ws_id--; - if (ws_id < 0 || ws_id >= SWM_WS_MAX) + if (ws_id < 0 || ws_id >= workspace_limit) errx(1, "autorun: invalid workspace %d", ws_id + 1); /* @@ -5443,7 +5758,7 @@ setlayout(char *selector, char *value, int flags) "::::" "'"); ws_id--; - if (ws_id < 0 || ws_id >= SWM_WS_MAX) + if (ws_id < 0 || ws_id >= workspace_limit) errx(1, "layout: invalid workspace %d", ws_id + 1); if (!strcasecmp(s, "vertical")) @@ -5508,6 +5823,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 }, @@ -5517,6 +5833,7 @@ struct config_option configopt[] = { { "color_unfocus", setconfcolor, SWM_S_COLOR_UNFOCUS }, { "cycle_empty", setconfvalue, SWM_S_CYCLE_EMPTY }, { "cycle_visible", setconfvalue, SWM_S_CYCLE_VISIBLE }, + { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, { "dialog_ratio", setconfvalue, SWM_S_DIALOG_RATIO }, { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, { "modkey", setconfmodkey, 0 }, @@ -5532,6 +5849,10 @@ struct config_option configopt[] = { { "title_class_enabled", setconfvalue, SWM_S_TITLE_CLASS_ENABLED }, { "title_name_enabled", setconfvalue, SWM_S_TITLE_NAME_ENABLED }, { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, + { "focus_close", setconfvalue, SWM_S_FOCUS_CLOSE }, + { "focus_close_wrap", setconfvalue, SWM_S_FOCUS_CLOSE_WRAP }, + { "focus_default", setconfvalue, SWM_S_FOCUS_DEFAULT }, + { "spawn_position", setconfvalue, SWM_S_SPAWN_ORDER }, { "disable_border", setconfvalue, SWM_S_DISABLE_BORDER }, { "border_width", setconfvalue, SWM_S_BORDER_WIDTH }, { "autorun", setautorun, 0 }, @@ -5757,7 +6078,7 @@ manage_window(Window id) Atom *prot = NULL, *pp; unsigned char ws_idx_str[SWM_PROPLEN], *prop = NULL; struct swm_region *r; - long mask; + long mask = 0; const char *errstr; XWindowChanges wc; struct pid_e *p; @@ -5771,12 +6092,27 @@ manage_window(Window id) DNPRINTF(SWM_D_MISC, "manage_window: previously unmanaged " "window: 0x%lx\n", win->id); TAILQ_REMOVE(&win->ws->unmanagedlist, win, entry); - if (win->transient) { + if (win->transient) set_child_transient(win, &trans); - } if (trans && (ww = find_window(trans))) + + if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); - else + else if ((ww = win->ws->focus) && + spawn_position == SWM_STACK_ABOVE) + TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, entry); + else if (ww && spawn_position == SWM_STACK_BELOW) + TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, entry); + else switch (spawn_position) { + default: + case SWM_STACK_TOP: + case SWM_STACK_ABOVE: TAILQ_INSERT_TAIL(&win->ws->winlist, win, entry); + break; + case SWM_STACK_BOTTOM: + case SWM_STACK_BELOW: + TAILQ_INSERT_HEAD(&win->ws->winlist, win, entry); + } + ewmh_update_actions(win); return (win); } @@ -5834,7 +6170,8 @@ manage_window(Window id) p = NULL; } else if (prop && win->transient == 0) { DNPRINTF(SWM_D_PROP, "manage_window: get _SWM_WS: %s\n", prop); - ws_idx = strtonum((const char *)prop, 0, 9, &errstr); + ws_idx = strtonum((const char *)prop, 0, workspace_limit - 1, + &errstr); if (errstr) { DNPRINTF(SWM_D_EVENT, "manage_window: window: #%s: %s", errstr, prop); @@ -5862,6 +6199,8 @@ manage_window(Window id) win->s = r->s; /* this never changes */ if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&ws->winlist, ww, win, entry); + else if (spawn_position == SWM_STACK_ABOVE && win->ws->focus) + TAILQ_INSERT_AFTER(&win->ws->winlist, win->ws->focus, win, entry); else TAILQ_INSERT_TAIL(&ws->winlist, win, entry); @@ -5944,7 +6283,7 @@ manage_window(Window id) if (border_me) { bzero(&wc, sizeof wc); wc.border_width = border_width; - mask = CWBorderWidth; + mask |= CWBorderWidth; XConfigureWindow(display, win->id, mask, &wc); } @@ -6012,8 +6351,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 @@ -6023,7 +6360,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; } @@ -6068,7 +6405,7 @@ keypress(XEvent *e) struct key *kp; struct swm_region *r; - keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); + keysym = XkbKeycodeToKeysym(display, (KeyCode)ev->keycode, 0, 0); if ((kp = key_lookup(CLEANMASK(ev->state), keysym)) == NULL) return; if (keyfuncs[kp->funcid].func == NULL) @@ -6126,9 +6463,8 @@ configurerequest(XEvent *e) wc.sibling = ev->above; wc.stack_mode = ev->detail; XConfigureWindow(display, ev->window, ev->value_mask, &wc); - } else { + } else config_win(win, ev); - } } void @@ -6350,6 +6686,13 @@ mapnotify(XEvent *e) win = manage_window(ev->window); if (win) set_win_state(win, NormalState); + + /* + * focus_win can only set input focus on a mapped window. + * make sure the window really has focus since it is just being mapped. + */ + if (win->ws->focus == win) + focus_win(win); } void @@ -6430,12 +6773,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; @@ -6636,7 +6975,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) /* if we don't have a workspace already, find one */ if (ws == NULL) { - for (i = 0; i < SWM_WS_MAX; i++) + for (i = 0; i < workspace_limit; i++) if (s->ws[i].r == NULL) { ws = &s->ws[i]; break; @@ -6897,9 +7236,9 @@ workaround(void) screens[i].c[SWM_S_COLOR_UNFOCUS].color); XChangeProperty(display, root, netwmcheck, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win,1); + PropModeReplace, (unsigned char *)&win, 1); XChangeProperty(display, win, netwmcheck, XA_WINDOW, 32, - PropModeReplace, (unsigned char *)&win,1); + PropModeReplace, (unsigned char *)&win, 1); XChangeProperty(display, win, netwmname, utf8_string, 8, PropModeReplace, (unsigned char*)"LG3D", strlen("LG3D")); }