X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=bf4a3bdc4d3abecaa2753b3e2af7accbc10eead4;hb=d9ed576fa12c69b7316cd070124e953a217f5e05;hp=789aca0707d075a8dfa66d9c18b7cb210467dca8;hpb=739a5e6e3218529604d7a36cda21910719897e7b;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 789aca0..bf4a3bd 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -74,6 +74,11 @@ #include #include #include +#if defined(__linux__) +#include "linux/tree.h" +#elif defined(__OpenBSD__) +#include +# endif #include #include @@ -423,9 +428,11 @@ struct workspace { int horizontal_msize; int horizontal_mwin; int horizontal_stacks; + int horizontal_flip; int vertical_msize; int vertical_mwin; int vertical_stacks; + int vertical_flip; } l_state; }; @@ -467,6 +474,7 @@ union arg { #define SWM_ARG_ID_MASTERGROW (21) #define SWM_ARG_ID_MASTERADD (22) #define SWM_ARG_ID_MASTERDEL (23) +#define SWM_ARG_ID_FLIPLAYOUT (24) #define SWM_ARG_ID_STACKRESET (30) #define SWM_ARG_ID_STACKINIT (31) #define SWM_ARG_ID_CYCLEWS_UP (40) @@ -1215,10 +1223,12 @@ fancy_stacker(struct workspace *ws) { strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); if (ws->cur_layout->l_stack == vertical_stack) - snprintf(ws->stacker, sizeof ws->stacker, "[%d|%d]", + snprintf(ws->stacker, sizeof ws->stacker, + ws->l_state.vertical_flip ? "[%d>%d]" : "[%d|%d]", ws->l_state.vertical_mwin, ws->l_state.vertical_stacks); if (ws->cur_layout->l_stack == horizontal_stack) - snprintf(ws->stacker, sizeof ws->stacker, "[%d-%d]", + snprintf(ws->stacker, sizeof ws->stacker, + ws->l_state.horizontal_flip ? "[%dv%d]" : "[%d-%d]", ws->l_state.horizontal_mwin, ws->l_state.horizontal_stacks); } @@ -1227,9 +1237,11 @@ plain_stacker(struct workspace *ws) { strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); if (ws->cur_layout->l_stack == vertical_stack) - strlcpy(ws->stacker, "[|]", sizeof ws->stacker); + strlcpy(ws->stacker, ws->l_state.vertical_flip ? "[>]" : "[|]", + sizeof ws->stacker); if (ws->cur_layout->l_stack == horizontal_stack) - strlcpy(ws->stacker, "[-]", sizeof ws->stacker); + strlcpy(ws->stacker, ws->l_state.horizontal_flip ? "[v]" : "[-]", + sizeof ws->stacker); } void @@ -1478,6 +1490,13 @@ bar_update(void) } 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; @@ -2208,8 +2227,7 @@ focus_win(struct ws_win *win) PropModeReplace, (unsigned char *)&win->id,1); } - if (window_name_enabled || title_class_enabled || title_name_enabled) - bar_update(); + bar_check_opts(); } void @@ -2474,7 +2492,7 @@ swapwin(struct swm_region *r, union arg *args) void focus_prev(struct ws_win *win) { - struct ws_win *winfocus = NULL, *winlostfocus = NULL; + struct ws_win *winfocus = NULL; struct ws_win *cur_focus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; @@ -2487,7 +2505,6 @@ focus_prev(struct ws_win *win) ws = win->ws; wl = &ws->winlist; cur_focus = ws->focus; - winlostfocus = cur_focus; /* pickle, just focus on whatever */ if (cur_focus == NULL) { @@ -2525,22 +2542,15 @@ focus_prev(struct ws_win *win) winfocus = TAILQ_LAST(wl, ws_win_list); if (winfocus == NULL || winfocus == win) winfocus = TAILQ_NEXT(cur_focus, entry); -done: - if (winfocus == winlostfocus || winfocus == NULL) { - /* update the bar so that title/class/name will be cleared. */ - if (window_name_enabled || title_name_enabled || - title_class_enabled) - bar_update(); - return; - } +done: focus_magic(winfocus); } void focus(struct swm_region *r, union arg *args) { - struct ws_win *winfocus = NULL, *winlostfocus = NULL, *head; + struct ws_win *winfocus = NULL, *head; struct ws_win *cur_focus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; @@ -2582,8 +2592,6 @@ focus(struct swm_region *r, union arg *args) if (all_iconics) return; - winlostfocus = cur_focus; - switch (args->id) { case SWM_ARG_ID_FOCUSPREV: head = TAILQ_PREV(cur_focus, ws_win_list, entry); @@ -2637,14 +2645,6 @@ focus(struct swm_region *r, union arg *args) default: return; } - if (winfocus == winlostfocus || winfocus == NULL) { - /* update the bar so that title/class/name will be cleared. */ - if (window_name_enabled || title_name_enabled || - title_class_enabled) - bar_update(); - - return; - } focus_magic(winfocus); } @@ -3091,6 +3091,9 @@ vertical_config(struct workspace *ws, int id) if (ws->l_state.vertical_stacks > 1) ws->l_state.vertical_stacks--; break; + case SWM_ARG_ID_FLIPLAYOUT: + ws->l_state.vertical_flip = !ws->l_state.vertical_flip; + break; default: return; } @@ -3101,7 +3104,7 @@ vertical_stack(struct workspace *ws, struct swm_geometry *g) { DNPRINTF(SWM_D_STACK, "vertical_stack: workspace: %d\n", ws->idx); - stack_master(ws, g, 0, 0); + stack_master(ws, g, 0, ws->l_state.vertical_flip); } void @@ -3138,6 +3141,9 @@ horizontal_config(struct workspace *ws, int id) if (ws->l_state.horizontal_stacks > 1) ws->l_state.horizontal_stacks--; break; + case SWM_ARG_ID_FLIPLAYOUT: + ws->l_state.horizontal_flip = !ws->l_state.horizontal_flip; + break; default: return; } @@ -3148,7 +3154,7 @@ horizontal_stack(struct workspace *ws, struct swm_geometry *g) { DNPRINTF(SWM_D_STACK, "horizontal_stack: workspace: %d\n", ws->idx); - stack_master(ws, g, 1, 0); + stack_master(ws, g, 1, ws->l_state.horizontal_flip); } /* fullscreen view */ @@ -4147,6 +4153,7 @@ move_step(struct swm_region *r, union arg *args) /* user/key callable function IDs */ enum keyfuncid { kf_cycle_layout, + kf_flip_layout, kf_stack_reset, kf_master_shrink, kf_master_grow, @@ -4238,6 +4245,7 @@ struct keyfunc { } keyfuncs[kf_invalid + 1] = { /* name function argument */ { "cycle_layout", cycle_layout, {0} }, + { "flip_layout", stack_config, {.id = SWM_ARG_ID_FLIPLAYOUT} }, { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, { "master_shrink", stack_config, {.id = SWM_ARG_ID_MASTERSHRINK} }, { "master_grow", stack_config, {.id = SWM_ARG_ID_MASTERGROW} }, @@ -4311,14 +4319,32 @@ struct keyfunc { { "invalid key func", NULL, {0} }, }; struct key { - TAILQ_ENTRY(key) entry; + RB_ENTRY(key) entry; unsigned int mod; KeySym keysym; enum keyfuncid funcid; char *spawn_name; }; -TAILQ_HEAD(key_list, key); -struct key_list keys = TAILQ_HEAD_INITIALIZER(keys); +RB_HEAD(key_list, key); + +int +key_cmp(struct key *kp1, struct key *kp2) +{ + if (kp1->keysym < kp2->keysym) + return (-1); + if (kp1->keysym > kp2->keysym) + return (1); + + if (kp1->mod < kp2->mod) + return (-1); + if (kp1->mod > kp2->mod) + return (1); + + return (0); +} + +RB_GENERATE_STATIC(key_list, key, entry, key_cmp); +struct key_list keys; /* mouse */ enum { client_click, root_click }; @@ -4342,7 +4368,7 @@ update_modkey(unsigned int mod) struct key *kp; mod_key = mod; - TAILQ_FOREACH(kp, &keys, entry) + RB_FOREACH(kp, key_list, &keys) if (kp->mod & ShiftMask) kp->mod = mod | ShiftMask; else @@ -4357,13 +4383,13 @@ update_modkey(unsigned int mod) /* spawn */ struct spawn_prog { + TAILQ_ENTRY(spawn_prog) entry; char *name; int argc; char **argv; }; - -int spawns_size = 0, spawns_length = 0; -struct spawn_prog *spawns = NULL; +TAILQ_HEAD(spawn_list, spawn_prog); +struct spawn_list spawns = TAILQ_HEAD_INITIALIZER(spawns); int spawn_expand(struct swm_region *r, union arg *args, char *spawn_name, @@ -4376,9 +4402,9 @@ spawn_expand(struct swm_region *r, union arg *args, char *spawn_name, DNPRINTF(SWM_D_SPAWN, "spawn_expand: %s\n", spawn_name); /* find program */ - for (i = 0; i < spawns_length; i++) { - if (!strcasecmp(spawn_name, spawns[i].name)) - prog = &spawns[i]; + TAILQ_FOREACH(prog, &spawns, entry) { + if (!strcasecmp(spawn_name, prog->name)) + break; } if (prog == NULL) { warnx("spawn_custom: program %s not found", spawn_name); @@ -4502,120 +4528,102 @@ spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) } void -setspawn(struct spawn_prog *prog) +spawn_insert(char *name, char *args) { - int i, j; + char *arg, *cp, *ptr; + struct spawn_prog *sp; - if (prog == NULL || prog->name == NULL) - return; + DNPRINTF(SWM_D_SPAWN, "spawn_insert: %s\n", name); - /* find existing */ - for (i = 0; i < spawns_length; i++) { - if (!strcmp(spawns[i].name, prog->name)) { - /* found */ - if (prog->argv == NULL) { - /* delete */ - DNPRINTF(SWM_D_SPAWN, - "setspawn: delete #%d: %s\n", - i, spawns[i].name); - free(spawns[i].name); - for (j = 0; j < spawns[i].argc; j++) - free(spawns[i].argv[j]); - free(spawns[i].argv); - j = spawns_length - 1; - if (i < j) - spawns[i] = spawns[j]; - spawns_length--; - free(prog->name); - } else { - /* replace */ - DNPRINTF(SWM_D_SPAWN, - "setspawn: replace #%d: %s\n", - i, spawns[i].name); - free(spawns[i].name); - for (j = 0; j < spawns[i].argc; j++) - free(spawns[i].argv[j]); - free(spawns[i].argv); - spawns[i] = *prog; - } - /* found case handled */ - free(prog); - return; - } + if ((sp = calloc(1, sizeof *sp)) == NULL) + err(1, "spawn_insert: malloc"); + if ((sp->name = strdup(name)) == NULL) + err(1, "spawn_insert: strdup"); + + /* convert the arguments to an argument list */ + if ((ptr = cp = strdup(args)) == NULL) + err(1, "spawn_insert: strdup"); + while ((arg = strsep(&ptr, " \t")) != NULL) { + /* empty field; skip it */ + if (*arg == '\0') + continue; + + sp->argc++; + if ((sp->argv = realloc(sp->argv, sp->argc * + sizeof *sp->argv)) == NULL) + err(1, "spawn_insert: realloc"); + if ((sp->argv[sp->argc - 1] = strdup(arg)) == NULL) + err(1, "spawn_insert: strdup"); } + free(cp); + + TAILQ_INSERT_TAIL(&spawns, sp, entry); + DNPRINTF(SWM_D_SPAWN, "spawn_insert: leave\n"); +} + +void +spawn_remove(struct spawn_prog *sp) +{ + int i; + + DNPRINTF(SWM_D_SPAWN, "spawn_remove: %s\n", sp->name); - if (prog->argv == NULL) { - warnx("error: setspawn: cannot find program: %s", prog->name); - free(prog); + TAILQ_REMOVE(&spawns, sp, entry); + for (i = 0; i < sp->argc; i++) + free(sp->argv[i]); + free(sp->argv); + free(sp->name); + free(sp); + + DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); +} + +void +spawn_replace(struct spawn_prog *sp, char *name, char *args) +{ + DNPRINTF(SWM_D_SPAWN, "spawn_replace: %s [%s]\n", sp->name, name); + + spawn_remove(sp); + spawn_insert(name, args); + + DNPRINTF(SWM_D_SPAWN, "spawn_replace: leave\n"); +} + +void +setspawn(char *name, char *args) +{ + struct spawn_prog *sp; + + DNPRINTF(SWM_D_SPAWN, "setspawn: %s\n", name); + + if (name == NULL) return; - } - /* not found: add */ - if (spawns_size == 0 || spawns == NULL) { - spawns_size = 4; - DNPRINTF(SWM_D_SPAWN, "setspawn: init list %d\n", spawns_size); - spawns = malloc((size_t)spawns_size * - sizeof(struct spawn_prog)); - if (spawns == NULL) { - warn("setspawn: malloc failed"); - quit(NULL, NULL); - } - } else if (spawns_length == spawns_size) { - spawns_size *= 2; - DNPRINTF(SWM_D_SPAWN, "setspawn: grow list %d\n", spawns_size); - spawns = realloc(spawns, (size_t)spawns_size * - sizeof(struct spawn_prog)); - if (spawns == NULL) { - warn("setspawn: realloc failed"); - quit(NULL, NULL); + TAILQ_FOREACH(sp, &spawns, entry) { + if (!strcmp(sp->name, name)) { + if (*args == '\0') + spawn_remove(sp); + else + spawn_replace(sp, name, args); + DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); + return; } } - - if (spawns_length < spawns_size) { - DNPRINTF(SWM_D_SPAWN, "setspawn: add #%d %s\n", - spawns_length, prog->name); - i = spawns_length++; - spawns[i] = *prog; - } else { - warnx("spawns array problem?"); - if (spawns == NULL) { - warnx("spawns array is NULL!"); - quit(NULL, NULL); - } + if (*args == '\0') { + warnx("error: setspawn: cannot find program: %s", name); + return; } - free(prog); + + spawn_insert(name, args); + DNPRINTF(SWM_D_SPAWN, "setspawn: leave\n"); } int setconfspawn(char *selector, char *value, int flags) { - struct spawn_prog *prog; - char *vp, *cp, *word; - DNPRINTF(SWM_D_SPAWN, "setconfspawn: [%s] [%s]\n", selector, value); - if ((prog = calloc(1, sizeof *prog)) == NULL) - err(1, "setconfspawn: calloc prog"); - prog->name = strdup(selector); - if (prog->name == NULL) - err(1, "setconfspawn prog->name"); - if ((cp = vp = strdup(value)) == NULL) - err(1, "setconfspawn: strdup(value) "); - while ((word = strsep(&cp, " \t")) != NULL) { - DNPRINTF(SWM_D_SPAWN, "setconfspawn: arg [%s]\n", word); - if (cp) - cp += (long)strspn(cp, " \t"); - if (strlen(word) > 0) { - prog->argc++; - if ((prog->argv = realloc(prog->argv, - prog->argc * sizeof(char *))) == NULL) - err(1, "setconfspawn: realloc"); - if ((prog->argv[prog->argc - 1] = strdup(word)) == NULL) - err(1, "setconfspawn: strdup"); - } - } - free(vp); - setspawn(prog); + setspawn(selector, value); DNPRINTF(SWM_D_SPAWN, "setconfspawn: done\n"); return (0); @@ -4728,17 +4736,28 @@ 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); - TAILQ_INSERT_TAIL(&keys, kp, entry); + RB_INSERT(key_list, &keys, kp); DNPRINTF(SWM_D_KEY, "key_insert: leave\n"); } +struct key * +key_lookup(unsigned int mod, KeySym ks) +{ + struct key kp; + + kp.keysym = ks; + kp.mod = mod; + + return (RB_FIND(key_list, &keys, &kp)); +} + void key_remove(struct key *kp) { DNPRINTF(SWM_D_KEY, "key_remove: %s\n", keyfuncs[kp->funcid].name); - TAILQ_REMOVE(&keys, kp, entry); + RB_REMOVE(key_list, &keys, kp); free(kp->spawn_name); free(kp); @@ -4767,15 +4786,13 @@ setkeybinding(unsigned int mod, KeySym ks, enum keyfuncid kfid, DNPRINTF(SWM_D_KEY, "setkeybinding: enter %s [%s]\n", keyfuncs[kfid].name, spawn_name); - TAILQ_FOREACH(kp, &keys, entry) { - if (kp->mod == mod && kp->keysym == ks) { - if (kfid == kf_invalid) - key_remove(kp); - else - key_replace(kp, mod, ks, kfid, spawn_name); - DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); - return; - } + if ((kp = key_lookup(mod, ks)) != NULL) { + if (kfid == kf_invalid) + key_remove(kp); + else + key_replace(kp, mod, ks, kfid, spawn_name); + DNPRINTF(SWM_D_KEY, "setkeybinding: leave\n"); + return; } if (kfid == kf_invalid) { warnx("error: setkeybinding: cannot find mod/key combination"); @@ -4793,7 +4810,7 @@ setconfbinding(char *selector, char *value, int flags) enum keyfuncid kfid; unsigned int mod; KeySym ks; - int i; + struct spawn_prog *sp; DNPRINTF(SWM_D_KEY, "setconfbinding: enter\n"); if (selector == NULL) { DNPRINTF(SWM_D_KEY, "setconfbinding: unbind %s\n", value); @@ -4818,13 +4835,13 @@ setconfbinding(char *selector, char *value, int flags) } } /* search by custom spawn name */ - for (i = 0; i < spawns_length; i++) { - if (strcasecmp(selector, spawns[i].name) == 0) { + TAILQ_FOREACH(sp, &spawns, entry) { + if (strcasecmp(selector, sp->name) == 0) { DNPRINTF(SWM_D_KEY, "setconfbinding: %s: match\n", selector); if (parsekeys(value, mod_key, &mod, &ks) == 0) { setkeybinding(mod, ks, kf_spawn_custom, - spawns[i].name); + sp->name); return (0); } else return (1); @@ -4838,6 +4855,7 @@ void setup_keys(void) { setkeybinding(MODKEY, XK_space, kf_cycle_layout,NULL); + setkeybinding(MODKEY|ShiftMask, XK_backslash, kf_flip_layout, NULL); setkeybinding(MODKEY|ShiftMask, XK_space, kf_stack_reset, NULL); setkeybinding(MODKEY, XK_h, kf_master_shrink,NULL); setkeybinding(MODKEY, XK_l, kf_master_grow, NULL); @@ -4916,13 +4934,11 @@ setup_keys(void) void clear_keys(void) { - struct key *kp_loop, *kp_next; + struct key *kp; - kp_loop = TAILQ_FIRST(&keys); - while (kp_loop != NULL) { - kp_next = TAILQ_NEXT(kp_loop, entry); - key_remove(kp_loop); - kp_loop = kp_next; + while (RB_EMPTY(&keys) == 0) { + kp = RB_ROOT(&keys); + key_remove(kp); } } @@ -4980,7 +4996,7 @@ grabkeys(void) if (TAILQ_EMPTY(&screens[k].rl)) continue; XUngrabKey(display, AnyKey, AnyModifier, screens[k].root); - TAILQ_FOREACH(kp, &keys, entry) { + RB_FOREACH(kp, key_list, &keys) { if ((code = XKeysymToKeycode(display, kp->keysym))) for (j = 0; j < LENGTH(modifiers); j++) XGrabKey(display, code, @@ -5999,8 +6015,11 @@ focus_magic(struct ws_win *win) { DNPRINTF(SWM_D_FOCUS, "focus_magic: window: 0x%lx\n", WINID(win)); - if (win == NULL) + if (win == NULL) { + /* if there are no windows clear the status-bar */ + bar_check_opts(); return; + } if (win->child_trans) { /* win = parent & has a transient so focus on that */ @@ -6009,7 +6028,7 @@ focus_magic(struct ws_win *win) if (win->child_trans->take_focus) client_msg(win, takefocus); } else { - /* make sure transient hasn't dissapeared */ + /* make sure transient hasn't disappeared */ if (validate_win(win->child_trans) == 0) { focus_win(win->child_trans); if (win->child_trans->take_focus) @@ -6041,24 +6060,19 @@ keypress(XEvent *e) KeySym keysym; XKeyEvent *ev = &e->xkey; struct key *kp; + struct swm_region *r; keysym = XKeycodeToKeysym(display, (KeyCode)ev->keycode, 0); - TAILQ_FOREACH(kp, &keys, entry) - if (keysym == kp->keysym - && CLEANMASK(kp->mod) == CLEANMASK(ev->state) - && keyfuncs[kp->funcid].func) { - if (kp->funcid == kf_spawn_custom) - spawn_custom( - root_to_region(ev->root), - &(keyfuncs[kp->funcid].args), - kp->spawn_name - ); - else - keyfuncs[kp->funcid].func( - root_to_region(ev->root), - &(keyfuncs[kp->funcid].args) - ); - } + if ((kp = key_lookup(CLEANMASK(ev->state), keysym)) == NULL) + return; + if (keyfuncs[kp->funcid].func == NULL) + return; + + r = root_to_region(ev->root); + if (kp->funcid == kf_spawn_custom) + spawn_custom(r, &(keyfuncs[kp->funcid].args), kp->spawn_name); + else + keyfuncs[kp->funcid].func(r, &(keyfuncs[kp->funcid].args)); } void