X-Git-Url: https://jasonwoof.com/gitweb/?a=blobdiff_plain;f=scrotwm.c;h=9da5d15af9e081820d58627b23894752f1647b51;hb=bc00007fce763065c8618fab6bb2d21cc5f536a0;hp=862077f7bd41ebc67d1fe567a4c02f500ec07952;hpb=8eb6cfee6344a0e61511f1eb2e36a91c30854e1e;p=spectrwm.git diff --git a/scrotwm.c b/scrotwm.c index 862077f..9da5d15 100644 --- a/scrotwm.c +++ b/scrotwm.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2009-2010-2011 Marco Peereboom - * Copyright (c) 2009-2010-2011 Ryan McBride + * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2011 Ryan McBride * Copyright (c) 2009 Darrin Chandler * Copyright (c) 2009 Pierre-Yves Ritschard * Copyright (c) 2010 Tuukka Kataja * Copyright (c) 2011 Jason L. Wright + * Copyright (c) 2011-2012 Reginald Kennedy * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -51,11 +52,6 @@ * DEALINGS IN THE SOFTWARE. */ -static const char *cvstag = - "$scrotwm$"; - -#define SWM_VERSION "0.9.34" - #include #include #include @@ -92,6 +88,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 @@ -162,6 +166,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 @@ -172,6 +179,7 @@ Atom aprot; Atom adelete; Atom takefocus; Atom a_wmname; +Atom a_netwmname; Atom a_utf8_string; Atom a_string; Atom a_swm_iconic; @@ -199,11 +207,35 @@ int select_list_pipe[2]; int select_resp_pipe[2]; pid_t searchpid; volatile sig_atomic_t search_resp; +int search_resp_action; + +struct search_window { + TAILQ_ENTRY(search_window) entry; + int idx; + struct ws_win *win; + Window indicator; +}; +TAILQ_HEAD(search_winlist, search_window); + +struct search_winlist search_wl; + +/* search actions */ +enum { + SWM_SEARCH_NONE, + SWM_SEARCH_UNICONIFY, + SWM_SEARCH_NAME_WORKSPACE, + SWM_SEARCH_SEARCH_WORKSPACE, + SWM_SEARCH_SEARCH_WINDOW +}; /* 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]; @@ -218,6 +250,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; @@ -236,6 +269,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) @@ -321,6 +355,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); @@ -348,6 +384,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 */ @@ -411,6 +448,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) @@ -1122,23 +1161,23 @@ setscreencolor(char *val, int i, int c) screens[i - 1].c[c].color = name_to_color(val); free(screens[i - 1].c[c].name); if ((screens[i - 1].c[c].name = strdup(val)) == NULL) - errx(1, "strdup"); + err(1, "strdup"); } else if (i == -1) { for (i = 0; i < ScreenCount(display); i++) { screens[i].c[c].color = name_to_color(val); free(screens[i].c[c].name); if ((screens[i].c[c].name = strdup(val)) == NULL) - errx(1, "strdup"); + err(1, "strdup"); } } else - errx(1, "invalid screen index: %d out of bounds (maximum %d)\n", + errx(1, "invalid screen index: %d out of bounds (maximum %d)", i, ScreenCount(display)); } 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); @@ -1150,11 +1189,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 @@ -1164,14 +1203,14 @@ custom_region(char *val) if (sscanf(val, "screen[%u]:%ux%u+%u+%u", &sidx, &w, &h, &x, &y) != 5) errx(1, "invalid custom region, " - "should be 'screen[]:x++\n"); + "should be 'screen[]:x++"); if (sidx < 1 || sidx > ScreenCount(display)) - errx(1, "invalid screen index: %d out of bounds (maximum %d)\n", + errx(1, "invalid screen index: %d out of bounds (maximum %d)", sidx, ScreenCount(display)); sidx--; if (w < 1 || h < 1) - errx(1, "region %ux%u+%u+%u too small\n", w, h, x, y); + errx(1, "region %ux%u+%u+%u too small", w, h, x, y); if (x > DisplayWidth(display, sidx) || y > DisplayHeight(display, sidx) || @@ -1202,10 +1241,31 @@ socket_setnonblock(int fd) void bar_print(struct swm_region *r, char *s) { + int textwidth, x = 0; + 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 @@ -1315,10 +1375,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; @@ -1350,14 +1411,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); } @@ -1411,9 +1477,9 @@ bar_refresh(void) socket_setnonblock(bar_pipe[0]); socket_setnonblock(bar_pipe[1]); /* XXX hmmm, really? */ if (dup2(bar_pipe[0], 0) == -1) - errx(1, "dup2"); + err(1, "dup2"); if (dup2(bar_pipe[1], 1) == -1) - errx(1, "dup2"); + err(1, "dup2"); if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) err(1, "could not disable SIGPIPE"); switch (bar_pid = fork()) { @@ -1462,7 +1528,7 @@ bar_setup(struct swm_region *r) } } if (bar_fonts[i] == NULL) - errx(1, "couldn't load font"); + errx(1, "couldn't load font"); if (bar_fs == NULL) errx(1, "couldn't create font structure"); @@ -1534,8 +1600,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(); @@ -1698,7 +1764,7 @@ restart(struct swm_region *r, union arg *args) /* disable alarm because the following code may not be interrupted */ alarm(0); if (signal(SIGALRM, SIG_IGN) == SIG_ERR) - errx(1, "can't disable alarm"); + err(1, "can't disable alarm"); bar_extra_stop(); bar_extra = 1; @@ -1881,12 +1947,12 @@ validate_win(struct ws_win *testwin) struct ws_win *win; struct workspace *ws; struct swm_region *r; - int i, x, foundit = 0; + int i, x; if (testwin == NULL) return (0); - for (i = 0, foundit = 0; i < ScreenCount(display); i++) + for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) for (x = 0; x < SWM_WS_MAX; x++) { ws = &r->s->ws[x]; @@ -1902,10 +1968,10 @@ validate_ws(struct workspace *testws) { struct swm_region *r; struct workspace *ws; - int foundit, i, x; + int i, x; /* validate all ws */ - for (i = 0, foundit = 0; i < ScreenCount(display); i++) + for (i = 0; i < ScreenCount(display); i++) TAILQ_FOREACH(r, &screens[i].rl, entry) for (x = 0; x < SWM_WS_MAX; x++) { ws = &r->s->ws[x]; @@ -2109,6 +2175,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, @@ -2117,12 +2184,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--; @@ -2133,7 +2206,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; @@ -2356,8 +2430,14 @@ focus_prev(struct ws_win *win) if (winfocus == NULL || winfocus == win) winfocus = TAILQ_NEXT(cur_focus, entry); done: - if (winfocus == winlostfocus || winfocus == NULL) + 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); } @@ -2369,6 +2449,7 @@ focus(struct swm_region *r, union arg *args) struct ws_win *cur_focus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; + int all_iconics; if (!(r && r->ws)) return; @@ -2394,6 +2475,17 @@ focus(struct swm_region *r, union arg *args) return; ws = r->ws; wl = &ws->winlist; + if (TAILQ_EMPTY(wl)) + return; + /* make sure there is at least one uniconified window */ + all_iconics = 1; + TAILQ_FOREACH(winfocus, wl, entry) + if (winfocus->iconic == 0) { + all_iconics = 0; + break; + } + if (all_iconics) + return; winlostfocus = cur_focus; @@ -2412,9 +2504,13 @@ focus(struct swm_region *r, union arg *args) /* skip iconics */ if (winfocus && winfocus->iconic) { - TAILQ_FOREACH_REVERSE(winfocus, wl, ws_win_list, entry) + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); if (winfocus->iconic == 0) break; + winfocus = TAILQ_PREV(winfocus, ws_win_list, entry); + } } break; @@ -2426,9 +2522,13 @@ focus(struct swm_region *r, union arg *args) /* skip iconics */ if (winfocus && winfocus->iconic) { - TAILQ_FOREACH(winfocus, wl, entry) + while (winfocus != cur_focus) { + if (winfocus == NULL) + winfocus = TAILQ_FIRST(wl); if (winfocus->iconic == 0) break; + winfocus = TAILQ_NEXT(winfocus, entry); + } } break; @@ -2441,8 +2541,14 @@ focus(struct swm_region *r, union arg *args) default: return; } - if (winfocus == winlostfocus || winfocus == NULL) + 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); } @@ -2451,13 +2557,10 @@ void cycle_layout(struct swm_region *r, union arg *args) { struct workspace *ws = r->ws; - struct ws_win *winfocus; union arg a; DNPRINTF(SWM_D_EVENT, "cycle_layout: workspace: %d\n", ws->idx); - winfocus = ws->focus; - ws->cur_layout++; if (ws->cur_layout->l_stack == NULL) ws->cur_layout = &layouts[0]; @@ -2490,12 +2593,17 @@ void stack(void) { struct swm_geometry g; struct swm_region *r; - int i, j; + int i; +#ifdef SWM_DEBUG + int j; +#endif DNPRINTF(SWM_D_STACK, "stack\n"); for (i = 0; i < ScreenCount(display); i++) { +#ifdef SWM_DEBUG j = 0; +#endif TAILQ_FOREACH(r, &screens[i].rl, entry) { DNPRINTF(SWM_D_STACK, "stacking workspace %d " "(screen %d, region %d)\n", r->ws->idx, i, j++); @@ -3031,7 +3139,7 @@ send_to_ws(struct swm_region *r, union arg *args) unsigned char ws_idx_str[SWM_PROPLEN]; union arg a; - if (r && r->ws) + if (r && r->ws && r->ws->focus) win = r->ws->focus; else return; @@ -3059,6 +3167,8 @@ send_to_ws(struct swm_region *r, union arg *args) unmap_window(win); TAILQ_REMOVE(&ws->winlist, win, entry); TAILQ_INSERT_TAIL(&nws->winlist, win, entry); + if (TAILQ_EMPTY(&ws->winlist)) + r->ws->focus = NULL; win->ws = nws; /* Try to update the window's workspace property */ @@ -3167,8 +3277,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; @@ -3179,7 +3290,7 @@ uniconify(struct swm_region *r, union arg *args) if (win->iconic == 0) continue; - name = get_win_name(display, win->id, a_wmname, a_string, + name = get_win_name(display, win->id, a_netwmname, a_utf8_string, &len); if (name == NULL) continue; @@ -3190,40 +3301,152 @@ 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) +{ + FILE *lfile; + + DNPRINTF(SWM_D_MISC, "name_workspace\n"); + + if (r == NULL) + 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; + + 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 : "")); } - rbytes = read(select_resp_pipe[0], resp, MAX_RESP_LEN); - if (rbytes <= 0) { - fprintf(stderr, "search: read error: %s\n", strerror(errno)); - goto done; + fclose(lfile); +} + +void +search_win_cleanup(void) +{ + struct search_window *sw = NULL; + + while ((sw = TAILQ_FIRST(&search_wl)) != NULL) { + XDestroyWindow(display, sw->indicator); + TAILQ_REMOVE(&search_wl, sw, entry); + free(sw); } - resp[rbytes] = '\0'; - len = strlen(resp); +} + +void +search_win(struct swm_region *r, union arg *args) +{ + struct ws_win *win = NULL; + struct search_window *sw = NULL; + Window w; + GC gc; + XGCValues gcv; + int i; + char s[8]; + FILE *lfile; + size_t len; + int textwidth; + + DNPRINTF(SWM_D_MISC, "search_win\n"); + + search_r = r; + search_resp_action = SWM_SEARCH_SEARCH_WINDOW; + + spawn_select(r, args, "search", &searchpid); + + if ((lfile = fdopen(select_list_pipe[1], "w")) == NULL) + return; + + TAILQ_INIT(&search_wl); + + i = 1; + TAILQ_FOREACH(win, &r->ws->winlist, entry) { + if (win->iconic == 1) + continue; + + sw = calloc(1, sizeof(struct search_window)); + if (sw == NULL) { + fprintf(stderr, "search_win: calloc: %s", strerror(errno)); + fclose(lfile); + search_win_cleanup(); + return; + } + sw->idx = i; + sw->win = win; + + snprintf(s, sizeof s, "%d", i); + len = strlen(s); + textwidth = XTextWidth(bar_fs, s, len); + + w = XCreateSimpleWindow(display, + win->id, 0, 0, textwidth + 12, + bar_fs->ascent + bar_fs->descent + 4, 1, + r->s->c[SWM_S_COLOR_UNFOCUS].color, + r->s->c[SWM_S_COLOR_FOCUS].color); + + sw->indicator = w; + TAILQ_INSERT_TAIL(&search_wl, sw, entry); + + gc = XCreateGC(display, w, 0, &gcv); + XSetFont(display, gc, bar_fs->fid); + XMapRaised(display, w); + XSetForeground(display, gc, r->s->c[SWM_S_COLOR_BAR].color); + + XDrawString(display, w, gc, 6, bar_fs->ascent + 2, s, len); + + fprintf(lfile, "%d\n", i); + i++; + } + + 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); - DNPRINTF(SWM_D_MISC, "search_do_resp: resp %s\n", resp); TAILQ_FOREACH(win, &search_r->ws->winlist, entry) { if (win->iconic == 0) continue; - name = get_win_name(display, win->id, a_wmname, a_string, &len); + name = get_win_name(display, win->id, a_netwmname, a_utf8_string, &len); if (name == NULL) continue; if (asprintf(&s, "%s.%lu", name, win->id) == -1) { @@ -3239,7 +3462,152 @@ 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; + } + } +} + +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; + } + 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); +} + +void +search_resp_search_window(char *resp, unsigned long len) +{ + char *s; + int idx; + const char *errstr; + struct search_window *sw; + + DNPRINTF(SWM_D_MISC, "search_resp_search_window: resp %s\n", resp); + + s = strdup(resp); + if (!s) { + DNPRINTF(SWM_D_MISC, "search_resp_search_window: strdup: %s", + strerror(errno)); + return; + } + + idx = strtonum(s, 1, INT_MAX, &errstr); + if (errstr) { + DNPRINTF(SWM_D_MISC, "window idx is %s: %s", + errstr, s); + free(s); + return; + } + free(s); + + TAILQ_FOREACH(sw, &search_wl, entry) + if (idx == sw->idx) { + focus_win(sw->win); + break; + } +} + +#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'; + + /* XXX: + * Older versions of dmenu (Atleast pre 4.4.1) do not send a + * newline, so work around that by sanitizing the resp now. + */ + resp[strcspn(resp, "\n")] = '\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; + case SWM_SEARCH_SEARCH_WINDOW: + search_resp_search_window(resp, len); + break; + } + done: + if (search_resp_action == SWM_SEARCH_SEARCH_WINDOW) + search_win_cleanup(); + + search_resp_action = SWM_SEARCH_NONE; + close(select_resp_pipe[0]); free(resp); } @@ -3321,25 +3689,57 @@ floating_toggle(struct swm_region *r, union arg *args) } void -resize_window(struct ws_win *win, int center) +constrain_window(struct ws_win *win, struct swm_region *r, int resizable) +{ + if (win->g.x + win->g.w > r->g.x + r->g.w - border_width) { + if (resizable) + win->g.w = r->g.x + r->g.w - win->g.x - border_width; + else + win->g.x = r->g.x + r->g.w - win->g.w - border_width; + } + + if (win->g.x < r->g.x - border_width) { + if (resizable) + win->g.w -= r->g.x - win->g.x - border_width; + + win->g.x = r->g.x - border_width; + } + + if (win->g.y + win->g.h > r->g.y + r->g.h - border_width) { + if (resizable) + win->g.h = r->g.y + r->g.h - win->g.y - border_width; + else + win->g.y = r->g.y + r->g.h - win->g.h - border_width; + } + + if (win->g.y < r->g.y - border_width) { + if (resizable) + win->g.h -= r->g.y - win->g.y - border_width; + + win->g.y = r->g.y - border_width; + } + + if (win->g.w < 1) + win->g.w = 1; + if (win->g.h < 1) + win->g.h = 1; +} + +void +update_window(struct ws_win *win) { unsigned int mask; XWindowChanges wc; - struct swm_region *r; - r = root_to_region(win->wa.root); bzero(&wc, sizeof wc); - mask = CWBorderWidth | CWWidth | CWHeight; + mask = CWBorderWidth | CWWidth | CWHeight | CWX | CWY; wc.border_width = border_width; + wc.x = win->g.x; + wc.y = win->g.y; wc.width = win->g.w; wc.height = win->g.h; - if (center == SWM_ARG_ID_CENTER) { - wc.x = (WIDTH(r) - win->g.w) / 2 - border_width; - wc.y = (HEIGHT(r) - win->g.h) / 2 - border_width; - mask |= CWX | CWY; - } - DNPRINTF(SWM_D_STACK, "resize_window: win %lu x %d y %d w %d h %d\n", + DNPRINTF(SWM_D_STACK, "update_window: win %lu x %d y %d w %d h %d\n", win->id, wc.x, wc.y, wc.width, wc.height); XConfigureWindow(display, win->id, mask, &wc); @@ -3353,8 +3753,15 @@ resize(struct ws_win *win, union arg *args) XEvent ev; Time time = 0; struct swm_region *r = NULL; - int relx, rely; int resize_step = 0; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + struct swm_geometry g; + int top = 0, left = 0; + int dx, dy; + Cursor cursor; + unsigned int shape; /* cursor style */ if (win == NULL) return; @@ -3397,7 +3804,8 @@ resize(struct ws_win *win, union arg *args) break; } if (resize_step) { - resize_window(win, 0); + constrain_window(win, r, 1); + update_window(win); store_float_geom(win,r); return; } @@ -3405,22 +3813,33 @@ resize(struct ws_win *win, union arg *args) if (focus_mode == SWM_FOCUS_DEFAULT) drain_enter_notify(); - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) - return; + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; - /* place pointer at bottom left corner or nearest point inside r */ - if ( win->g.x + win->g.w < r->g.x + r->g.w - 1) - relx = win->g.w - 1; - else - relx = r->g.x + r->g.w - win->g.x - 1; + g = win->g; + + if (wx < win->g.w / 2) + left = 1; + + if (wy < win->g.h / 2) + top = 1; - if ( win->g.y + win->g.h < r->g.y + r->g.h - 1) - rely = win->g.h - 1; + if (args->id == SWM_ARG_ID_CENTER) + shape = XC_sizing; + else if (top) + shape = (left) ? XC_top_left_corner : XC_top_right_corner; else - rely = r->g.y + r->g.h - win->g.y - 1; + shape = (left) ? XC_bottom_left_corner : XC_bottom_right_corner; + + cursor = XCreateFontCursor(display, shape); + + if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, + GrabModeAsync, None, cursor, CurrentTime) != GrabSuccess) { + XFreeCursor(display, cursor); + return; + } - XWarpPointer(display, None, win->id, 0, 0, 0, 0, relx, rely); do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -3431,38 +3850,69 @@ resize(struct ws_win *win, union arg *args) handler[ev.type](&ev); break; case MotionNotify: - /* do not allow resize outside of region */ - if ( ev.xmotion.x_root < r->g.x || - ev.xmotion.x_root > r->g.x + r->g.w - 1 || - ev.xmotion.y_root < r->g.y || - ev.xmotion.y_root > r->g.y + r->g.h - 1) - continue; + /* cursor offset/delta from start of the operation */ + dx = ev.xmotion.x_root - x; + dy = ev.xmotion.y_root - y; + + /* vertical */ + if (top) + dy = -dy; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.h / 2 + dy < 1) + dy = 1 - g.h / 2; + + win->g.y = g.y - dy; + win->g.h = g.h + 2 * dy; + } else { + if (g.h + dy < 1) + dy = 1 - g.h; + + if (top) + win->g.y = g.y - dy; - if (ev.xmotion.x <= 1) - ev.xmotion.x = 1; - if (ev.xmotion.y <= 1) - ev.xmotion.y = 1; - win->g.w = ev.xmotion.x + 1; - win->g.h = ev.xmotion.y + 1; + win->g.h = g.h + dy; + } + + /* horizontal */ + if (left) + dx = -dx; + + if (args->id == SWM_ARG_ID_CENTER) { + if (g.w / 2 + dx < 1) + dx = 1 - g.w / 2; + + win->g.x = g.x - dx; + win->g.w = g.w + 2 * dx; + } else { + if (g.w + dx < 1) + dx = 1 - g.w; + + if (left) + win->g.x = g.x - dx; + + win->g.w = g.w + dx; + } + + constrain_window(win, r, 1); /* not free, don't sync more than 120 times / second */ if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); - resize_window(win, args->id); + update_window(win); } break; } } while (ev.type != ButtonRelease); if (time) { XSync(display, False); - resize_window(win, args->id); + update_window(win); } store_float_geom(win,r); - XWarpPointer(display, None, win->id, 0, 0, 0, 0, win->g.w - 1, - win->g.h - 1); XUngrabPointer(display, CurrentTime); + XFreeCursor(display, cursor); /* drain events */ drain_enter_notify(); @@ -3481,27 +3931,6 @@ resize_step(struct swm_region *r, union arg *args) resize(win, args); } - -void -move_window(struct ws_win *win) -{ - unsigned int mask; - XWindowChanges wc; - struct swm_region *r; - - r = root_to_region(win->wa.root); - bzero(&wc, sizeof wc); - mask = CWX | CWY; - wc.x = win->g.x; - wc.y = win->g.y; - wc.border_width = border_width; - - DNPRINTF(SWM_D_STACK, "move_window: win %lu x %d y %d w %d h %d\n", - win->id, wc.x, wc.y, wc.width, wc.height); - - XConfigureWindow(display, win->id, mask, &wc); -} - #define SWM_MOVE_STEPS (50) void @@ -3512,6 +3941,10 @@ move(struct ws_win *win, union arg *args) int move_step = 0; struct swm_region *r = NULL; + Window rr, cr; + int x, y, wx, wy; + unsigned int mask; + if (win == NULL) return; r = win->ws->r; @@ -3525,6 +3958,7 @@ move(struct ws_win *win, union arg *args) win->manual = 1; if (win->floating == 0 && !win->transient) { + store_float_geom(win,r); ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom, _NET_WM_STATE_ADD); } @@ -3555,16 +3989,21 @@ move(struct ws_win *win, union arg *args) break; } if (move_step) { - move_window(win); + constrain_window(win, r, 0); + update_window(win); store_float_geom(win,r); return; } - if (XGrabPointer(display, win->id, False, MOUSEMASK, GrabModeAsync, - GrabModeAsync, None, None /* cursor */, CurrentTime) != GrabSuccess) + GrabModeAsync, None, XCreateFontCursor(display, XC_fleur), + CurrentTime) != GrabSuccess) return; - XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); + + /* get cursor offset from window root */ + if (!XQueryPointer(display, win->id, &rr, &cr, &x, &y, &wx, &wy, &mask)) + return; + do { XMaskEvent(display, MOUSEMASK | ExposureMask | SubstructureRedirectMask, &ev); @@ -3575,31 +4014,25 @@ move(struct ws_win *win, union arg *args) handler[ev.type](&ev); break; case MotionNotify: - /* don't allow to move window origin out of region */ - if ( ev.xmotion.x_root < r->g.x || - ev.xmotion.x_root > r->g.x + r->g.w - 1 || - ev.xmotion.y_root < r->g.y || - ev.xmotion.y_root > r->g.y + r->g.h - 1) - continue; + win->g.x = ev.xmotion.x_root - wx - border_width; + win->g.y = ev.xmotion.y_root - wy - border_width; - win->g.x = ev.xmotion.x_root - border_width; - win->g.y = ev.xmotion.y_root - border_width; + constrain_window(win, r, 0); /* not free, don't sync more than 120 times / second */ if ((ev.xmotion.time - time) > (1000 / 120) ) { time = ev.xmotion.time; XSync(display, False); - move_window(win); + update_window(win); } break; } } while (ev.type != ButtonRelease); if (time) { XSync(display, False); - move_window(win); + update_window(win); } store_float_geom(win,r); - XWarpPointer(display, None, win->id, 0, 0, 0, 0, 0, 0); XUngrabPointer(display, CurrentTime); /* drain events */ @@ -3655,6 +4088,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, @@ -3690,6 +4125,9 @@ enum keyfuncid { kf_move_right, kf_move_up, kf_move_down, + kf_name_workspace, + kf_search_workspace, + kf_search_win, kf_dumpwins, /* MUST BE LAST */ kf_invalid }; @@ -3741,6 +4179,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} }, @@ -3776,6 +4216,9 @@ 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} }, + { "search_win", search_win, {0} }, { "dumpwins", dumpwins, {0} }, /* MUST BE LAST */ { "invalid key func", NULL, {0} }, }; @@ -3953,9 +4396,9 @@ spawn_select(struct swm_region *r, union arg *args, char *spawn_name, int *pid) break; case 0: /* child */ if (dup2(select_list_pipe[0], 0) == -1) - errx(1, "dup2"); + err(1, "dup2"); if (dup2(select_resp_pipe[1], 1) == -1) - errx(1, "dup2"); + err(1, "dup2"); close(select_list_pipe[1]); close(select_resp_pipe[0]); spawn(r->ws->idx, &a, 0); @@ -4108,13 +4551,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 */ @@ -4341,6 +4791,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); @@ -4377,12 +4829,46 @@ 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); + setkeybinding(MODKEY, XK_f, kf_search_win, 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; @@ -4619,13 +5105,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); @@ -4639,6 +5126,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; @@ -4684,7 +5181,7 @@ setconfvalue(char *selector, char *value, int flags) else if (!strcmp(value, "synergy")) focus_mode = SWM_FOCUS_SYNERGY; else - err(1, "focus_mode"); + errx(1, "focus_mode"); break; case SWM_S_DISABLE_BORDER: disable_border = atoi(value); @@ -4775,10 +5272,10 @@ setautorun(char *selector, char *value, int flags) bzero(s, sizeof s); if (sscanf(value, "ws[%d]:%1023c", &ws_id, s) != 2) - errx(1, "invalid autorun entry, should be 'ws[]:command'\n"); + errx(1, "invalid autorun entry, should be 'ws[]:command'"); ws_id--; if (ws_id < 0 || ws_id >= SWM_WS_MAX) - errx(1, "autorun: invalid workspace %d\n", ws_id + 1); + errx(1, "autorun: invalid workspace %d", ws_id + 1); /* * This is a little intricate @@ -4840,10 +5337,10 @@ setlayout(char *selector, char *value, int flags) &ws_id, &mg, &ma, &si, &raise, s) != 6) errx(1, "invalid layout entry, should be 'ws[]:" "::::" - "'\n"); + "'"); ws_id--; if (ws_id < 0 || ws_id >= SWM_WS_MAX) - errx(1, "layout: invalid workspace %d\n", ws_id + 1); + errx(1, "layout: invalid workspace %d", ws_id + 1); if (!strcasecmp(s, "vertical")) st = SWM_V_STACK; @@ -4854,7 +5351,7 @@ setlayout(char *selector, char *value, int flags) else errx(1, "invalid layout entry, should be 'ws[]:" "::::" - "'\n"); + "'"); for (i = 0; i < ScreenCount(display); i++) { ws = (struct workspace *)&screens[i].ws; @@ -4906,6 +5403,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 }, @@ -4937,7 +5436,7 @@ struct config_option configopt[] = { int -conf_load(char *filename) +conf_load(char *filename, int keymapping) { FILE *config; char *line, *cp, *optsub, *optval; @@ -4952,7 +5451,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); } @@ -4976,7 +5475,7 @@ conf_load(char *filename) if (wordlen == 0) { warnx("%s: line %zd: no option found", filename, lineno); - return (1); + goto out; } optind = -1; for (i = 0; i < LENGTH(configopt); i++) { @@ -4990,7 +5489,12 @@ conf_load(char *filename) if (optind == -1) { warnx("%s: line %zd: unknown option %.*s", filename, lineno, wordlen, cp); - return (1); + goto out; + } + if (keymapping && strcmp(opt->optname, "bind")) { + warnx("%s: line %zd: invalid option %.*s", + filename, lineno, wordlen, cp); + goto out; } cp += wordlen; cp += strspn(cp, " \t\n"); /* eat whitespace */ @@ -5003,9 +5507,16 @@ conf_load(char *filename) if (wordlen == 0) { warnx("%s: line %zd: syntax error", filename, lineno); - return (1); + goto out; + } + + if (asprintf(&optsub, "%.*s", wordlen, cp) == + -1) { + warnx("%s: line %zd: unable to allocate" + "memory for selector", filename, + lineno); + goto out; } - asprintf(&optsub, "%.*s", wordlen, cp); } cp += wordlen; cp += strspn(cp, "] \t\n"); /* eat trailing */ @@ -5030,6 +5541,12 @@ conf_load(char *filename) DNPRINTF(SWM_D_CONF, "conf_load end\n"); return (0); + +out: + free(line); + fclose(config); + + return (1); } void @@ -5163,7 +5680,7 @@ manage_window(Window id) } if ((win = calloc(1, sizeof(struct ws_win))) == NULL) - errx(1, "calloc: failed to allocate memory for new window"); + err(1, "calloc: failed to allocate memory for new window"); win->id = id; @@ -5573,6 +6090,11 @@ enternotify(XEvent *e) ev->window, ev->mode, ev->detail, ev->root, ev->subwindow, ev->same_screen, ev->focus, ev->state); + if (ev->mode != NotifyNormal) { + DNPRINTF(SWM_D_EVENT, "ignoring enternotify: generated by cursor grab.\n"); + return; + } + switch (focus_mode) { case SWM_FOCUS_DEFAULT: break; @@ -5772,8 +6294,8 @@ propertynotify(XEvent *e) struct ws_win *win; XPropertyEvent *ev = &e->xproperty; - DNPRINTF(SWM_D_EVENT, "propertynotify: window: %lu\n", - ev->window); + DNPRINTF(SWM_D_EVENT, "propertynotify: window: %lu atom:%s\n", + ev->window, XGetAtomName(display, ev->atom)); win = find_window(ev->window); if (win == NULL) @@ -5788,8 +6310,8 @@ propertynotify(XEvent *e) } switch (ev->atom) { - case XA_WM_NORMAL_HINTS: #if 0 + case XA_WM_NORMAL_HINTS: long mask; XGetWMNormalHints(display, win->id, &win->sh, &mask); fprintf(stderr, "normal hints: flag 0x%x\n", win->sh.flags); @@ -5801,6 +6323,11 @@ propertynotify(XEvent *e) XMoveResizeWindow(display, win->id, win->g.x, win->g.y, win->g.w, win->g.h); #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(); break; @@ -5995,7 +6522,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) ws = r->ws; } else if ((r = calloc(1, sizeof(struct swm_region))) == NULL) - errx(1, "calloc: failed to allocate memory for screen"); + err(1, "calloc: failed to allocate memory for screen"); /* if we don't have a workspace already, find one */ if (ws == NULL) { @@ -6007,7 +6534,7 @@ new_region(struct swm_screen *s, int x, int y, int w, int h) } if (ws == NULL) - errx(1, "no free workspaces\n"); + errx(1, "no free workspaces"); X(r) = x; Y(r) = y; @@ -6096,7 +6623,7 @@ screenchange(XEvent *e) { if (screens[i].root == xe->root) break; if (i >= ScreenCount(display)) - errx(1, "screenchange: screen not found\n"); + errx(1, "screenchange: screen not found"); /* brute force for now, just re-enumerate the regions */ scan_xrandr(i); @@ -6164,7 +6691,7 @@ setup_screens(void) if ((screens = calloc(ScreenCount(display), sizeof(struct swm_screen))) == NULL) - errx(1, "calloc: screens"); + err(1, "calloc: screens"); /* initial Xrandr setup */ xrandr_support = XRRQueryExtension(display, @@ -6197,6 +6724,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; @@ -6234,7 +6762,7 @@ setup_globals(void) if ((spawn_term[0] = strdup("xterm")) == NULL) err(1, "setup_globals: strdup"); if ((clock_format = strdup("%a %b %d %R %Z %Y")) == NULL) - errx(1, "strdup"); + err(1, "strdup"); } void @@ -6266,7 +6794,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; @@ -6279,9 +6806,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))) @@ -6309,6 +6837,7 @@ main(int argc, char *argv[]) adelete = XInternAtom(display, "WM_DELETE_WINDOW", False); takefocus = XInternAtom(display, "WM_TAKE_FOCUS", False); a_wmname = XInternAtom(display, "WM_NAME", False); + a_netwmname = XInternAtom(display, "_NET_WM_NAME", False); a_utf8_string = XInternAtom(display, "UTF8_STRING", False); a_string = XInternAtom(display, "STRING", False); a_swm_iconic = XInternAtom(display, "_SWM_ICONIC", False); @@ -6337,7 +6866,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 */