X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/5a6f9473f2ebd8a85db681432d2af89a6b6f9e60..d5362eb9f74aafae8330ae3806f450fdd6ffe17b:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index c5f7d1c..2cc0d24 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -9,6 +9,7 @@ * Copyright (c) 2011-2012 Lawrence Teo * Copyright (c) 2011-2012 Tiago Cunha * Copyright (c) 2012-2015 David Hill + * Copyright (c) 2014-2015 Yuri D'Elia * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -332,9 +333,9 @@ bool cycle_visible = false; int term_width = 0; int font_adjusted = 0; unsigned int mod_key = MODKEY; +bool warp_focus = false; bool warp_pointer = false; -unsigned int mouse_button_move = XCB_BUTTON_INDEX_1; -unsigned int mouse_button_resize = XCB_BUTTON_INDEX_3; +bool workspace_clamp = false; /* dmenu search */ struct swm_region *search_r; @@ -657,6 +658,8 @@ union arg { #define SWM_ARG_ID_LOWER (106) #define SWM_ARG_ID_BAR_TOGGLE (110) #define SWM_ARG_ID_BAR_TOGGLE_WS (111) +#define SWM_ARG_ID_CYCLERG_MOVE_UP (112) +#define SWM_ARG_ID_CYCLERG_MOVE_DOWN (113) char **argv; }; @@ -675,7 +678,7 @@ struct quirk { #define SWM_Q_TRANSSZ (1<<1) /* transiend window size too small */ #define SWM_Q_ANYWHERE (1<<2) /* don't position this window */ #define SWM_Q_XTERM_FONTADJ (1<<3) /* adjust xterm fonts when resizing */ -#define SWM_Q_FULLSCREEN (1<<4) /* remove border */ +#define SWM_Q_FULLSCREEN (1<<4) /* remove border when fullscreen */ #define SWM_Q_FOCUSPREV (1<<5) /* focus on caller */ #define SWM_Q_NOFOCUSONMAP (1<<6) /* Don't focus on window when mapped. */ #define SWM_Q_FOCUSONMAP_SINGLE (1<<7) /* Only focus if single win of type. */ @@ -683,6 +686,7 @@ struct quirk { #define SWM_Q_IGNOREPID (1<<9) /* Ignore PID when determining ws. */ #define SWM_Q_IGNORESPAWNWS (1<<10) /* Ignore _SWM_WS when managing win. */ #define SWM_Q_NOFOCUSCYCLE (1<<11) /* Remove from normal focus cycle. */ +#define SWM_Q_MINIMALBORDER (1<<12) /* Remove border when floating/unfocused */ }; TAILQ_HEAD(quirk_list, quirk); struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); @@ -886,6 +890,8 @@ enum keyfuncid { KF_RG_7, KF_RG_8, KF_RG_9, + KF_RG_MOVE_NEXT, + KF_RG_MOVE_PREV, KF_RG_NEXT, KF_RG_PREV, KF_SCREEN_NEXT, @@ -893,10 +899,10 @@ enum keyfuncid { KF_SEARCH_WIN, KF_SEARCH_WORKSPACE, KF_SPAWN_CUSTOM, + KF_STACK_BALANCE, KF_STACK_INC, KF_STACK_DEC, KF_STACK_RESET, - KF_STACK_BALANCE, KF_SWAP_MAIN, KF_SWAP_NEXT, KF_SWAP_PREV, @@ -978,6 +984,8 @@ void center_pointer(struct swm_region *); void check_conn(void); void clear_keys(void); int clear_maximized(struct workspace *); +void clear_quirks(void); +void clear_spawns(void); void clientmessage(xcb_client_message_event_t *); void client_msg(struct ws_win *, xcb_atom_t, xcb_timestamp_t); int conf_load(const char *, int); @@ -1125,8 +1133,6 @@ int setautorun(const char *, const char *, int); int setconfbinding(const char *, const char *, int); int setconfcolor(const char *, const char *, int); int setconfmodkey(const char *, const char *, int); -int setconfmousebuttonmove(const char *, const char *, int); -int setconfmousebuttonresize(const char *, const char *, int); int setconfquirk(const char *, const char *, int); int setconfregion(const char *, const char *, int); int setconfspawn(const char *, const char *, int); @@ -1174,7 +1180,6 @@ void unmap_window(struct ws_win *); void updatenumlockmask(void); void update_floater(struct ws_win *); void update_modkey(unsigned int); -unsigned char update_mousebutton(unsigned char, unsigned int); void update_win_stacking(struct ws_win *); void update_window(struct ws_win *); void update_window_color(struct ws_win *); @@ -2222,6 +2227,8 @@ bar_urgent(char *s, size_t sz) strlcat(s, "- ", sz); } } + if(urgent_collapse && s[0]) + s[strlen(s) - 1] = 0; } void @@ -3600,6 +3607,15 @@ unfocus_win(struct ws_win *win) if (win->ws->always_raise) raise_window(win); + /* Update border width */ + if (win->bordered && (win->quirks & SWM_Q_MINIMALBORDER) && + FLOATING(win)) { + win->bordered = 0; + X(win) += border_width; + Y(win) += border_width; + update_window(win); + } + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -3639,6 +3655,16 @@ focus_win(struct ws_win *win) &cfw->s->c[(MAXIMIZED(cfw) ? SWM_S_COLOR_UNFOCUS_MAXIMIZED : SWM_S_COLOR_UNFOCUS)].pixel); + + /* Update border width */ + if (cfw->bordered && + (cfw->quirks & SWM_Q_MINIMALBORDER) && + FLOATING(cfw)) { + cfw->bordered = 0; + X(cfw) += border_width; + Y(cfw) += border_width; + update_window(cfw); + } } else { unfocus_win(cfw); } @@ -3727,10 +3753,20 @@ focus_win(struct ws_win *win) &win->id); } - if (cfw != win) + if (cfw != win) { /* Update window border even if workspace is hidden. */ update_window_color(win); + /* Update border width */ + if (!win->bordered && WS_FOCUSED(win->ws) && + (win->quirks & SWM_Q_MINIMALBORDER) && FLOATING(win)) { + win->bordered = 1; + X(win) -= border_width; + Y(win) -= border_width; + update_window(win); + } + } + out: bar_draw(); @@ -3881,6 +3917,20 @@ switchws(struct swm_region *r, union arg *args) if (new_ws == old_ws) return; + other_r = new_ws->r; + if (other_r && workspace_clamp) { + DNPRINTF(SWM_D_WS, "switchws: ws clamped.\n"); + + if (warp_focus) { + DNPRINTF(SWM_D_WS, "switchws: warping focus to region " + "with ws %d.\n", wsid); + focus_region(other_r); + center_pointer(other_r); + focus_flush(); + } + return; + } + if ((win = old_ws->focus) != NULL) { update_window_color(win); @@ -3889,17 +3939,17 @@ switchws(struct swm_region *r, union arg *args) &none); } - other_r = new_ws->r; - if (other_r == NULL) { - /* the other workspace is hidden, hide this one */ - old_ws->r = NULL; - unmap_old = true; - } else { + if (other_r) { /* the other ws is visible in another region, exchange them */ other_r->ws_prior = new_ws; other_r->ws = old_ws; old_ws->r = other_r; + } else { + /* the other workspace is hidden, hide this one */ + old_ws->r = NULL; + unmap_old = true; } + this_r->ws_prior = old_ws; this_r->ws = new_ws; new_ws->r = this_r; @@ -4044,6 +4094,7 @@ focusrg(struct swm_region *r, union arg *args) void cyclerg(struct swm_region *r, union arg *args) { + union arg a; struct swm_region *rr = NULL; int i, num_screens; @@ -4057,11 +4108,13 @@ cyclerg(struct swm_region *r, union arg *args) switch (args->id) { case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_MOVE_UP: rr = TAILQ_NEXT(r, entry); if (rr == NULL) rr = TAILQ_FIRST(&screens[i].rl); break; case SWM_ARG_ID_CYCLERG_DOWN: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: rr = TAILQ_PREV(r, swm_region_list, entry); if (rr == NULL) rr = TAILQ_LAST(&screens[i].rl, swm_region_list); @@ -4072,9 +4125,22 @@ cyclerg(struct swm_region *r, union arg *args) if (rr == NULL) return; - focus_region(rr); - center_pointer(rr); - focus_flush(); + switch (args->id) { + case SWM_ARG_ID_CYCLERG_UP: + case SWM_ARG_ID_CYCLERG_DOWN: + focus_region(rr); + center_pointer(rr); + focus_flush(); + break; + case SWM_ARG_ID_CYCLERG_MOVE_UP: + case SWM_ARG_ID_CYCLERG_MOVE_DOWN: + a.id = rr->ws->idx; + switchws(r, &a); + break; + default: + return; + }; + DNPRINTF(SWM_D_FOCUS, "cyclerg: done\n"); } @@ -4673,9 +4739,11 @@ update_floater(struct ws_win *win) if (r != ws->old_r) load_float_geom(win); - if ((win->quirks & SWM_Q_FULLSCREEN) && - WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) { - /* Remove border for FULLSCREEN quirk. */ + if (((win->quirks & SWM_Q_FULLSCREEN) && + WIDTH(win) >= WIDTH(r) && HEIGHT(win) >= HEIGHT(r)) || + ((!WS_FOCUSED(win->ws) || win->ws->focus != win) && + (win->quirks & SWM_Q_MINIMALBORDER))) { + /* Remove border */ win->bordered = false; } else if (!MANUAL(win)) { if (TRANS(win) && (win->quirks & SWM_Q_TRANSSZ)) { @@ -4950,9 +5018,6 @@ vertical_config(struct workspace *ws, int id) ws->l_state.vertical_mwin = 1; ws->l_state.vertical_stacks = 1; break; - case SWM_ARG_ID_STACKBALANCE: - ws->l_state.vertical_msize = SWM_V_SLICE / (ws->l_state.vertical_stacks + 1); - break; case SWM_ARG_ID_MASTERSHRINK: if (ws->l_state.vertical_msize > 1) ws->l_state.vertical_msize--; @@ -4968,6 +5033,9 @@ vertical_config(struct workspace *ws, int id) if (ws->l_state.vertical_mwin > 0) ws->l_state.vertical_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.vertical_msize = SWM_V_SLICE / (ws->l_state.vertical_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.vertical_stacks++; break; @@ -5003,9 +5071,6 @@ horizontal_config(struct workspace *ws, int id) ws->l_state.horizontal_msize = SWM_H_SLICE / 2; ws->l_state.horizontal_stacks = 1; break; - case SWM_ARG_ID_STACKBALANCE: - ws->l_state.horizontal_msize = SWM_H_SLICE / (ws->l_state.horizontal_stacks + 1); - break; case SWM_ARG_ID_MASTERSHRINK: if (ws->l_state.horizontal_msize > 1) ws->l_state.horizontal_msize--; @@ -5021,6 +5086,9 @@ horizontal_config(struct workspace *ws, int id) if (ws->l_state.horizontal_mwin > 0) ws->l_state.horizontal_mwin--; break; + case SWM_ARG_ID_STACKBALANCE: + ws->l_state.horizontal_msize = SWM_H_SLICE / (ws->l_state.horizontal_stacks + 1); + break; case SWM_ARG_ID_STACKINC: ws->l_state.horizontal_stacks++; break; @@ -5824,10 +5892,13 @@ ewmh_update_current_desktop(void) int num_screens, i; num_screens = get_screen_count(); - for (i = 0; i < num_screens; ++i) - xcb_change_property(conn, XCB_PROP_MODE_REPLACE, - screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom, - XCB_ATOM_CARDINAL, 32, 1, &screens[i].r_focus->ws->idx); + for (i = 0; i < num_screens; ++i) { + if (screens[i].r_focus) + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, + screens[i].root, ewmh[_NET_CURRENT_DESKTOP].atom, + XCB_ATOM_CARDINAL, 32, 1, + &screens[i].r_focus->ws->idx); + } } void @@ -6710,6 +6781,8 @@ struct keyfunc { { "rg_7", focusrg, {.id = 6} }, { "rg_8", focusrg, {.id = 7} }, { "rg_9", focusrg, {.id = 8} }, + { "rg_move_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_UP} }, + { "rg_move_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_MOVE_DOWN} }, { "rg_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, { "rg_prev", cyclerg, {.id = SWM_ARG_ID_CYCLERG_DOWN} }, { "screen_next", cyclerg, {.id = SWM_ARG_ID_CYCLERG_UP} }, @@ -6717,10 +6790,10 @@ struct keyfunc { { "search_win", search_win, {0} }, { "search_workspace", search_workspace, {0} }, { "spawn_custom", NULL, {0} }, + { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} }, { "stack_inc", stack_config, {.id = SWM_ARG_ID_STACKINC} }, { "stack_dec", stack_config, {.id = SWM_ARG_ID_STACKDEC} }, { "stack_reset", stack_config, {.id = SWM_ARG_ID_STACKRESET} }, - { "stack_balance", stack_config, {.id = SWM_ARG_ID_STACKBALANCE} }, { "swap_main", swapwin, {.id = SWM_ARG_ID_SWAPMAIN} }, { "swap_next", swapwin, {.id = SWM_ARG_ID_SWAPNEXT} }, { "swap_prev", swapwin, {.id = SWM_ARG_ID_SWAPPREV} }, @@ -6816,31 +6889,6 @@ update_modkey(unsigned int mod) buttons[i].mask = mod; } -unsigned char -update_mousebutton(unsigned char type, unsigned int but) -{ - int i; - - switch (type) { - case 0: - mouse_button_move = but; - break; - case 1: - mouse_button_resize = but; - break; - } - - for (i = 0; i < LENGTH(buttons); i++) { - if (buttons[i].func == move) - buttons[i].button = mouse_button_move; - - if (buttons[i].func == resize) - buttons[i].button = mouse_button_resize; - } - - return(1); -} - int spawn_expand(struct swm_region *r, union arg *args, const char *spawn_name, char ***ret_args) @@ -7107,6 +7155,16 @@ spawn_remove(struct spawn_prog *sp) DNPRINTF(SWM_D_SPAWN, "spawn_remove: leave\n"); } +void +clear_spawns(void) +{ + struct spawn_prog *sp; + + while ((sp = TAILQ_FIRST(&spawns)) != NULL) { + spawn_remove(sp); + } +} + struct spawn_prog* spawn_find(const char *name) { @@ -7523,7 +7581,6 @@ setup_keys(void) setkeybinding(MODKEY_SHIFT, XK_comma, KF_STACK_INC, NULL); setkeybinding(MODKEY_SHIFT, XK_period, KF_STACK_DEC, NULL); setkeybinding(MODKEY_SHIFT, XK_space, KF_STACK_RESET, NULL); - setkeybinding(MODKEY_SHIFT, XK_h, KF_STACK_BALANCE, NULL); setkeybinding(MODKEY, XK_Return, KF_SWAP_MAIN, NULL); setkeybinding(MODKEY_SHIFT, XK_j, KF_SWAP_NEXT, NULL); setkeybinding(MODKEY_SHIFT, XK_k, KF_SWAP_PREV, NULL); @@ -7722,6 +7779,7 @@ const char *quirkname[] = { "IGNOREPID", "IGNORESPAWNWS", "NOFOCUSCYCLE", + "MINIMALBORDER", }; /* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */ @@ -7862,6 +7920,16 @@ quirk_free(struct quirk *qp) free(qp); } +void +clear_quirks(void) +{ + struct quirk *qp; + + while ((qp = TAILQ_FIRST(&quirks)) != NULL) { + quirk_remove(qp); + } +} + void quirk_replace(struct quirk *qp, const char *class, const char *instance, const char *name, uint32_t quirk, int ws) @@ -8049,10 +8117,12 @@ enum { SWM_S_URGENT_COLLAPSE, SWM_S_URGENT_ENABLED, SWM_S_VERBOSE_LAYOUT, + SWM_S_WARP_FOCUS, SWM_S_WARP_POINTER, SWM_S_WINDOW_CLASS_ENABLED, SWM_S_WINDOW_INSTANCE_ENABLED, SWM_S_WINDOW_NAME_ENABLED, + SWM_S_WORKSPACE_CLAMP, SWM_S_WORKSPACE_LIMIT, SWM_S_WORKSPACE_NAME, }; @@ -8267,6 +8337,9 @@ setconfvalue(const char *selector, const char *value, int flags) layouts[i].l_string = plain_stacker; } break; + case SWM_S_WARP_FOCUS: + warp_focus = (atoi(value) != 0); + break; case SWM_S_WARP_POINTER: warp_pointer = (atoi(value) != 0); break; @@ -8279,6 +8352,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_WINDOW_NAME_ENABLED: window_name_enabled = (atoi(value) != 0); break; + case SWM_S_WORKSPACE_CLAMP: + workspace_clamp = (atoi(value) != 0); + break; case SWM_S_WORKSPACE_LIMIT: workspace_limit = atoi(value); if (workspace_limit > SWM_WS_MAX) @@ -8342,48 +8418,6 @@ setconfmodkey(const char *selector, const char *value, int flags) return (0); } -int -setconfmousebuttonmove(const char *selector, const char *value, int flags) -{ - /* suppress unused warnings since vars are needed */ - (void)selector; - (void)flags; - - if (strncasecmp(value, "But1", strlen("But1")) == 0) { - if (!update_mousebutton(0, XCB_BUTTON_INDEX_1)) - return (1); - } else if (strncasecmp(value, "But2", strlen("But2")) == 0) { - if (!update_mousebutton(0, XCB_BUTTON_INDEX_2)) - return (1); - } else if (strncasecmp(value, "But3", strlen("But3")) == 0) { - if (!update_mousebutton(0, XCB_BUTTON_INDEX_3)) - return (1); - } else - return (1); - return (0); -} - -int -setconfmousebuttonresize(const char *selector, const char *value, int flags) -{ - /* suppress unused warnings since vars are needed */ - (void)selector; - (void)flags; - - if (strncasecmp(value, "But1", strlen("But1")) == 0) { - if (!update_mousebutton(1, XCB_BUTTON_INDEX_1)) - return (1); - } else if (strncasecmp(value, "But2", strlen("But2")) == 0) { - if (!update_mousebutton(1, XCB_BUTTON_INDEX_2)) - return (1); - } else if (strncasecmp(value, "But3", strlen("But3")) == 0) { - if (!update_mousebutton(1, XCB_BUTTON_INDEX_3)) - return (1); - } else - return (1); - return (0); -} - int setconfcolor(const char *selector, const char *value, int flags) { @@ -8629,12 +8663,10 @@ struct config_option configopt[] = { { "focus_mode", setconfvalue, SWM_S_FOCUS_MODE }, { "iconic_enabled", setconfvalue, SWM_S_ICONIC_ENABLED }, { "java_workaround", setconfvalue, SWM_S_JAVA_WORKAROUND }, - { "maximize_hide_bar", setconfvalue, SWM_S_MAXIMIZE_HIDE_BAR }, { "keyboard_mapping", setkeymapping, 0 }, { "layout", setlayout, 0 }, + { "maximize_hide_bar", setconfvalue, SWM_S_MAXIMIZE_HIDE_BAR }, { "modkey", setconfmodkey, 0 }, - { "move_button", setconfmousebuttonmove, 0 }, - { "resize_button", setconfmousebuttonresize, 0 }, { "program", setconfspawn, 0 }, { "quirk", setconfquirk, 0 }, { "region", setconfregion, 0 }, @@ -8651,10 +8683,12 @@ struct config_option configopt[] = { { "urgent_collapse", setconfvalue, SWM_S_URGENT_COLLAPSE }, { "urgent_enabled", setconfvalue, SWM_S_URGENT_ENABLED }, { "verbose_layout", setconfvalue, SWM_S_VERBOSE_LAYOUT }, + { "warp_focus", setconfvalue, SWM_S_WARP_FOCUS }, { "warp_pointer", setconfvalue, SWM_S_WARP_POINTER }, { "window_class_enabled", setconfvalue, SWM_S_WINDOW_CLASS_ENABLED }, { "window_instance_enabled", setconfvalue, SWM_S_WINDOW_INSTANCE_ENABLED }, { "window_name_enabled", setconfvalue, SWM_S_WINDOW_NAME_ENABLED }, + { "workspace_clamp", setconfvalue, SWM_S_WORKSPACE_CLAMP }, { "workspace_limit", setconfvalue, SWM_S_WORKSPACE_LIMIT }, { "name", setconfvalue, SWM_S_WORKSPACE_NAME }, }; @@ -8800,12 +8834,6 @@ conf_load(const char *filename, int keymapping) if (line) free(line); fclose(config); - - if (mouse_button_move == mouse_button_resize) { - add_startup_exception("%s: move and resize mouse buttons match", - filename); - } - DNPRINTF(SWM_D_CONF, "conf_load: end\n"); return (0); @@ -10791,10 +10819,17 @@ shutdown_cleanup(void) cursors_cleanup(); + clear_quirks(); + clear_spawns(); + clear_keys(); + teardown_ewmh(); num_screens = get_screen_count(); for (i = 0; i < num_screens; ++i) { + struct swm_region *r; + int j; + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, screens[i].root, XCB_CURRENT_TIME); @@ -10806,13 +10841,45 @@ shutdown_cleanup(void) XftColorFree(display, DefaultVisual(display, i), DefaultColormap(display, i), &search_font_color); } + + for (j = 0; j < SWM_S_COLOR_MAX; ++j) { + free(screens[i].c[j].name); + } + + for (j = 0; j < SWM_WS_MAX; ++j) { + struct ws_win *win; + + free(screens[i].ws[j].name); + + while ((win = TAILQ_FIRST(&screens[i].ws[j].winlist)) != NULL) { + TAILQ_REMOVE(&screens[i].ws[j].winlist, win, entry); + free(win); + } + } + + while ((r = TAILQ_FIRST(&screens[i].rl)) != NULL) { + TAILQ_REMOVE(&screens[i].rl, r, entry); + free(r->bar); + free(r); + } + + while ((r = TAILQ_FIRST(&screens[i].orl)) != NULL) { + TAILQ_REMOVE(&screens[i].rl, r, entry); + free(r->bar); + free(r); + } } + free(screens); - if (bar_font_legacy) + free(bar_format); + free(bar_fonts); + free(clock_format); + free(startup_exception); + + if (bar_fs) XFreeFontSet(display, bar_fs); - else { + if (bar_font_legacy == false) XftFontClose(display, bar_font); - } xcb_key_symbols_free(syms); xcb_flush(conn);