#define SH_INC_H(w) (w)->sh.height_inc
#define SWM_MAX_FONT_STEPS (3)
#define WINID(w) ((w) ? (w)->id : XCB_WINDOW_NONE)
+#define WS_FOCUSED(ws) ((ws)->r && (ws)->r->s->r_focus == (ws)->r)
#define YESNO(x) ((x) ? "yes" : "no")
/* Constrain Window flags */
#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)
KF_FOCUS_MAIN,
KF_FOCUS_NEXT,
KF_FOCUS_PREV,
+ KF_FOCUS_URGENT,
KF_HEIGHT_GROW,
KF_HEIGHT_SHRINK,
KF_ICONIFY,
void
switchws(struct swm_region *r, union arg *args)
{
- int wsid = args->id, unmap_old = 0;
struct swm_region *this_r, *other_r;
struct ws_win *win;
struct workspace *new_ws, *old_ws;
+ xcb_window_t none = XCB_WINDOW_NONE;
+ int wsid = args->id, unmap_old = 0;
if (!(r && r->s))
return;
if (new_ws == old_ws)
return;
- unfocus_win(old_ws->focus);
+ if ((win = old_ws->focus) != NULL) {
+ xcb_change_window_attributes(conn, win->id, XCB_CW_BORDER_PIXEL,
+ &win->ws->r->s->c[SWM_S_COLOR_UNFOCUS].pixel);
+
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, win->s->root,
+ ewmh[_NET_ACTIVE_WINDOW].atom, XCB_ATOM_WINDOW, 32, 1,
+ &none);
+ }
other_r = new_ws->r;
if (other_r == NULL) {
/* Set focus_pending before stacking, if needed. */
if (focus_mode != SWM_FOCUS_FOLLOW && (!new_ws->focus_pending ||
- validate_win(new_ws->focus_pending)))
+ validate_win(new_ws->focus_pending))) {
new_ws->focus_pending = get_region_focus(new_ws->r);
+ new_ws->focus = new_ws->focus_prev;
+ new_ws->focus_prev = NULL;
+ }
stack();
DNPRINTF(SWM_D_FOCUS, "focusrg: id: %d\n", ridx);
rr = TAILQ_FIRST(&r->s->rl);
- for (i = 0; i < ridx; ++i)
+ for (i = 0; i < ridx && rr != NULL; ++i)
rr = TAILQ_NEXT(rr, entry);
if (rr == NULL)
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
DNPRINTF(SWM_D_FOCUS, "send_to_rg: id: %d\n", ridx);
rr = TAILQ_FIRST(&r->s->rl);
- for (i = 0; i < ridx; ++i)
+ for (i = 0; i < ridx && rr != NULL; ++i)
rr = TAILQ_NEXT(rr, entry);
if (rr == NULL)
{ "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} },
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);
unmanage_window(win);
stack();
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) {
if (win->ws->focus_pending) {
focus_win(win->ws->focus_pending);
win->ws->focus_pending = NULL;
- } else if (win == win->ws->focus && win->ws->r) {
+ } else if (win == win->ws->focus) {
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
win->ws->r->id, XCB_CURRENT_TIME);
}
win->mapped = 1;
set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(win->ws)) {
if (win->ws->focus_pending == win) {
focus_win(win);
win->ws->focus_pending = NULL;
if (ws->r) {
stack();
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW &&
+ WS_FOCUSED(ws)) {
if (ws->focus_pending) {
focus_win(ws->focus_pending);
ws->focus_pending = NULL;
} else if (e->atom == a_state) {
/* State just changed, make sure it gets focused if mapped. */
if (e->state == XCB_PROPERTY_NEW_VALUE) {
- if (focus_mode != SWM_FOCUS_FOLLOW) {
+ if (focus_mode != SWM_FOCUS_FOLLOW && WS_FOCUSED(ws)) {
if (win->mapped &&
ws->focus_pending == win) {
focus_win(ws->focus_pending);
if (ws->r)
stack();
- if (focus_mode == SWM_FOCUS_FOLLOW) {
- if (ws->r)
+ if (WS_FOCUSED(ws)) {
+ if (focus_mode == SWM_FOCUS_FOLLOW) {
focus_win(get_pointer_win(ws->r->s->root));
- } else if (ws->focus_pending) {
- focus_win(ws->focus_pending);
- ws->focus_pending = NULL;
- } else if (ws->focus == NULL && ws->r) {
- xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
- ws->r->id, XCB_CURRENT_TIME);
+ } else if (ws->focus_pending) {
+ focus_win(ws->focus_pending);
+ ws->focus_pending = NULL;
+ } else if (ws->focus == NULL) {
+ xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+ ws->r->id, XCB_CURRENT_TIME);
+ }
}
}
if (e->type == ewmh[_NET_ACTIVE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_ACTIVE_WINDOW\n");
- focus_win(win);
+ if (WS_FOCUSED(win->ws))
+ focus_win(win);
+ else
+ win->ws->focus_pending = win;
}
if (e->type == ewmh[_NET_CLOSE_WINDOW].atom) {
DNPRINTF(SWM_D_EVENT, "clientmessage: _NET_CLOSE_WINDOW\n");