i3 - improved tiling WM


Dont set input focus and send WM_TAKE_FOCUS

Patch status: needinfo

Patch by Tony Crisci

Long description:

If input focus is set by the window manager, it is not necessary to send
WM_TAKE_FOCUS because it has already taken focus.

http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7

> The goal is to support window managers that want to assign the input
> focus to a top-level window in such a way that the top-level window
> either can assign it to one of its subwindows or can decline the offer
> of the focus. For example, a clock or a text editor with no currently
> open frames might not want to take focus even though the window
> manager generally believes that clients should take the input focus
> after being deiconified or raised.

Both setting input focus and sending WM_TAKE_FOCUS is effectively
setting focus on the window twice which is certainly against the spirit
of the spec, if not the letter.

fixes #1167

To apply this patch, use:
curl http://cr.i3wm.org/patch/497/raw.patch | git am

b/src/x.c

32
@@ -987,20 +987,16 @@ void x_push_changes(Con *con) {
33
             /* Invalidate focused_id to correctly focus new windows with the same ID */
34
             focused_id = XCB_NONE;
35
         } else {
36
-            bool set_focus = true;
37
             if (focused->window != NULL &&
38
-                focused->window->needs_take_focus) {
39
+                focused->window->needs_take_focus &&
40
+                focused->window->doesnt_accept_focus) {
41
                 DLOG("Updating focus by sending WM_TAKE_FOCUS to window 0x%08x (focused: %p / %s)\n",
42
                      to_focus, focused, focused->name);
43
                 send_take_focus(to_focus);
44
-                set_focus = !focused->window->doesnt_accept_focus;
45
-                DLOG("set_focus = %d\n", set_focus);
46
 
47
-                if (!set_focus && to_focus != last_focused && is_con_attached(focused))
48
+                if (to_focus != last_focused && is_con_attached(focused))
49
                    ipc_send_window_event("focus", focused);
50
-            }
51
-
52
-            if (set_focus) {
53
+            } else {
54
                 DLOG("Updating focus (focused: %p / %s) to X11 window 0x%08x\n", focused, focused->name, to_focus);
55
                 /* We remove XCB_EVENT_MASK_FOCUS_CHANGE from the event mask to get
56
                  * no focus change events for our own focus changes. We only want

b/testcases/t/158-wm_take_focus.t

61
@@ -30,7 +30,7 @@ subtest 'Window without WM_TAKE_FOCUS', sub {
62
     done_testing;
63
 };
64
 
65
-subtest 'Window with WM_TAKE_FOCUS', sub {
66
+subtest 'Window with WM_TAKE_FOCUS and without InputHint', sub {
67
     fresh_workspace;
68
 
69
     my $take_focus = $x->atom(name => 'WM_TAKE_FOCUS');
70
@@ -40,6 +40,9 @@ subtest 'Window with WM_TAKE_FOCUS', sub {
71
         protocols => [ $take_focus ],
72
     });
73
 
74
+    # add a WM_HINTS property without the InputHint
75
+    $window->delete_hint('input');
76
+
77
     $window->map;
78
 
79
     ok(wait_for_event(1, sub {