summaryrefslogtreecommitdiff
path: root/gui-libs/wayfire-plugins-extra/files/wayfire-plugins-extra-0.11.2-follow-focus-explicit.patch
blob: 22e4d994261e40df2dc0690ffc2b5f937743977d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
diff --git a/src/follow-focus.cpp b/src/follow-focus.cpp
index ced6a92..b271452 100644
--- a/src/follow-focus.cpp
+++ b/src/follow-focus.cpp
@@ -28,10 +28,12 @@
 #include <wayfire/output-layout.hpp>
 #include <wayfire/per-output-plugin.hpp>
 #include <wayfire/view-helpers.hpp>
+#include <wayfire/workspace-set.hpp>
 #include <wayfire/view.hpp>
 #include <wayfire/util.hpp>
 #include <wayfire/seat.hpp>
 #include <wayfire/signal-definitions.hpp>
+#include <wayfire/plugins/common/util.hpp>
 
 namespace follow_focus
 {
@@ -44,8 +46,10 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
     wayfire_view focus_view = nullptr;
     wf::wl_timer<false> change_output_focus, change_view_focus;
     wf::pointf_t last_output_coords, last_view_coords;
-    wf::wl_idle_call workspace_focus_idle;
+    wf::wl_idle_call workspace_focus_idle, workspace_switch_idle;
     bool workspace_focus_pending = false;
+    bool workspace_switch_started = false;
+    uint64_t workspace_switch_focus_ts = 0;
     wf::option_wrapper_t<bool> focus_on_workspace_change{"follow-focus/focus_on_workspace_change"};
 
     wf::option_wrapper_t<bool> should_change_view{"follow-focus/change_view"};
@@ -172,7 +176,8 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
                 if (!should_change_view || !focus_on_workspace_change ||
                     output != wf::get_core().seat->get_active_output() ||
                     !output->can_activate_plugin(wf::CAPABILITY_MANAGE_COMPOSITOR) ||
-                    !view || view != focus_view || view->get_output() != output)
+                    !view || view != focus_view || view->get_output() != output ||
+                    workspace_focus_overridden())
                 {
                     return false;
                 }
@@ -183,6 +188,29 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
         });
     }
 
+    // Remember the seat's focus timestamp when a workspace switch begins, so
+    // focus given explicitly as part of the switch (scale, switcher,
+    // activation requests, a window carried along) can be told apart from
+    // the core's refocus after the switch, which does not update timestamps.
+    // Requests are serviced synchronously, so the mark expires on idle.
+    void mark_workspace_switch_start()
+    {
+        if (!workspace_switch_started && !workspace_focus_pending)
+        {
+            workspace_switch_started  = true;
+            workspace_switch_focus_ts = wf::get_core().seat->get_last_focus_timestamp();
+            workspace_switch_idle.run_once([=] () { workspace_switch_started = false; });
+        }
+    }
+
+    bool workspace_focus_overridden()
+    {
+        auto active = wf::toplevel_cast(wf::get_core().seat->get_active_view());
+        return active && (active->get_output() == output) &&
+               (wf::get_focus_timestamp(active) > workspace_switch_focus_ts) &&
+               output->wset()->view_visible_on(active, output->wset()->get_current_workspace());
+    }
+
     // A workspace switch can put a window under a stationary pointer. Wait
     // until the switcher's animation/grab is finished, then use the normal
     // follow-focus delay and raise policy without requiring pointer movement.
@@ -195,8 +223,11 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
                 return;
             }
 
+            // A lock (output inhibited) or an explicit focus since the switch
+            // makes the pending pointer focus stale; drop it.
             if (!should_change_view || !focus_on_workspace_change ||
-                output != wf::get_core().seat->get_active_output())
+                output != wf::get_core().seat->get_active_output() ||
+                output->is_inhibited() || workspace_focus_overridden())
             {
                 workspace_focus_pending = false;
                 return;
@@ -221,12 +252,30 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
     {
         if (ev->old_viewport != ev->new_viewport)
         {
+            mark_workspace_switch_start();
+            workspace_switch_started = false;
             change_view_focus.disconnect();
             workspace_focus_pending = should_change_view && focus_on_workspace_change;
             schedule_workspace_focus();
         }
     };
 
+    wf::signal::connection_t<wf::workspace_change_request_signal> workspace_change_request =
+        [=] (wf::workspace_change_request_signal *ev)
+    {
+        if (ev->old_viewport != ev->new_viewport)
+        {
+            mark_workspace_switch_start();
+        }
+    };
+
+    // Emitted for views carried along with a switch, before they are focused.
+    wf::signal::connection_t<wf::view_change_workspace_signal> view_change_workspace =
+        [=] (wf::view_change_workspace_signal *ev)
+    {
+        mark_workspace_switch_start();
+    };
+
     wf::signal::connection_t<wf::output_plugin_activated_changed_signal> plugin_changed =
         [=] (wf::output_plugin_activated_changed_signal *ev)
     {
@@ -256,6 +305,8 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
     {
         wf::get_core().connect(&pointer_motion);
         wf::get_core().connect(&pointer_motion_absolute);
+        output->connect(&workspace_change_request);
+        output->connect(&view_change_workspace);
         output->connect(&workspace_changed);
         output->connect(&plugin_changed);
     }
@@ -263,6 +314,7 @@ class wayfire_follow_focus : public wf::per_output_plugin_instance_t
     void fini() override
     {
         workspace_focus_idle.disconnect();
+        workspace_switch_idle.disconnect();
         change_output_focus.disconnect();
         change_view_focus.disconnect();
     }