JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
Fix focus when switching to an inactive workspace with a new window.
[spectrwm.git] / spectrwm.c
index 3b11992..1e20562 100644 (file)
@@ -5,10 +5,10 @@
  * Copyright (c) 2009 Pierre-Yves Ritschard <pyr@spootnik.org>
  * Copyright (c) 2010 Tuukka Kataja <stuge@xor.fi>
  * Copyright (c) 2011 Jason L. Wright <jason@thought.net>
- * Copyright (c) 2011-2012 Reginald Kennedy <rk@rejii.com>
+ * Copyright (c) 2011-2013 Reginald Kennedy <rk@rejii.com>
  * Copyright (c) 2011-2012 Lawrence Teo <lteo@lteo.net>
  * Copyright (c) 2011-2012 Tiago Cunha <tcunha@gmx.com>
- * Copyright (c) 2012 David Hill <dhill@mindcry.org>
+ * Copyright (c) 2012-2013 David Hill <dhill@mindcry.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -995,10 +995,10 @@ struct swm_region *root_to_region(xcb_window_t, int);
 void    screenchange(xcb_randr_screen_change_notify_event_t *);
 void    scan_xrandr(int);
 void    search_do_resp(void);
-void    search_resp_name_workspace(const char *, unsigned long);
+void    search_resp_name_workspace(const char *, size_t);
 void    search_resp_search_window(const char *);
 void    search_resp_search_workspace(const char *);
-void    search_resp_uniconify(const char *, unsigned long);
+void    search_resp_uniconify(const char *, size_t);
 void    search_win(struct swm_region *, union arg *);
 void    search_win_cleanup(void);
 void    search_workspace(struct swm_region *, union arg *);
@@ -2979,6 +2979,8 @@ root_to_region(xcb_window_t root, int check)
        if (r == NULL && check & SWM_CK_FALLBACK)
                r = TAILQ_FIRST(&screens[i].rl);
 
+       DNPRINTF(SWM_D_MISC, "root_to_region: idx: %d\n", get_region_index(r));
+
        return (r);
 }
 
@@ -3412,7 +3414,7 @@ focus_region(struct swm_region *r)
                if (old_r)
                        unfocus_win(old_r->ws->focus);
 
-               xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->s->root,
+               xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
                    XCB_CURRENT_TIME);
 
                /* Clear bar since empty. */
@@ -3463,8 +3465,9 @@ switchws(struct swm_region *r, union arg *args)
        this_r->ws = new_ws;
        new_ws->r = this_r;
 
-       /* Set focus_pending before stacking. */
-       if (focus_mode != SWM_FOCUS_FOLLOW)
+       /* Set focus_pending before stacking, if needed. */
+       if (focus_mode != SWM_FOCUS_FOLLOW && (!new_ws->focus_pending ||
+           validate_win(new_ws->focus_pending)))
                new_ws->focus_pending = get_region_focus(new_ws->r);
 
        stack();
@@ -3478,17 +3481,16 @@ switchws(struct swm_region *r, union arg *args)
        if (old_ws->r && focus_mode != SWM_FOCUS_FOLLOW) {
                if (new_ws->focus_pending) {
                        focus_win(new_ws->focus_pending);
-               } else {
-                       /* Empty region, focus on root. */
-                       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
-                           new_ws->r->s[new_ws->r->s->idx].root,
-                           XCB_CURRENT_TIME);
+                       new_ws->focus_pending = NULL;
                }
        }
 
-       /* Clear bar if new ws is empty. */
-       if (new_ws->focus_pending == NULL)
+       /* Clear bar and set focus on region input win if new ws is empty. */
+       if (new_ws->focus_pending == NULL && new_ws->focus == NULL) {
+               xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT, r->id,
+                   XCB_CURRENT_TIME);
                bar_draw();
+       }
 
        focus_flush();
 
@@ -4634,11 +4636,10 @@ send_to_ws(struct swm_region *r, union arg *args)
 
                                        unfocus_win(parent);
 
