]> code.delx.au - spectrwm/blobdiff - spectrwm.c
Take input focus into consideration when determining active region.
[spectrwm] / spectrwm.c
index 12465bbe8016819d45a7187682d11dd6538ad8d2..75b833f17cc54f01676e40d0b4b75d3e9309722a 100644 (file)
@@ -1643,7 +1643,7 @@ bar_fmt(const char *fmtexp, char *fmtnew, struct swm_region *r, size_t sz)
 
        if (title_class_enabled) {
                strlcat(fmtnew, "+C", sz);
-               if (title_name_enabled == 0)
+               if (!title_name_enabled)
                        strlcat(fmtnew, "+4<", sz);
        }
 
@@ -1849,7 +1849,7 @@ bar_update(void)
        size_t                  len;
        char                    *b;
 
-       if (bar_enabled == 0)
+       if (!bar_enabled)
                return;
        if (bar_extra && bar_extra_running) {
                /* ignore short reads; it'll correct itself */
@@ -1921,7 +1921,7 @@ bar_refresh(void)
        int                     i, num_screens;
 
        /* do this here because the conf file is in memory */
-       if (bar_extra && bar_extra_running == 0 && bar_argv[0]) {
+       if (bar_extra && !bar_extra_running && bar_argv[0]) {
                /* launch external status app */
                bar_extra_running = 1;
                if (pipe(bar_pipe) == -1)
@@ -2313,9 +2313,9 @@ count_win(struct workspace *ws, int count_transient)
        int                     count = 0;
 
        TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (count_transient == 0 && win->floating)
+               if (!count_transient && win->floating)
                        continue;
-               if (count_transient == 0 && win->transient)
+               if (!count_transient && win->transient)
                        continue;
                if (win->iconic)
                        continue;
@@ -2446,9 +2446,11 @@ restart(struct swm_region *r, union arg *args)
 struct swm_region *
 root_to_region(xcb_window_t root)
 {
+       struct ws_win                   *cfw;
        struct swm_region               *r = NULL;
        int                             i, num_screens;
        xcb_query_pointer_reply_t       *qpr;
+       xcb_get_input_focus_reply_t     *gifr;
 
        DNPRINTF(SWM_D_MISC, "root_to_region: window: 0x%x\n", root);
 
@@ -2457,20 +2459,33 @@ root_to_region(xcb_window_t root)
                if (screens[i].root == root)
                        break;
 
-       qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn,
-           screens[i].root), NULL);
+       /* Try to find an actively focused window */
+       gifr = xcb_get_input_focus_reply(conn, xcb_get_input_focus(conn), NULL);
+       if (gifr) {
+               cfw = find_window(gifr->focus);
+               if (cfw && cfw->ws->r)
+                       r = cfw->ws->r;
 
-       if (qpr) {
-               DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n",
-                   qpr->root_x, qpr->root_y);
-               /* choose a region based on pointer location */
-               TAILQ_FOREACH(r, &screens[i].rl, entry)
-                       if (X(r) <= qpr->root_x && qpr->root_x < MAX_X(r) &&
-                           Y(r) <= qpr->root_y && qpr->root_y < MAX_Y(r))
-                               break;
-               free(qpr);
+               free(gifr);
+       }
+
+       if (r == NULL) {
+               /* No region with an active focus; try to use pointer. */
+               qpr = xcb_query_pointer_reply(conn, xcb_query_pointer(conn,
+                   screens[i].root), NULL);
+
+               if (qpr) {
+                       DNPRINTF(SWM_D_MISC, "root_to_region: pointer: (%d,%d)\n",
+                           qpr->root_x, qpr->root_y);
+                       TAILQ_FOREACH(r, &screens[i].rl, entry)
+                               if (X(r) <= qpr->root_x && qpr->root_x < MAX_X(r) &&
+                                   Y(r) <= qpr->root_y && qpr->root_y < MAX_Y(r))
+                                       break;
+                       free(qpr);
+               }
        }
 
+       /* Last resort. */
        if (r == NULL)
                r = TAILQ_FIRST(&screens[i].rl);
 
@@ -2779,6 +2794,7 @@ struct ws_win *
 get_focus_magic(struct ws_win *win)
 {
        struct ws_win   *parent = NULL;
+       struct ws_win   *child = NULL;
 
        DNPRINTF(SWM_D_FOCUS, "get_focus_magic: window: 0x%x\n", WINID(win));
        if (win == NULL)
@@ -2787,19 +2803,19 @@ get_focus_magic(struct ws_win *win)
        if (win->transient) {
                parent = find_window(win->transient);
 
-               /* If parent prefers focus elsewhere, then do so. */
-               if (parent && parent->focus_child) {
-                       if (validate_win(parent->focus_child) == 0)
-                               win = parent->focus_child;
+               /* If parent prefers focus elsewhere, then try to do so. */
+               if (parent && (child = parent->focus_child)) {
+                       if (validate_win(child) == 0 && child->mapped)
+                               win = child;
                        else
                                parent->focus_child = NULL;
                }
        }
 
-       /* If this window prefers focus elsewhere, then do so. */
-       if (win->focus_child) {
-               if (validate_win(win->focus_child) == 0)
-                       win = win->focus_child;
+       /* If this window prefers focus elsewhere, then try to do so. */
+       if ((child = win->focus_child)) {
+               if (validate_win(child) == 0 && child->mapped)
+                       win = child;
                else
                        win->focus_child = NULL;
        }
@@ -2872,9 +2888,10 @@ switchws(struct swm_region *r, union arg *args)
                TAILQ_FOREACH(win, &old_ws->winlist, entry)
                        unmap_window(win);
 
-       new_ws->focus_pending = get_region_focus(new_ws->r);
+       if (focus_mode != SWM_FOCUS_FOLLOW)
+               new_ws->focus_pending = get_region_focus(new_ws->r);
 
-       if (new_ws->focus_pending) {
+       if (new_ws->focus_pending && focus_mode != SWM_FOCUS_FOLLOW) {
                /* if workspaces were swapped, then don't wait to set focus */
                if (old_ws->r)
                        focus_win(new_ws->focus_pending);
@@ -2924,9 +2941,9 @@ cyclews(struct swm_region *r, union arg *args)
                };
 
                if (!cycle_all &&
-                   (cycle_empty == 0 && TAILQ_EMPTY(&s->ws[a.id].winlist)))
+                   (!cycle_empty && TAILQ_EMPTY(&s->ws[a.id].winlist)))
                        continue;
-               if (cycle_visible == 0 && s->ws[a.id].r != NULL)
+               if (!cycle_visible && s->ws[a.id].r != NULL)
                        continue;
 
                switchws(r, &a);
@@ -2954,7 +2971,7 @@ void
 cyclescr(struct swm_region *r, union arg *args)
 {
        struct swm_region       *rr = NULL;
-       int                     i, x, y, num_screens;
+       int                     i, num_screens;
 
        num_screens = xcb_setup_roots_length(xcb_get_setup(conn));
        /* do nothing if we don't have more than one screen */
@@ -2979,21 +2996,7 @@ cyclescr(struct swm_region *r, union arg *args)
        if (rr == NULL)
                return;
 
-       /* move mouse to region */
-       x = X(rr) + 1;
-       y = Y(rr) + 1 + (bar_enabled ? bar_height : 0);
-       xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0, 0,
-           x, y);
-
-       rr->ws->focus = get_region_focus(rr);
-
-       if (rr->ws->focus) {
-               /* move to focus window */
-               x = X(rr->ws->focus) + 1;
-               y = Y(rr->ws->focus) + 1;
-               xcb_warp_pointer(conn, XCB_WINDOW_NONE, rr->s[i].root, 0, 0, 0,
-                   0, x, y);
-       }
+       focus_win(get_region_focus(rr));
 
        focus_flush();
 }
@@ -3224,7 +3227,7 @@ focus(struct swm_region *r, union arg *args)
        /* make sure there is at least one uniconified window */
        all_iconics = 1;
        TAILQ_FOREACH(winfocus, wl, entry)
-               if (winfocus->iconic == 0) {
+               if (!winfocus->iconic) {
                        all_iconics = 0;
                        break;
                }
@@ -3249,7 +3252,7 @@ focus(struct swm_region *r, union arg *args)
                        while (winfocus != cur_focus) {
                                if (winfocus == NULL)
                                        winfocus = TAILQ_LAST(wl, ws_win_list);
-                               if (winfocus->iconic == 0)
+                               if (!winfocus->iconic)
                                        break;
                                winfocus = TAILQ_PREV(winfocus, ws_win_list,
                                    entry);
@@ -3268,7 +3271,7 @@ focus(struct swm_region *r, union arg *args)
                        while (winfocus != cur_focus) {
                                if (winfocus == NULL)
                                        winfocus = TAILQ_FIRST(wl);
-                               if (winfocus->iconic == 0)
+                               if (!winfocus->iconic)
                                        break;
                                winfocus = TAILQ_NEXT(winfocus, entry);
                        }
@@ -3532,8 +3535,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                return;
 
        TAILQ_FOREACH(win, &ws->winlist, entry)
-               if (win->transient == 0 && win->floating == 0
-                   && win->iconic == 0)
+               if (!win->transient && !win->floating && !win->iconic)
                        break;
 
        if (win == NULL)
@@ -3590,9 +3592,9 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
        /*  stack all the tiled windows */
        i = j = 0, s = stacks;
        TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (win->transient != 0 || win->floating != 0)
+               if (win->transient || win->floating)
                        continue;
-               if (win->iconic != 0)
+               if (win->iconic)
                        continue;
 
                if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
@@ -3648,7 +3650,7 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
                else
                        win_g.y += last_h + 2 * border_width;
 
-               if (disable_border && bar_enabled == 0 && winno == 1){
+               if (disable_border && !bar_enabled && winno == 1){
                        bordered = 0;
                        win_g.w += 2 * border_width;
                        win_g.h += 2 * border_width;
@@ -3695,9 +3697,9 @@ stack_master(struct workspace *ws, struct swm_geometry *g, int rot, int flip)
 notiles:
        /* now, stack all the floaters and transients */
        TAILQ_FOREACH(win, &ws->winlist, entry) {
-               if (win->transient == 0 && win->floating == 0)
+               if (!win->transient && !win->floating)
                        continue;
-               if (win->iconic == 1)
+               if (win->iconic)
                        continue;
                if (win->ewmh_flags & EWMH_F_FULLSCREEN) {
                        fs_win = win;
@@ -3840,7 +3842,7 @@ max_stack(struct workspace *ws, struct swm_geometry *g)
                        continue;
                }
 
-               if (win->floating && win->floatmaxed == 0 ) {
+               if (win->floating && !win->floatmaxed ) {
                        /*
                         * retain geometry for retrieval on exit from
                         * max_stack mode
@@ -3883,7 +3885,7 @@ send_to_ws(struct swm_region *r, union arg *args)
 {
        int                     wsid = args->id;
        struct ws_win           *win = NULL, *parent;
-       struct workspace        *ws, *nws;
+       struct workspace        *ws, *nws, *pws;
        char                    ws_idx_str[SWM_PROPLEN];
 
        if (wsid >= workspace_limit)
@@ -3905,20 +3907,27 @@ send_to_ws(struct swm_region *r, union arg *args)
 
        /* Update the window's workspace property: _SWM_WS */
        if (snprintf(ws_idx_str, SWM_PROPLEN, "%d", nws->idx) < SWM_PROPLEN) {
-               ws->focus_pending = get_focus_prev(win);
+               if (focus_mode != SWM_FOCUS_FOLLOW)
+                       ws->focus_pending = get_focus_prev(win);
 
                /* Move the parent if this is a transient window. */
                if (win->transient) {
                        parent = find_window(win->transient);
                        if (parent) {
+                               pws = parent->ws;
                                /* Set new focus in parent's ws if needed. */
-                               if (parent->ws->focus == parent) {
-                                       parent->ws->focus_pending =
-                                           get_focus_prev(parent);
+                               if (pws->focus == parent) {
+                                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                                               pws->focus_pending =
+                                                   get_focus_prev(parent);
+
                                        unfocus_win(parent);
-                                       parent->ws->focus =
-                                           parent->ws->focus_pending;
-                                       parent->ws->focus_pending = NULL;
+
+                                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                                               pws->focus = pws->focus_pending;
+
+                                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                                               pws->focus_pending = NULL;
                                }
 
                                /* Don't unmap parent if new ws is visible */
@@ -3961,8 +3970,11 @@ send_to_ws(struct swm_region *r, union arg *args)
 
                /* Restack and set new focus. */
                stack();
-               focus_win(ws->focus_pending);
-               ws->focus_pending = NULL;
+
+               if (focus_mode != SWM_FOCUS_FOLLOW) {
+                       focus_win(ws->focus_pending);
+                       ws->focus_pending = NULL;
+               }
 
                focus_flush();
        }
@@ -3994,7 +4006,7 @@ 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 == 0)
+       if (!r->ws->always_raise)
                stack();
 
        focus_flush();
@@ -4064,7 +4076,7 @@ uniconify(struct swm_region *r, union arg *args)
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
                if (win->ws == NULL)
                        continue; /* should never happen */
-               if (win->iconic == 0)
+               if (!win->iconic)
                        continue;
                count++;
        }
@@ -4082,7 +4094,7 @@ uniconify(struct swm_region *r, union arg *args)
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
                if (win->ws == NULL)
                        continue; /* should never happen */
-               if (win->iconic == 0)
+               if (!win->iconic)
                        continue;
 
                name = get_win_name(win->id);
@@ -4191,7 +4203,7 @@ search_win(struct swm_region *r, union arg *args)
 
        i = 1;
        TAILQ_FOREACH(win, &r->ws->winlist, entry) {
-               if (win->iconic == 1)
+               if (win->iconic)
                        continue;
 
                sw = calloc(1, sizeof(struct search_window));
@@ -4278,7 +4290,7 @@ search_resp_uniconify(char *resp, unsigned long len)
        DNPRINTF(SWM_D_MISC, "search_resp_uniconify: resp: %s\n", resp);
 
        TAILQ_FOREACH(win, &search_r->ws->winlist, entry) {
-               if (win->iconic == 0)
+               if (!win->iconic)
                        continue;
                name = get_win_name(win->id);
                if (name == NULL)
@@ -4613,7 +4625,7 @@ resize(struct ws_win *win, union arg *args)
            "transient: 0x%x\n", win->id, YESNO(win->floating),
            win->transient);
 
-       if (!(win->transient != 0 || win->floating != 0))
+       if (!win->transient && !win->floating)
                return;
 
        /* reject resizes in max mode for floaters (transient ok) */
@@ -4811,7 +4823,7 @@ move(struct ws_win *win, union arg *args)
                return;
 
        win->manual = 1;
-       if (win->floating == 0 && !win->transient) {
+       if (!win->floating && !win->transient) {
                store_float_geom(win, r);
                ewmh_update_win_state(win, ewmh[_NET_WM_STATE_ABOVE].atom,
                    _NET_WM_STATE_ADD);
@@ -4922,7 +4934,7 @@ move_step(struct swm_region *r, union arg *args)
        else
                return;
 
-       if (!(win->transient != 0 || win->floating != 0))
+       if (!win->transient && !win->floating)
                return;
 
        move(win, args);
@@ -6221,7 +6233,8 @@ setconfvalue(char *selector, char *value, int flags)
        case SWM_S_FOCUS_MODE:
                if (!strcmp(value, "default"))
                        focus_mode = SWM_FOCUS_DEFAULT;
-               else if (!strcmp(value, "follow_cursor"))
+               else if (!strcmp(value, "follow") ||
+                   !strcmp(value, "follow_cursor"))
                        focus_mode = SWM_FOCUS_FOLLOW;
                else if (!strcmp(value, "manual"))
                        focus_mode = SWM_FOCUS_MANUAL;
@@ -6877,7 +6890,7 @@ manage_window(xcb_window_t id, uint16_t mapped)
                free(p);
                p = NULL;
        } else if ((ws_idx = get_ws_idx(win->id)) != -1 &&
-           win->transient == 0) {
+           !win->transient) {
                /* _SWM_WS is set; use that. */
                win->ws = &r->s->ws[ws_idx];
        } else if (trans && (ww = find_window(trans)) != NULL) {
@@ -7303,8 +7316,11 @@ configurenotify(xcb_configure_notify_event_t *e)
 {
        struct ws_win           *win;
 
-       DNPRINTF(SWM_D_EVENT, "configurenotify: window: 0x%x\n",
-           e->window);
+       DNPRINTF(SWM_D_EVENT, "configurenotify: win 0x%x, event win: 0x%x, "
+           "(x,y) WxH: (%d,%d) %ux%u, border: %u, above_sibling: 0x%x, "
+           "override_redirect: %s\n", e->window, e->event, e->x, e->y,
+           e->width, e->height, e->border_width, e->above_sibling,
+           YESNO(e->override_redirect));
 
        win = find_window(e->window);
        if (win) {
@@ -7333,16 +7349,20 @@ destroynotify(xcb_destroy_notify_event_t *e)
                return;
        }
 
-       /* If we were focused, make sure we focus on something else. */
-       if (win == win->ws->focus)
-               win->ws->focus_pending = get_focus_prev(win);
+       if (focus_mode != SWM_FOCUS_FOLLOW) {
+               /* If we were focused, make sure we focus on something else. */
+               if (win == win->ws->focus)
+                       win->ws->focus_pending = get_focus_prev(win);
+       }
 
        unmanage_window(win);
        stack();
 
-       if (win->ws->focus_pending) {
-               focus_win(win->ws->focus_pending);
-               win->ws->focus_pending = NULL;
+       if (focus_mode != SWM_FOCUS_FOLLOW) {
+               if (win->ws->focus_pending) {
+                       focus_win(win->ws->focus_pending);
+                       win->ws->focus_pending = NULL;
+               }
        }
 
        free_window(win);
@@ -7477,9 +7497,11 @@ mapnotify(xcb_map_notify_event_t *e)
        win->mapped = 1;
        set_win_state(win, XCB_ICCCM_WM_STATE_NORMAL);
 
-       if (win->ws->focus_pending == win) {
-               focus_win(win);
-               win->ws->focus_pending = NULL;
+       if (focus_mode != SWM_FOCUS_FOLLOW) {
+               if (win->ws->focus_pending == win) {
+                       focus_win(win);
+                       win->ws->focus_pending = NULL;
+               }
        }
 
        xcb_flush(conn);
@@ -7525,7 +7547,8 @@ maprequest(xcb_map_request_event_t *e)
                stack();
 
        /* The new window should get focus. */
-       win->ws->focus_pending = get_focus_magic(win);
+       if (focus_mode != SWM_FOCUS_FOLLOW)
+               win->ws->focus_pending = get_focus_magic(win);
 
        /* Ignore EnterNotify to handle the mapnotify without interference. */
        if (focus_mode == SWM_FOCUS_DEFAULT)
@@ -7589,19 +7612,25 @@ propertynotify(xcb_property_notify_event_t *e)
 
        if (e->atom == a_swm_iconic) {
                if (e->state == XCB_PROPERTY_NEW_VALUE) {
-                       win->ws->focus_pending = get_focus_prev(win);
+                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                               win->ws->focus_pending = get_focus_prev(win);
+
                        unfocus_win(win);
                        unmap_window(win);
 
                        if (win->ws->r) {
                                stack();
-                               focus_win(win->ws->focus_pending);
-                               win->ws->focus_pending = NULL;
+                               if (focus_mode != SWM_FOCUS_FOLLOW) {
+                                       focus_win(win->ws->focus_pending);
+                                       win->ws->focus_pending = NULL;
+                               }
                                focus_flush();
                        }
                } else if (e->state == XCB_PROPERTY_DELETE) {
                        /* The window is no longer iconic, restack ws. */
-                       win->ws->focus_pending = get_focus_magic(win);
+                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                               win->ws->focus_pending = get_focus_magic(win);
+
                        stack();
 
                        /* Flush EnterNotify for mapnotify, if needed. */
@@ -7610,9 +7639,12 @@ propertynotify(xcb_property_notify_event_t *e)
        } else if (e->atom == a_state) {
                /* State just changed, make sure it gets focused if mapped. */
                if (e->state == XCB_PROPERTY_NEW_VALUE) {
-                       if (win->mapped && win->ws->focus_pending == win) {
-                               win->ws->focus_pending = NULL;
-                               focus_win(win);
+                       if (focus_mode != SWM_FOCUS_FOLLOW) {
+                               if (win->mapped &&
+                                   win->ws->focus_pending == win) {
+                                       focus_win(win->ws->focus_pending);
+                                       win->ws->focus_pending = NULL;
+                               }
                        }
                }
        } else if (e->atom == XCB_ATOM_WM_CLASS ||
@@ -7627,6 +7659,7 @@ void
 unmapnotify(xcb_unmap_notify_event_t *e)
 {
        struct ws_win           *win;
+       struct workspace        *ws;
 
        DNPRINTF(SWM_D_EVENT, "unmapnotify: window: 0x%x\n", e->window);
 
@@ -7635,20 +7668,29 @@ unmapnotify(xcb_unmap_notify_event_t *e)
        if (win == NULL)
                return;
 
-       if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) {
-               /* If we were focused, make sure we focus on something else. */
-               if (win == win->ws->focus)
-                       win->ws->focus_pending = get_focus_prev(win);
+       ws = win->ws;
 
+       if (getstate(e->window) == XCB_ICCCM_WM_STATE_NORMAL) {
                win->mapped = 0;
                set_win_state(win, XCB_ICCCM_WM_STATE_ICONIC);
 
+               /* If we were focused, make sure we focus on something else. */
+               if (win == ws->focus)
+                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                               ws->focus_pending = get_focus_prev(win);
+
+               unfocus_win(win);
                unmanage_window(win);
                stack();
 
-               if (win->ws->focus_pending) {
-                       focus_win(win->ws->focus_pending);
-                       win->ws->focus_pending = NULL;
+               DNPRINTF(SWM_D_EVENT, "unmapnotify: focus_pending: 0x%x\n",
+                   ws->focus_pending->id);
+
+               if (focus_mode != SWM_FOCUS_FOLLOW) {
+                       if (ws->focus_pending) {
+                               focus_win(ws->focus_pending);
+                               ws->focus_pending = NULL;
+                       }
                }
 
                focus_flush();
@@ -8448,7 +8490,7 @@ noconfig:
 
        while (running) {
                while ((evt = xcb_poll_for_event(conn))) {
-                       if (running == 0)
+                       if (!running)
                                goto done;
                        event_handle(evt);
                        free(evt);
@@ -8482,11 +8524,11 @@ noconfig:
                        if (errno != EINTR) {
                                DNPRINTF(SWM_D_MISC, "select failed");
                        }
-               if (restart_wm == 1)
+               if (restart_wm)
                        restart(NULL, NULL);
-               if (search_resp == 1)
+               if (search_resp)
                        search_do_resp();
-               if (running == 0)
+               if (!running)
                        goto done;
                if (bar_alarm) {
                        bar_alarm = 0;