From bb8117c675cf5ccc4a7ce345fcf2a79b4e23ec9f Mon Sep 17 00:00:00 2001 From: Reginald Kennedy Date: Sat, 20 Jul 2013 16:20:10 +0800 Subject: [PATCH] Add new focus_urgent binding. Focuses on the next window with the urgency hint set. The workspace is switched if needed. Fix description of urgent_enabled in man page. --- spectrwm.1 | 19 +++++--- spectrwm.c | 135 ++++++++++++++++++++++++++++++--------------------- spectrwm_cz.conf | 1 + spectrwm_es.conf | 1 + spectrwm_fr.conf | 1 + spectrwm_fr_ch.conf | 1 + spectrwm_se.conf | 1 + spectrwm_us.conf | 1 + 8 files changed, 98 insertions(+), 62 deletions(-) diff --git a/spectrwm.1 b/spectrwm.1 index d9697e4..42b8000 100644 --- a/spectrwm.1 +++ b/spectrwm.1 @@ -376,13 +376,14 @@ Enable by setting to 1. Enable or disable displaying the window title in the status bar. Enable by setting to 1. .It Ic urgent_enabled -Enable or disable the urgency hint. -Note that many terminal emulators require this to be enabled for it to -propagate. -In xterm, for example, one needs to add the following line -.Pa xterm.bellIsUrgent: true -to -.Pa .Xdefaults . +Enable or disable the urgency hint indicator in the status bar. +Note that many terminal emulators require an explicit setting for the bell +character to trigger urgency on the window. In xterm, for example, one needs to +add the following line to +.Pa .Xdefaults : +.Bd -literal -offset indent +xterm.bellIsUrgent: true +.Ed .It Ic verbose_layout Enable or disable displaying the current master window count and stack column/row count in the status bar. @@ -551,6 +552,8 @@ focus_prev .It Cm M-m focus_main .It Cm M-S-j +focus_urgent +.It Cm M-u swap_next .It Cm M-S-k swap_prev @@ -677,6 +680,8 @@ Focus next window in workspace. Focus previous window in workspace. .It Cm focus_main Focus on main window in workspace. +.It Cm focus_urgent +Focus on next window with the urgency hint flag set. The workspace is switched if needed. .It Cm swap_next Swap with next window in workspace. .It Cm swap_prev diff --git a/spectrwm.c b/spectrwm.c index 4aff709..aef7c60 100644 --- a/spectrwm.c +++ b/spectrwm.c @@ -569,6 +569,7 @@ union arg { #define SWM_ARG_ID_FOCUSNEXT (0) #define SWM_ARG_ID_FOCUSPREV (1) #define SWM_ARG_ID_FOCUSMAIN (2) +#define SWM_ARG_ID_FOCUSURGENT (3) #define SWM_ARG_ID_SWAPNEXT (10) #define SWM_ARG_ID_SWAPPREV (11) #define SWM_ARG_ID_SWAPMAIN (12) @@ -744,6 +745,7 @@ enum keyfuncid { KF_FOCUS_MAIN, KF_FOCUS_NEXT, KF_FOCUS_PREV, + KF_FOCUS_URGENT, KF_HEIGHT_GROW, KF_HEIGHT_SHRINK, KF_ICONIFY, @@ -3945,86 +3947,107 @@ focus(struct swm_region *r, union arg *args) struct ws_win *head, *cur_focus = NULL, *winfocus = NULL; struct ws_win_list *wl = NULL; struct workspace *ws = NULL; - int all_iconics; + union arg a; + int i; + xcb_icccm_wm_hints_t hints; if (!(r && r->ws)) - return; + goto out; DNPRINTF(SWM_D_FOCUS, "focus: id: %d\n", args->id); - if ((cur_focus = r->ws->focus) == NULL) - return; + cur_focus = r->ws->focus; 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) { - all_iconics = 0; - break; - } - if (all_iconics) - return; + + /* Make sure an uniconified window has focus, if one exists. */ + if (cur_focus == NULL) { + cur_focus = TAILQ_FIRST(wl); + while (cur_focus != NULL && cur_focus->iconic) + cur_focus = TAILQ_NEXT(cur_focus, entry); + } switch (args->id) { case SWM_ARG_ID_FOCUSPREV: - head = TAILQ_PREV(cur_focus, ws_win_list, entry); - if (head == NULL) - head = TAILQ_LAST(wl, ws_win_list); - winfocus = head; - if (WINID(winfocus) == cur_focus->transient) { - head = TAILQ_PREV(winfocus, ws_win_list, entry); - if (head == NULL) - head = TAILQ_LAST(wl, ws_win_list); - winfocus = head; - } + if (cur_focus == NULL) + goto out; - /* skip iconics */ - if (winfocus && winfocus->iconic) { - while (winfocus != cur_focus) { - if (winfocus == NULL) - winfocus = TAILQ_LAST(wl, ws_win_list); - if (!winfocus->iconic) - break; - winfocus = TAILQ_PREV(winfocus, ws_win_list, - entry); - } - } + winfocus = cur_focus; + do { + winfocus = TAILQ_PREV(winfocus, ws_win_list, entry); + if (winfocus == NULL) + winfocus = TAILQ_LAST(wl, ws_win_list); + if (winfocus == cur_focus) + break; + } while (winfocus != NULL && + (winfocus->iconic || winfocus->id == cur_focus->transient)); break; - case SWM_ARG_ID_FOCUSNEXT: - head = TAILQ_NEXT(cur_focus, entry); - if (head == NULL) - head = TAILQ_FIRST(wl); - winfocus = head; - - /* skip iconics */ - if (winfocus && winfocus->iconic) { - while (winfocus != cur_focus) { - if (winfocus == NULL) - winfocus = TAILQ_FIRST(wl); - if (!winfocus->iconic) - break; - winfocus = TAILQ_NEXT(winfocus, entry); - } - } - break; + if (cur_focus == NULL) + goto out; + winfocus = cur_focus; + do { + winfocus = TAILQ_NEXT(winfocus, entry); + if (winfocus == NULL) + winfocus = TAILQ_FIRST(wl); + if (winfocus == cur_focus) + break; + } while (winfocus != NULL && + (winfocus->iconic || winfocus->id == cur_focus->transient)); + break; case SWM_ARG_ID_FOCUSMAIN: + if (cur_focus == NULL) + goto out; + winfocus = TAILQ_FIRST(wl); if (winfocus == cur_focus) winfocus = cur_focus->ws->focus_prev; break; + case SWM_ARG_ID_FOCUSURGENT: + /* Search forward for the next urgent window. */ + winfocus = NULL; + head = cur_focus; + + for (i = 0; i <= workspace_limit; ++i) { + if (head == NULL) + head = TAILQ_FIRST(&r->s->ws[(ws->idx + i) % + workspace_limit].winlist); + while (head != NULL && + (head = TAILQ_NEXT(head, entry)) != NULL) { + 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)) { + winfocus = head; + break; + } + } + + if (winfocus != NULL) + break; + } + + /* Switch ws if new focus is on a different ws. */ + if (winfocus != NULL && winfocus->ws != ws) { + a.id = winfocus->ws->idx; + switchws(r, &a); + } + break; default: - return; + goto out; } focus_win(get_focus_magic(winfocus)); - focus_flush(); + +out: + DNPRINTF(SWM_D_FOCUS, "focus: done\n"); } void @@ -5879,6 +5902,7 @@ struct keyfunc { { "focus_main", focus, {.id = SWM_ARG_ID_FOCUSMAIN} }, { "focus_next", focus, {.id = SWM_ARG_ID_FOCUSNEXT} }, { "focus_prev", focus, {.id = SWM_ARG_ID_FOCUSPREV} }, + { "focus_urgent", focus, {.id = SWM_ARG_ID_FOCUSURGENT} }, { "height_grow", resize_step, {.id = SWM_ARG_ID_HEIGHTGROW} }, { "height_shrink", resize_step, {.id = SWM_ARG_ID_HEIGHTSHRINK} }, { "iconify", iconify, {0} }, @@ -6578,6 +6602,7 @@ setup_keys(void) setkeybinding(MODKEY, XK_Tab, KF_FOCUS_NEXT, NULL); setkeybinding(MODKEY, XK_k, KF_FOCUS_PREV, NULL); setkeybinding(MODKEY_SHIFT, XK_Tab, KF_FOCUS_PREV, NULL); + setkeybinding(MODKEY, XK_u, KF_FOCUS_URGENT,NULL); setkeybinding(MODKEY_SHIFT, XK_equal, KF_HEIGHT_GROW,NULL); setkeybinding(MODKEY_SHIFT, XK_minus, KF_HEIGHT_SHRINK,NULL); setkeybinding(MODKEY, XK_w, KF_ICONIFY, NULL); diff --git a/spectrwm_cz.conf b/spectrwm_cz.conf index 0929bb8..ec6c0e2 100644 --- a/spectrwm_cz.conf +++ b/spectrwm_cz.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+plus bind[ws_2] = MOD+ecaron bind[ws_3] = MOD+scaron diff --git a/spectrwm_es.conf b/spectrwm_es.conf index 09d60a7..88c6c4e 100644 --- a/spectrwm_es.conf +++ b/spectrwm_es.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+1 bind[ws_2] = MOD+2 bind[ws_3] = MOD+3 diff --git a/spectrwm_fr.conf b/spectrwm_fr.conf index 5705458..7879545 100644 --- a/spectrwm_fr.conf +++ b/spectrwm_fr.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+ampersand bind[ws_2] = MOD+eacute bind[ws_3] = MOD+quotedbl diff --git a/spectrwm_fr_ch.conf b/spectrwm_fr_ch.conf index 91bd898..65c17e8 100644 --- a/spectrwm_fr_ch.conf +++ b/spectrwm_fr_ch.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+1 bind[ws_2] = MOD+2 bind[ws_3] = MOD+3 diff --git a/spectrwm_se.conf b/spectrwm_se.conf index 1a14a6e..f0c7747 100644 --- a/spectrwm_se.conf +++ b/spectrwm_se.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+1 bind[ws_2] = MOD+2 bind[ws_3] = MOD+3 diff --git a/spectrwm_us.conf b/spectrwm_us.conf index 331996d..b48280d 100644 --- a/spectrwm_us.conf +++ b/spectrwm_us.conf @@ -19,6 +19,7 @@ bind[menu] = MOD+p bind[quit] = MOD+Shift+q bind[restart] = MOD+q bind[focus_main] = MOD+m +bind[focus_urgent] = MOD+u bind[ws_1] = MOD+1 bind[ws_2] = MOD+2 bind[ws_3] = MOD+3 -- 1.7.10.4