-                                       if (focus_mode != SWM_FOCUS_FOLLOW)
+                                       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 */
@@ -4683,8 +4684,14 @@ send_to_ws(struct swm_region *r, union arg *args)
                stack();
 
                if (focus_mode != SWM_FOCUS_FOLLOW) {
-                       focus_win(ws->focus_pending);
-                       ws->focus_pending = NULL;
+                       if (ws->focus_pending) {
+                               focus_win(ws->focus_pending);
+                               ws->focus_pending = NULL;
+                       } else {
+                               xcb_set_input_focus(conn,
+                                   XCB_INPUT_FOCUS_PARENT, r->id,
+                                   XCB_CURRENT_TIME);
+                       }
                }
 
                focus_flush();
@@ -4996,7 +5003,7 @@ search_win(struct swm_region *r, union arg *args)
 }
 
 void
-search_resp_uniconify(const char *resp, unsigned long len)
+search_resp_uniconify(const char *resp, size_t len)
 {
        char                    *name;
        struct ws_win           *win;
@@ -5026,7 +5033,7 @@ search_resp_uniconify(const char *resp, unsigned long len)
 }
 
 void
-search_resp_name_workspace(const char *resp, unsigned long len)
+search_resp_name_workspace(const char *resp, size_t len)
 {
        struct workspace        *ws;
 
@@ -5122,7 +5129,7 @@ search_do_resp(void)
 {
        ssize_t                 rbytes;
        char                    *resp;
-       unsigned long           len;
+       size_t                  len;
 
        DNPRINTF(SWM_D_MISC, "search_do_resp:\n");
 
@@ -8199,6 +8206,9 @@ destroynotify(xcb_destroy_notify_event_t *e)
                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) {
+                       xcb_set_input_focus(conn, XCB_INPUT_FOCUS_PARENT,
+                           win->ws->r->id, XCB_CURRENT_TIME);
                }
        }
 
@@ -8440,6 +8450,9 @@ motionnotify(xcb_motion_notify_event_t *e)
 
        last_event_time = e->time;
 
+       if (focus_mode == SWM_FOCUS_MANUAL)
+               return;
+
        num_screens = get_screen_count();
        for (i = 0; i < num_screens; i++)
                if (screens[i].root == e->root)
@@ -8491,6 +8504,7 @@ void
 propertynotify(xcb_property_notify_event_t *e)
 {
        struct ws_win           *win;
+       struct workspace        *ws;
 #ifdef SWM_DEBUG
        char                    *name;
 
@@ -8504,28 +8518,39 @@ propertynotify(xcb_property_notify_event_t *e)
        if (win == NULL)
                return;
 
+       ws = win->ws;
+
        last_event_time = e->time;
 
        if (e->atom == a_swm_iconic) {
                if (e->state == XCB_PROPERTY_NEW_VALUE) {
                        if (focus_mode != SWM_FOCUS_FOLLOW)
-                               win->ws->focus_pending = get_focus_prev(win);
+                               ws->focus_pending = get_focus_prev(win);
 
                        unfocus_win(win);
                        unmap_window(win);
 
-                       if (win->ws->r) {
+                       if (ws->r) {
                                stack();
+
                                if (focus_mode != SWM_FOCUS_FOLLOW) {
-                                       focus_win(win->ws->focus_pending);
-                                       win->ws->focus_pending = NULL;
+                                       if (ws->focus_pending) {
+                                               focus_win(ws->focus_pending);
+                                               ws->focus_pending = NULL;
+                                       } else {
+                                               xcb_set_input_focus(conn,
+                                                   XCB_INPUT_FOCUS_PARENT,
+                                                   ws->r->id,
+                                                   XCB_CURRENT_TIME);
+                                       }
                                }
+
                                focus_flush();
                        }
                } else if (e->state == XCB_PROPERTY_DELETE) {
                        /* The window is no longer iconic, restack ws. */
                        if (focus_mode != SWM_FOCUS_FOLLOW)
-                               win->ws->focus_pending = get_focus_magic(win);
+                               ws->focus_pending = get_focus_magic(win);
 
                        stack();
 
@@ -8537,9 +8562,9 @@ propertynotify(xcb_property_notify_event_t *e)
                if (e->state == XCB_PROPERTY_NEW_VALUE) {
                        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;
+                                   ws->focus_pending == win) {
+                                       focus_win(ws->focus_pending);
+                                       ws->focus_pending = NULL;
                                }
                        }
                }
@@ -8594,11 +8619,12 @@ unmapnotify(xcb_unmap_notify_event_t *e)
                if (focus_mode == SWM_FOCUS_FOLLOW) {
                        if (ws->r)
                                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_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);
                }
        }