X-Git-Url: https://code.delx.au/spectrwm/blobdiff_plain/56313f2dcc507dc9c7d2387debe869fcd87a812e..4f61f954631d86255dab707a0b91b44b63fed06f:/spectrwm.c diff --git a/spectrwm.c b/spectrwm.c index 5fc8877..1542fe1 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -1,14 +1,15 @@ /* - * Copyright (c) 2009-2012 Marco Peereboom + * Copyright (c) 2009-2015 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-2014 Reginald Kennedy + * Copyright (c) 2011-2015 Reginald Kennedy * Copyright (c) 2011-2012 Lawrence Teo * Copyright (c) 2011-2012 Tiago Cunha - * Copyright (c) 2012-2013 David Hill + * 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 @@ -77,6 +78,7 @@ #include #include #include +#include #include #include #include @@ -331,7 +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; +bool workspace_clamp = false; /* dmenu search */ struct swm_region *search_r; @@ -401,6 +405,7 @@ char *bar_format = NULL; bool stack_enabled = true; bool clock_enabled = true; bool iconic_enabled = false; +bool maximize_hide_bar = false; bool urgent_enabled = false; bool urgent_collapse = false; char *clock_format = NULL; @@ -624,6 +629,7 @@ union arg { #define SWM_ARG_ID_FLIPLAYOUT (24) #define SWM_ARG_ID_STACKRESET (30) #define SWM_ARG_ID_STACKINIT (31) +#define SWM_ARG_ID_STACKBALANCE (32) #define SWM_ARG_ID_CYCLEWS_UP (40) #define SWM_ARG_ID_CYCLEWS_DOWN (41) #define SWM_ARG_ID_CYCLERG_UP (42) @@ -652,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; }; @@ -677,6 +685,7 @@ struct quirk { #define SWM_Q_OBEYAPPFOCUSREQ (1<<8) /* Focus when applications ask. */ #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. */ }; TAILQ_HEAD(quirk_list, quirk); struct quirk_list quirks = TAILQ_HEAD_INITIALIZER(quirks); @@ -880,6 +889,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, @@ -887,6 +898,7 @@ enum keyfuncid { KF_SEARCH_WIN, KF_SEARCH_WORKSPACE, KF_SPAWN_CUSTOM, + KF_STACK_BALANCE, KF_STACK_INC, KF_STACK_DEC, KF_STACK_RESET, @@ -1041,6 +1053,7 @@ char *get_source_type_label(uint32_t); char *get_stack_mode_name(uint8_t); #endif int32_t get_swm_ws(xcb_window_t); +bool get_urgent(struct ws_win *); char *get_win_name(xcb_window_t); uint8_t get_win_state(xcb_window_t); void get_wm_protocols(struct ws_win *); @@ -1063,6 +1076,7 @@ void kill_refs(struct ws_win *); void leavenotify(xcb_leave_notify_event_t *); #endif void load_float_geom(struct ws_win *); +void lower_window(struct ws_win *); struct ws_win *manage_window(xcb_window_t, int, bool); void map_window(struct ws_win *); void mapnotify(xcb_map_notify_event_t *); @@ -1085,6 +1099,7 @@ void print_win_geom(xcb_window_t); #endif void propertynotify(xcb_property_notify_event_t *); void quirk_free(struct quirk *); +void clear_quirks(void); void quirk_insert(const char *, const char *, const char *, uint32_t, int); void quirk_remove(struct quirk *); void quirk_replace(struct quirk *, const char *, const char *, const char *, @@ -1144,6 +1159,7 @@ int spawn_expand(struct swm_region *, union arg *, const char *, char ***); void spawn_insert(const char *, const char *, int); struct spawn_prog *spawn_find(const char *); void spawn_remove(struct spawn_prog *); +void clear_spawns(void); void spawn_replace(struct spawn_prog *, const char *, const char *, int); void spawn_select(struct swm_region *, union arg *, const char *, int *); void stack_config(struct swm_region *, union arg *); @@ -2168,6 +2184,22 @@ bar_window_name(char *s, size_t sz, struct swm_region *r) free(title); } +bool +get_urgent(struct ws_win *win) +{ + xcb_icccm_wm_hints_t hints; + xcb_get_property_cookie_t c; + bool urgent = false; + + if (win) { + c = xcb_icccm_get_wm_hints(conn, win->id); + if (xcb_icccm_get_wm_hints_reply(conn, c, &hints, NULL)) + urgent = xcb_icccm_wm_hints_get_urgency(&hints); + } + + return urgent; +} + void bar_urgent(char *s, size_t sz) { @@ -2175,8 +2207,6 @@ bar_urgent(char *s, size_t sz) int i, j, num_screens; bool urgent[SWM_WS_MAX]; char b[8]; - xcb_get_property_cookie_t c; - xcb_icccm_wm_hints_t hints; for (i = 0; i < workspace_limit; i++) urgent[i] = false; @@ -2184,14 +2214,9 @@ bar_urgent(char *s, size_t sz) num_screens = get_screen_count(); for (i = 0; i < num_screens; i++) for (j = 0; j < workspace_limit; j++) - TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) { - c = xcb_icccm_get_wm_hints(conn, win->id); - if (xcb_icccm_get_wm_hints_reply(conn, c, - &hints, NULL) == 0) - continue; - if (hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY) + TAILQ_FOREACH(win, &screens[i].ws[j].winlist, entry) + if (get_urgent(win)) urgent[j] = true; - } for (i = 0; i < workspace_limit; i++) { if (urgent[i]) { @@ -2201,6 +2226,8 @@ bar_urgent(char *s, size_t sz) strlcat(s, "- ", sz); } } + if(urgent_collapse && s[0]) + s[strlen(s) - 1] = 0; } void @@ -3006,14 +3033,74 @@ quit(struct swm_region *r, union arg *args) running = 0; } +void +lower_window(struct ws_win *win) +{ + struct ws_win *target = NULL; + struct workspace *ws; + + if (win == NULL) + return; + + ws = win->ws; + + DNPRINTF(SWM_D_EVENT, "lower_window: win %#x\n", win->id); + + TAILQ_FOREACH(target, &ws->stack, stack_entry) { + if (target == win || ICONIC(target)) + continue; + if (ws->cur_layout == &layouts[SWM_MAX_STACK]) + break; + if (TRANS(win)) { + if (win->transient == target->transient) + continue; + if (win->transient == target->id) + break; + } + if (FULLSCREEN(target)) + continue; + if (FULLSCREEN(win)) + break; + if (MAXIMIZED(target)) + continue; + if (MAXIMIZED(win)) + break; + if (ABOVE(target) || TRANS(target)) + continue; + if (ABOVE(win) || TRANS(win)) + break; + } + + /* Change stack position. */ + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) + TAILQ_INSERT_BEFORE(target, win, stack_entry); + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); + +#ifdef SWM_DEBUG + if (swm_debug & SWM_D_STACK) { + DPRINTF("=== stacking order (top down) === \n"); + TAILQ_FOREACH(target, &ws->stack, stack_entry) { + DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " + "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)), + YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)), + YESNO(ICONIC(target))); + } + } +#endif + DNPRINTF(SWM_D_EVENT, "lower_window: done\n"); +} + void raise_window(struct ws_win *win) { struct ws_win *target = NULL; - struct swm_region *r; struct workspace *ws; - if (win == NULL || (r = win->ws->r) == NULL) + if (win == NULL) return; ws = win->ws; @@ -3035,23 +3122,25 @@ raise_window(struct ws_win *win) break; if (MAXIMIZED(target)) continue; - if (ABOVE(win) || TRANS(win)) + if (ABOVE(win) || TRANS(win) || + (win->ws->focus == win && ws->always_raise)) break; if (!ABOVE(target) && !TRANS(target)) break; } - if (target != NULL) { - /* Change stack position. */ - TAILQ_REMOVE(&ws->stack, win, stack_entry); + TAILQ_REMOVE(&ws->stack, win, stack_entry); + if (target) TAILQ_INSERT_BEFORE(target, win, stack_entry); - update_win_stacking(win); - } + else + TAILQ_INSERT_TAIL(&ws->stack, win, stack_entry); + + update_win_stacking(win); #ifdef SWM_DEBUG if (swm_debug & SWM_D_STACK) { DPRINTF("=== stacking order (top down) === \n"); - TAILQ_FOREACH(target, &r->ws->stack, stack_entry) { + TAILQ_FOREACH(target, &ws->stack, stack_entry) { DPRINTF("win %#x, fs: %s, maximized: %s, above: %s, " "iconic: %s\n", target->id, YESNO(FULLSCREEN(target)), YESNO(MAXIMIZED(target)), YESNO(ABOVE(target)), @@ -3073,10 +3162,14 @@ update_win_stacking(struct ws_win *win) return; sibling = TAILQ_NEXT(win, stack_entry); - if (sibling != NULL && FLOATING(win) == FLOATING(sibling)) + if (sibling != NULL && (FLOATING(win) == FLOATING(sibling) || + (win->ws->always_raise && win->ws->focus == win))) val[0] = sibling->id; + else if (FLOATING(win) || (win->ws->always_raise && + win->ws->focus == win)) + val[0] = r->bar->id; else - val[0] = FLOATING(win) ? r->bar->id : r->id; + val[0] = r->id; DNPRINTF(SWM_D_EVENT, "update_win_stacking: %#x, sibling %#x\n", win->id, val[0]); @@ -3509,6 +3602,10 @@ unfocus_win(struct ws_win *win) update_window_color(win); + /* Raise window to "top unfocused position." */ + if (win->ws->always_raise) + raise_window(win); + xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root, ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1, &none); @@ -3790,6 +3887,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); @@ -3798,17 +3909,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; @@ -3953,6 +4064,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; @@ -3966,11 +4078,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); @@ -3981,9 +4095,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"); } @@ -4270,7 +4397,6 @@ focus(struct swm_region *r, union arg *args) struct workspace *ws = NULL; union arg a; int i; - xcb_icccm_wm_hints_t hints; if (!(r && r->ws)) goto out; @@ -4307,7 +4433,8 @@ focus(struct swm_region *r, union arg *args) } while (winfocus && (ICONIC(winfocus) || winfocus->id == cur_focus->transient || (cur_focus->transient != XCB_WINDOW_NONE && - winfocus->transient == cur_focus->transient))); + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSNEXT: if (cur_focus == NULL) @@ -4323,7 +4450,8 @@ focus(struct swm_region *r, union arg *args) } while (winfocus && (ICONIC(winfocus) || winfocus->id == cur_focus->transient || (cur_focus->transient != XCB_WINDOW_NONE && - winfocus->transient == cur_focus->transient))); + winfocus->transient == cur_focus->transient) || + (winfocus->quirks & SWM_Q_NOFOCUSCYCLE))); break; case SWM_ARG_ID_FOCUSMAIN: if (cur_focus == NULL) @@ -4343,27 +4471,26 @@ focus(struct swm_region *r, union arg *args) head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) % workspace_limit].winlist); - while (head != NULL && - (head = TAILQ_NEXT(head, entry)) != NULL) { + while (head) { if (head == cur_focus) { - winfocus = cur_focus; - break; - } - if (xcb_icccm_get_wm_hints_reply(conn, - xcb_icccm_get_wm_hints(conn, head->id), - &hints, NULL) != 0 && - xcb_icccm_wm_hints_get_urgency(&hints)) { + if (i > 0) { + winfocus = cur_focus; + break; + } + } else if (get_urgent(head)) { winfocus = head; break; } + + head = TAILQ_NEXT(head, entry); } - if (winfocus != NULL) + if (winfocus) break; } /* Switch ws if new focus is on a different ws. */ - if (winfocus != NULL && winfocus->ws != ws) { + if (winfocus && winfocus->ws != ws) { a.id = winfocus->ws->idx; switchws(r, &a); } @@ -4564,7 +4691,7 @@ update_floater(struct ws_win *win) win->g = r->g; - if (bar_enabled && ws->bar_enabled) { + if (bar_enabled && ws->bar_enabled && !maximize_hide_bar) { if (!bar_at_bottom) Y(win) += bar_height; HEIGHT(win) -= bar_height; @@ -4790,7 +4917,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, bool flip) win_g.y += last_h + 2 * border_width + tile_gap; if (disable_border && !(bar_enabled && ws->bar_enabled) && - winno == 1){ + winno == 1) { bordered = false; win_g.w += 2 * border_width; win_g.h += 2 * border_width; @@ -4874,6 +5001,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; @@ -4924,6 +5054,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; @@ -5003,12 +5136,13 @@ max_stack(struct workspace *ws, struct swm_geometry *g) if (X(w) != gg.x || Y(w) != gg.y || WIDTH(w) != gg.w || HEIGHT(w) != gg.h) { w->g = gg; - if (bar_enabled && ws->bar_enabled){ - w->bordered = true; - } else { + + if (disable_border && !(bar_enabled && ws->bar_enabled)) { w->bordered = false; WIDTH(w) += 2 * border_width; HEIGHT(w) += 2 * border_width; + } else { + w->bordered = true; } update_window(w); @@ -5251,7 +5385,7 @@ pressbutton(struct swm_region *r, union arg *args) void raise_toggle(struct swm_region *r, union arg *args) { - /* suppress unused warning since var is needed */ + /* Suppress warning. */ (void)args; if (r == NULL || r->ws == NULL) @@ -5262,9 +5396,8 @@ raise_toggle(struct swm_region *r, union arg *args) r->ws->always_raise = !r->ws->always_raise; - /* bring floaters back to top */ - if (!r->ws->always_raise) - stack(); + /* Update focused win stacking order based on new always_raise value. */ + raise_window(r->ws->focus); focus_flush(); } @@ -5273,7 +5406,8 @@ void iconify(struct swm_region *r, union arg *args) { struct ws_win *w; - /* suppress unused warning since var is needed */ + + /* Suppress warning. */ (void)args; if ((w = r->ws->focus) == NULL) @@ -5726,10 +5860,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 @@ -6612,6 +6749,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} }, @@ -6619,6 +6758,7 @@ 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} }, @@ -6983,6 +7123,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) { @@ -7147,6 +7297,8 @@ parsekeys(const char *keystr, unsigned int currmod, unsigned int *mod, KeySym *k *mod |= XCB_MOD_MASK_3; else if (strncmp(name, "Mod4", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_4; + else if (strncmp(name, "Mod5", SWM_MODNAME_SIZE) == 0) + *mod |= XCB_MOD_MASK_5; else if (strncasecmp(name, "SHIFT", SWM_MODNAME_SIZE) == 0) *mod |= XCB_MOD_MASK_SHIFT; else if (strncasecmp(name, "CONTROL", SWM_MODNAME_SIZE) == 0) @@ -7594,6 +7746,7 @@ const char *quirkname[] = { "OBEYAPPFOCUSREQ", "IGNOREPID", "IGNORESPAWNWS", + "NOFOCUSCYCLE", }; /* SWM_Q_DELIM: retain '|' for back compat for now (2009-08-11) */ @@ -7734,6 +7887,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) @@ -7909,6 +8072,7 @@ enum { SWM_S_FOCUS_MODE, SWM_S_ICONIC_ENABLED, SWM_S_JAVA_WORKAROUND, + SWM_S_MAXIMIZE_HIDE_BAR, SWM_S_REGION_PADDING, SWM_S_SPAWN_ORDER, SWM_S_SPAWN_TERM, @@ -7920,10 +8084,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, }; @@ -8082,6 +8248,9 @@ setconfvalue(const char *selector, const char *value, int flags) case SWM_S_JAVA_WORKAROUND: java_workaround = (atoi(value) != 0); break; + case SWM_S_MAXIMIZE_HIDE_BAR: + maximize_hide_bar = atoi(value); + break; case SWM_S_REGION_PADDING: region_padding = atoi(value); if (region_padding < 0) @@ -8135,6 +8304,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; @@ -8147,6 +8319,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) @@ -8203,6 +8378,8 @@ setconfmodkey(const char *selector, const char *value, int flags) update_modkey(XCB_MOD_MASK_3); else if (strncasecmp(value, "Mod4", strlen("Mod4")) == 0) update_modkey(XCB_MOD_MASK_4); + else if (strncasecmp(value, "Mod5", strlen("Mod5")) == 0) + update_modkey(XCB_MOD_MASK_5); else return (1); return (0); @@ -8455,6 +8632,7 @@ struct config_option configopt[] = { { "java_workaround", setconfvalue, SWM_S_JAVA_WORKAROUND }, { "keyboard_mapping", setkeymapping, 0 }, { "layout", setlayout, 0 }, + { "maximize_hide_bar", setconfvalue, SWM_S_MAXIMIZE_HIDE_BAR }, { "modkey", setconfmodkey, 0 }, { "program", setconfspawn, 0 }, { "quirk", setconfquirk, 0 }, @@ -8472,10 +8650,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 }, }; @@ -8963,7 +9143,7 @@ manage_window(xcb_window_t id, int spawn_pos, bool mapped) } out: - /* Figure out where to stack the window in the workspace. */ + /* Figure out where to insert the window in the workspace list. */ if (trans && (ww = find_window(trans))) TAILQ_INSERT_AFTER(&win->ws->winlist, ww, win, entry); else if (win->ws->focus && spawn_pos == SWM_STACK_ABOVE) @@ -8984,7 +9164,8 @@ out: ewmh_update_client_list(); - TAILQ_INSERT_TAIL(&win->ws->stack, win, stack_entry); + TAILQ_INSERT_HEAD(&win->ws->stack, win, stack_entry); + lower_window(win); /* Get/apply initial _NET_WM_STATE */ ewmh_get_wm_state(win); @@ -9533,6 +9714,12 @@ enternotify(xcb_enter_notify_event_t *e) return; } + if (focus_mode != SWM_FOCUS_FOLLOW && + e->mode == XCB_NOTIFY_MODE_UNGRAB) { + DNPRINTF(SWM_D_EVENT, "enternotify: ungrab; ignoring.\n"); + return; + } + last_event_time = e->time; if ((win = find_window(e->event)) == NULL) { @@ -10599,10 +10786,16 @@ 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) { + int j; + xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, screens[i].root, XCB_CURRENT_TIME); @@ -10614,7 +10807,19 @@ 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) { + free(screens[i].ws[j].name); + } } + free(screens); + + free(bar_format); + free(clock_format); if (bar_font_legacy) XFreeFontSet(display, bar_fs); @@ -10703,10 +10908,8 @@ main(int argc, char *argv[]) int xfd, i, num_screens; struct sigaction sact; xcb_generic_event_t *evt; - struct timeval tv; - fd_set rd; - int rd_max; int num_readable; + struct pollfd pfd[2]; bool stdin_ready = false, startup = true; /* suppress unused warning since var is needed */ @@ -10843,7 +11046,11 @@ noconfig: TAILQ_FOREACH(r, &screens[i].rl, entry) r->ws->state = SWM_WS_STATE_MAPPED; - rd_max = xfd > STDIN_FILENO ? xfd : STDIN_FILENO; + memset(&pfd, 0, sizeof(pfd)); + pfd[0].fd = xfd; + pfd[0].events = POLLIN; + pfd[1].fd = STDIN_FILENO; + pfd[1].events = POLLIN; while (running) { while ((evt = xcb_poll_for_event(conn))) { @@ -10867,18 +11074,10 @@ noconfig: } } - FD_ZERO(&rd); - - if (bar_extra) - FD_SET(STDIN_FILENO, &rd); - - FD_SET(xfd, &rd); - tv.tv_sec = 1; - tv.tv_usec = 0; - num_readable = select(rd_max + 1, &rd, NULL, NULL, &tv); - if (num_readable == -1 && errno != EINTR) { - DNPRINTF(SWM_D_MISC, "select failed"); - } else if (num_readable > 0 && FD_ISSET(STDIN_FILENO, &rd)) { + num_readable = poll(pfd, bar_extra ? 2 : 1, 1000); + if (num_readable == -1) { + DNPRINTF(SWM_D_MISC, "poll failed: %s", strerror(errno)); + } else if (num_readable > 0 && bar_extra && pfd[1].revents & POLLIN) { stdin_ready = true; }