X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=1575a43ad6d307f70f4d958ee3833972fdf870e1;hb=63eea690871eadbb0998dd035cf8d2759f495016;hp=55bf753bd425679fcbb7d944b486bec2f3da98ae;hpb=163f135835a874fde60008254cea4a1f753ddc64;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 55bf753..1575a43 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -1,4 +1,3 @@ -/* $scrotwm$ */ /* * Copyright (c) 2009-2010-2011 Marco Peereboom * Copyright (c) 2009-2010-2011 Ryan McBride @@ -52,11 +51,6 @@ * DEALINGS IN THE SOFTWARE. */ -static const char *cvstag = - "$scrotwm$"; - -#define SWM_VERSION "0.9.34" - #include #include #include @@ -93,6 +87,14 @@ static const char *cvstag = #include #endif +#include "version.h" + +#ifdef SCROTWM_BUILDSTR +static const char *buildstr = SCROTWM_BUILDSTR; +#else +static const char *buildstr = SCROTWM_VERSION; +#endif + #if RANDR_MAJOR < 1 # error XRandR versions less than 1.0 are not supported #endif @@ -163,6 +165,9 @@ u_int32_t swm_debug = 0 #define SWM_FOCUS_SYNERGY (1) #define SWM_FOCUS_FOLLOW (2) +#define SWM_CONF_DEFAULT (0) +#define SWM_CONF_KEYMAPPING (1) + #ifndef SWM_LIB #define SWM_LIB "/usr/local/lib/libswmhack.so" #endif @@ -200,11 +205,24 @@ int select_list_pipe[2]; int select_resp_pipe[2]; pid_t searchpid; volatile sig_atomic_t search_resp; +int search_resp_action; + +/* search actions */ +enum { + SWM_SEARCH_NONE, + SWM_SEARCH_UNICONIFY, + SWM_SEARCH_NAME_WORKSPACE, + SWM_SEARCH_SEARCH_WORKSPACE +}; /* dialog windows */ double dialog_ratio = .6; /* status bar */ -#define SWM_BAR_MAX (256) +#define SWM_BAR_MAX (256) +#define SWM_BAR_JUSTIFY_LEFT (0) +#define SWM_BAR_JUSTIFY_CENTER (1) +#define SWM_BAR_JUSTIFY_RIGHT (2) +#define SWM_BAR_OFFSET (4) char *bar_argv[] = { NULL, NULL }; int bar_pipe[2]; char bar_ext[SWM_BAR_MAX]; @@ -219,6 +237,7 @@ int bar_extra = 1; int bar_extra_running = 0; int bar_verbose = 1; int bar_height = 0; +int bar_justify = SWM_BAR_JUSTIFY_LEFT; int stack_enabled = 1; int clock_enabled = 1; int urgent_enabled = 0; @@ -237,6 +256,7 @@ int bar_fidx = 0; XFontStruct *bar_fs; char *bar_fonts[] = { NULL, NULL, NULL, NULL };/* XXX Make fully dynamic */ char *spawn_term[] = { NULL, NULL }; /* XXX Make fully dynamic */ +struct passwd *pwd; #define SWM_MENU_FN (2) #define SWM_MENU_NB (4) @@ -322,6 +342,8 @@ void new_region(struct swm_screen *, int, int, int, int); void unmanage_window(struct ws_win *); long getstate(Window); +int conf_load(char *, int); + struct layout { void (*l_stack)(struct workspace *, struct swm_geometry *); void (*l_config)(struct workspace *, int); @@ -349,6 +371,7 @@ struct layout { /* define work spaces */ struct workspace { int idx; /* workspace index */ + char *name; /* workspace name */ int always_raise; /* raise windows on focus */ struct layout *cur_layout; /* current layout handlers */ struct ws_win *focus; /* may be NULL */ @@ -412,6 +435,8 @@ union arg { #define SWM_ARG_ID_CYCLEWS_DOWN (41) #define SWM_ARG_ID_CYCLESC_UP (42) #define SWM_ARG_ID_CYCLESC_DOWN (43) +#define SWM_ARG_ID_CYCLEWS_UP_ALL (44) +#define SWM_ARG_ID_CYCLEWS_DOWN_ALL (45) #define SWM_ARG_ID_STACKINC (50) #define SWM_ARG_ID_STACKDEC (51) #define SWM_ARG_ID_SS_ALL (60) @@ -1139,7 +1164,7 @@ setscreencolor(char *val, int i, int c) void fancy_stacker(struct workspace *ws) { - strcpy(ws->stacker, "[ ]"); + strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); if (ws->cur_layout->l_stack == vertical_stack) snprintf(ws->stacker, sizeof ws->stacker, "[%d|%d]", ws->l_state.vertical_mwin, ws->l_state.vertical_stacks); @@ -1151,11 +1176,11 @@ fancy_stacker(struct workspace *ws) void plain_stacker(struct workspace *ws) { - strcpy(ws->stacker, "[ ]"); + strlcpy(ws->stacker, "[ ]", sizeof ws->stacker); if (ws->cur_layout->l_stack == vertical_stack) - strcpy(ws->stacker, "[|]"); + strlcpy(ws->stacker, "[|]", sizeof ws->stacker); if (ws->cur_layout->l_stack == horizontal_stack) - strcpy(ws->stacker, "[-]"); + strlcpy(ws->stacker, "[-]", sizeof ws->stacker); } void @@ -1203,10 +1228,31 @@ socket_setnonblock(int fd) void bar_print(struct swm_region *r, char *s) { + int textwidth, x; + size_t len; + XClearWindow(display, r->bar_window); XSetForeground(display, bar_gc, r->s->c[SWM_S_COLOR_BAR_FONT].color); - XDrawString(display, r->bar_window, bar_gc, 4, bar_fs->ascent, s, - strlen(s)); + + len = strlen(s); + textwidth = XTextWidth(bar_fs, s, len); + + switch (bar_justify) { + case SWM_BAR_JUSTIFY_LEFT: + x = SWM_BAR_OFFSET; + break; + case SWM_BAR_JUSTIFY_CENTER: + x = (WIDTH(r) - textwidth) / 2; + break; + case SWM_BAR_JUSTIFY_RIGHT: + x = WIDTH(r) - textwidth - SWM_BAR_OFFSET; + break; + } + + if (x < SWM_BAR_OFFSET) + x = SWM_BAR_OFFSET; + + XDrawString(display, r->bar_window, bar_gc, x, bar_fs->ascent, s, len); } void @@ -1316,10 +1362,11 @@ bar_update(void) struct swm_region *r; int i, x; size_t len; + char ws[SWM_BAR_MAX]; char s[SWM_BAR_MAX]; char cn[SWM_BAR_MAX]; char loc[SWM_BAR_MAX]; - char *b; + char *b, *stack = ""; if (bar_enabled == 0) return; @@ -1351,14 +1398,19 @@ bar_update(void) x = 1; TAILQ_FOREACH(r, &screens[i].rl, entry) { strlcpy(cn, "", sizeof cn); + strlcpy(ws, "", sizeof ws); if (r && r->ws) { bar_urgent(cn, sizeof cn); bar_class_name(cn, sizeof cn, r->ws->focus); bar_window_name(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", - x++, r->ws->idx + 1, r->ws->stacker, s, cn, bar_ext, + 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); } @@ -1535,8 +1587,8 @@ version(struct swm_region *r, union arg *args) { bar_version = !bar_version; if (bar_version) - snprintf(bar_vertext, sizeof bar_vertext, "Version: %s CVS: %s", - SWM_VERSION, cvstag); + snprintf(bar_vertext, sizeof bar_vertext, "Version: %s Build: %s", + SCROTWM_VERSION, buildstr); else strlcpy(bar_vertext, "", sizeof bar_vertext); bar_update(); @@ -2110,6 +2162,7 @@ cyclews(struct swm_region *r, union arg *args) { union arg a; struct swm_screen *s = r->s; + int cycle_all = 0; DNPRINTF(SWM_D_WS, "cyclews id %d " "in screen[%d]:%dx%d+%d+%d ws %d\n", args->id, @@ -2118,12 +2171,18 @@ cyclews(struct swm_region *r, union arg *args) a.id = r->ws->idx; do { switch (args->id) { + case SWM_ARG_ID_CYCLEWS_UP_ALL: + cycle_all = 1; + /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_UP: if (a.id < SWM_WS_MAX - 1) a.id++; else a.id = 0; break; + case SWM_ARG_ID_CYCLEWS_DOWN_ALL: + cycle_all = 1; + /* FALLTHROUGH */ case SWM_ARG_ID_CYCLEWS_DOWN: if (a.id > 0) a.id--; @@ -2134,7 +2193,8 @@ cyclews(struct swm_region *r, union arg *args) return; }; - if (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist)) + if (!cycle_all && + (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist))) continue; if (cycle_visible == 0 && s->ws[a.id].r != NULL) continue; @@ -3168,8 +3228,9 @@ uniconify(struct swm_region *r, union arg *args) return; search_r = r; + search_resp_action = SWM_SEARCH_UNICONIFY; - spawn_select(r, args, "uniconify", &searchpid); + spawn_select(r, args, "search", &searchpid); if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) return; @@ -3191,36 +3252,71 @@ uniconify(struct swm_region *r, union arg *args) fclose(lfile); } -#define MAX_RESP_LEN 1024 +void +name_workspace(struct swm_region *r, union arg *args) +{ + struct workspace *ws; + FILE *lfile; + + DNPRINTF(SWM_D_MISC, "name_workspace\n"); + + if (r && r->ws) + ws = r->ws; + else + return; + + search_r = r; + search_resp_action = SWM_SEARCH_NAME_WORKSPACE; + + spawn_select(r, args, "name_workspace", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + fprintf(lfile, "%s", ""); + fclose(lfile); +} void -search_do_resp(void) +search_workspace(struct swm_region *r, union arg *args) { - ssize_t rbytes; - struct ws_win *win; - unsigned char *name; - char *resp, *s; - unsigned long len; + int i; + struct workspace *ws; + FILE *lfile; - DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); + DNPRINTF(SWM_D_MISC, "search_workspace\n"); - search_resp = 0; - searchpid = 0; + if (r == NULL) + return; - if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) { - fprintf(stderr, "search: calloc\n"); + search_r = r; + search_resp_action = SWM_SEARCH_SEARCH_WORKSPACE; + + spawn_select(r, args, "search", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) return; - } - rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); - if (rbytes <= 0) { - fprintf(stderr, "search: read error: %s\n", strerror(errno)); - goto done; + for (i = 0; i < SWM_WS_MAX; i++) { + ws = &r->s->ws[i]; + if (ws == NULL) + continue; + fprintf(lfile, "%d%s%s\n", ws->idx + 1, + (ws->name ? ":" : ""), (ws->name ? ws->name : "")); } - resp[rbytes] = '\0'; - len = strlen(resp); - DNPRINTF(SWM_D_MISC, "search_do_resp: resp %s\n", resp); + fclose(lfile); +} + +void +search_resp_uniconify(char *resp, unsigned long len) +{ + unsigned char *name; + struct ws_win *win; + char *s; + + DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp %s\n", resp); + TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { if (win->iconic == 0) continue; @@ -3240,7 +3336,109 @@ search_do_resp(void) } free(s); } +} + +void +search_resp_name_workspace(char *resp, unsigned long len) +{ + struct workspace *ws; + + DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: resp %s\n", resp); + + if (search_r->ws == NULL) + return; + ws = search_r->ws; + + if (ws->name) { + free(search_r->ws->name); + search_r->ws->name = NULL; + } + + if (len > 1) { + ws->name = strdup(resp); + if (ws->name == NULL) { + DNPRINTF(SWM_D_MISC, "search_resp_name_workspace: strdup: %s", + strerror(errno)); + return; + } + ws->name[len - 1] = '\0'; + } +} + +void +search_resp_search_workspace(char *resp, unsigned long len) +{ + char *p, *q; + int ws_idx; + const char *errstr; + union arg a; + + DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: resp %s\n", resp); + + q = strdup(resp); + if (!q) { + DNPRINTF(SWM_D_MISC, "search_resp_search_workspace: strdup: %s", + strerror(errno)); + return; + } + q[len - 1] = '\0'; + p = strchr(q, ':'); + if (p != NULL) + *p = '\0'; + ws_idx = strtonum(q, 1, SWM_WS_MAX, &errstr); + if (errstr) { + DNPRINTF(SWM_D_MISC, "workspace idx is %s: %s", + errstr, q); + free(q); + return; + } + free(q); + a.id = ws_idx - 1; + switchws(search_r, &a); +} + +#define MAX_RESP_LEN 1024 + +void +search_do_resp(void) +{ + ssize_t rbytes; + char *resp; + unsigned long len; + + DNPRINTF(SWM_D_MISC, "search_do_resp:\n"); + + search_resp = 0; + searchpid = 0; + + if ((resp = calloc(1, MAX_RESP_LEN + 1)) == NULL) { + fprintf(stderr, "search: calloc\n"); + goto done; + } + + rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); + if (rbytes <= 0) { + fprintf(stderr, "search: read error: %s\n", strerror(errno)); + goto done; + } + resp[rbytes] = '\0'; + len = strlen(resp); + + switch (search_resp_action) { + case SWM_SEARCH_UNICONIFY: + search_resp_uniconify(resp, len); + break; + case SWM_SEARCH_NAME_WORKSPACE: + search_resp_name_workspace(resp, len); + break; + case SWM_SEARCH_SEARCH_WORKSPACE: + search_resp_search_workspace(resp, len); + break; + } + done: + search_resp_action = SWM_SEARCH_NONE; + close(select_resp_pipe[0]); free(resp); } @@ -3656,6 +3854,8 @@ enum keyfuncid { kf_ws_10, kf_ws_next, kf_ws_prev, + kf_ws_next_all, + kf_ws_prev_all, kf_ws_prior, kf_screen_next, kf_screen_prev, @@ -3691,6 +3891,8 @@ enum keyfuncid { kf_move_right, kf_move_up, kf_move_down, + kf_name_workspace, + kf_search_workspace, kf_dumpwins, /* MUST BE LAST */ kf_invalid }; @@ -3742,6 +3944,8 @@ struct keyfunc { { "ws_10", switchws, {.id = 9} }, { "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} }, + { "ws_prev_all", cyclews, {.id = SWM_ARG_ID_CYCLEWS_DOWN_ALL} }, { "ws_prior", priorws, {0} }, { "screen_next", cyclescr, {.id = SWM_ARG_ID_CYCLESC_UP} }, { "screen_prev", cyclescr, {.id = SWM_ARG_ID_CYCLESC_DOWN} }, @@ -3777,6 +3981,8 @@ struct keyfunc { { "move_right", move_step, {.id = SWM_ARG_ID_MOVERIGHT} }, { "move_up", move_step, {.id = SWM_ARG_ID_MOVEUP} }, { "move_down", move_step, {.id = SWM_ARG_ID_MOVEDOWN} }, + { "name_workspace", name_workspace, {0} }, + { "search_workspace", search_workspace, {0} }, { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ { "invalid key func", NULL, {0} }, }; @@ -4109,13 +4315,20 @@ setup_spawn(void) " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); - setconfspawn("uniconify", "dmenu" + setconfspawn("search", "dmenu" " -i" " -fn $bar_font" " -nb $bar_color" " -nf $bar_font_color" " -sb $bar_border" " -sf $bar_color", 0); + setconfspawn("name_workspace", "dmenu" + " -p Workspace" + " -fn $bar_font" + " -nb $bar_color" + " -nf $bar_font_color" + " -sb $bar_border" + " -sf $bar_color", 0); } /* key bindings */ @@ -4342,6 +4555,8 @@ setup_keys(void) setkeybinding(MODKEY, XK_0, kf_ws_10, 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); + setkeybinding(MODKEY, XK_Down, kf_ws_prev_all, NULL); setkeybinding(MODKEY, XK_a, kf_ws_prior, NULL); setkeybinding(MODKEY|ShiftMask, XK_Right, kf_screen_next, NULL); setkeybinding(MODKEY|ShiftMask, XK_Left, kf_screen_prev, NULL); @@ -4378,12 +4593,45 @@ setup_keys(void) setkeybinding(MODKEY, XK_bracketright,kf_move_right, NULL); setkeybinding(MODKEY|ShiftMask, XK_bracketleft, kf_move_up, NULL); setkeybinding(MODKEY|ShiftMask, XK_bracketright,kf_move_down, NULL); + setkeybinding(MODKEY|ShiftMask, XK_slash, kf_name_workspace,NULL); + setkeybinding(MODKEY, XK_slash, kf_search_workspace,NULL); #ifdef SWM_DEBUG setkeybinding(MODKEY|ShiftMask, XK_d, kf_dumpwins, NULL); #endif } void +clear_keys(void) +{ + int i; + + /* clear all key bindings, if any */ + for (i = 0; i < keys_length; i++) + free(keys[i].spawn_name); + keys_length = 0; +} + +int +setkeymapping(char *selector, char *value, int flags) +{ + char keymapping_file[PATH_MAX]; + DNPRINTF(SWM_D_KEY, "setkeymapping: enter\n"); + if (value[0] == '~') + snprintf(keymapping_file, sizeof keymapping_file, "%s/%s", + pwd->pw_dir, &value[1]); + else + strlcpy(keymapping_file, value, sizeof keymapping_file); + clear_keys(); + /* load new key bindings; if it fails, revert to default bindings */ + if (conf_load(keymapping_file, SWM_CONF_KEYMAPPING)) { + clear_keys(); + setup_keys(); + } + DNPRINTF(SWM_D_KEY, "setkeymapping: leave\n"); + return (0); +} + +void updatenumlockmask(void) { unsigned int i, j; @@ -4620,13 +4868,14 @@ enum { SWM_S_BAR_DELAY, SWM_S_BAR_ENABLED, SWM_S_BAR_BORDER_WIDTH, 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_VERBOSE_LAYOUT, SWM_S_BAR_JUSTIFY }; int setconfvalue(char *selector, char *value, int flags) { - int i; + int i; + switch (flags) { case SWM_S_BAR_DELAY: bar_delay = atoi(value); @@ -4640,6 +4889,16 @@ setconfvalue(char *selector, char *value, int flags) case SWM_S_BAR_AT_BOTTOM: bar_at_bottom = atoi(value); break; + case SWM_S_BAR_JUSTIFY: + if (!strcmp(value, "left")) + bar_justify = SWM_BAR_JUSTIFY_LEFT; + else if (!strcmp(value, "center")) + bar_justify = SWM_BAR_JUSTIFY_CENTER; + else if (!strcmp(value, "right")) + bar_justify = SWM_BAR_JUSTIFY_RIGHT; + else + errx(1, "invalid bar_justify"); + break; case SWM_S_STACK_ENABLED: stack_enabled = atoi(value); break; @@ -4907,6 +5166,8 @@ struct config_option configopt[] = { { "bar_font", setconfvalue, SWM_S_BAR_FONT }, { "bar_action", setconfvalue, SWM_S_BAR_ACTION }, { "bar_delay", setconfvalue, SWM_S_BAR_DELAY }, + { "bar_justify", setconfvalue, SWM_S_BAR_JUSTIFY }, + { "keyboard_mapping", setkeymapping, 0 }, { "bind", setconfbinding, 0 }, { "stack_enabled", setconfvalue, SWM_S_STACK_ENABLED }, { "clock_enabled", setconfvalue, SWM_S_CLOCK_ENABLED }, @@ -4938,7 +5199,7 @@ struct config_option configopt[] = { int -conf_load(char *filename) +conf_load(char *filename, int keymapping) { FILE *config; char *line, *cp, *optsub, *optval; @@ -4953,7 +5214,7 @@ conf_load(char *filename) return (1); } if ((config = fopen(filename, "r")) == NULL) { - warn("conf_load: fopen"); + warn("conf_load: fopen: %s", filename); return (1); } @@ -4993,6 +5254,11 @@ conf_load(char *filename) filename, lineno, wordlen, cp); return (1); } + if (keymapping && strcmp(opt->optname, "bind")) { + warnx("%s: line %zd: invalid option %.*s", + filename, lineno, wordlen, cp); + return (1); + } cp += wordlen; cp += strspn(cp, " \t\n"); /* eat whitespace */ /* get [selector] if any */ @@ -6198,6 +6464,7 @@ setup_screens(void) for (j = 0; j < SWM_WS_MAX; j++) { ws = &screens[i].ws[j]; ws->idx = j; + ws->name = NULL; ws->focus = NULL; ws->r = NULL; ws->old_r = NULL; @@ -6267,7 +6534,6 @@ workaround(void) int main(int argc, char *argv[]) { - struct passwd *pwd; struct swm_region *r, *rr; struct ws_win *winfocus = NULL; struct timeval tv; @@ -6280,9 +6546,10 @@ main(int argc, char *argv[]) struct sigaction sact; start_argv = argv; - fprintf(stderr, "Welcome to scrotwm V%s cvs tag: %s\n", - SWM_VERSION, cvstag); - if (!setlocale(LC_CTYPE, "") || !XSupportsLocale()) + fprintf(stderr, "Welcome to scrotwm V%s Build: %s\n", + SCROTWM_VERSION, buildstr); + if (!setlocale(LC_CTYPE, "") || !setlocale(LC_TIME, "") || + !XSupportsLocale()) warnx("no locale support"); if (!(display = XOpenDisplay(0))) @@ -6338,7 +6605,7 @@ main(int argc, char *argv[]) cfile = conf; } if (cfile) - conf_load(cfile); + conf_load(cfile, SWM_CONF_DEFAULT); setup_ewmh(); /* set some values to work around bad programs */