summaryrefslogtreecommitdiff
path: root/gui-libs/wayfire-plugins-extra/files/wayfire-plugins-extra-0.11.0-workspace-focus.patch
blob: 6e1b1723606544b3bddf12f868a7985fdfd3cc0c (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
131
132
133
134
135
--- a/src/follow-focus.cpp
+++ b/src/follow-focus.cpp
@@ -44,6 +44,9 @@
     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;
+    bool workspace_focus_pending = false;
+    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"};
     wf::option_wrapper_t<bool> should_change_output{"follow-focus/change_output"};
@@ -117,7 +120,7 @@
         });
     }
 
-    void check_view()
+    void check_view(bool workspace_change = false)
     {
         change_view_focus.disconnect();
 
@@ -149,7 +152,7 @@
             focus_view = view;
         }
 
-        if (wf::abs(coords - last_view_coords) < threshold)
+        if (!workspace_change && wf::abs(coords - last_view_coords) < threshold)
         {
             return;
         }
@@ -163,11 +166,76 @@
 
         change_view_focus.set_timeout(focus_delay, [=] ()
         {
+            if (workspace_change)
+            {
+                auto view = wf::get_core().get_cursor_focus_view();
+                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)
+                {
+                    return false;
+                }
+            }
+
             change_view();
             return false; // disconnect
         });
     }
 
+    // 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.
+    void schedule_workspace_focus()
+    {
+        workspace_focus_idle.run_once([=] ()
+        {
+            if (!workspace_focus_pending)
+            {
+                return;
+            }
+
+            if (!should_change_view || !focus_on_workspace_change ||
+                output != wf::get_core().seat->get_active_output())
+            {
+                workspace_focus_pending = false;
+                return;
+            }
+
+            if (!output->can_activate_plugin(wf::CAPABILITY_MANAGE_COMPOSITOR))
+            {
+                return;
+            }
+
+            workspace_focus_pending = false;
+            auto view = wf::get_core().get_cursor_focus_view();
+            if (view && view->get_output() == output)
+            {
+                check_view(true);
+            }
+        });
+    }
+
+    wf::signal::connection_t<wf::workspace_changed_signal> workspace_changed =
+        [=] (wf::workspace_changed_signal *ev)
+    {
+        if (ev->old_viewport != ev->new_viewport)
+        {
+            change_view_focus.disconnect();
+            workspace_focus_pending = should_change_view && focus_on_workspace_change;
+            schedule_workspace_focus();
+        }
+    };
+
+    wf::signal::connection_t<wf::output_plugin_activated_changed_signal> plugin_changed =
+        [=] (wf::output_plugin_activated_changed_signal *ev)
+    {
+        if (!ev->activated && workspace_focus_pending)
+        {
+            schedule_workspace_focus();
+        }
+    };
+
     wf::signal::connection_t<wf::post_input_event_signal<wlr_pointer_motion_event>> pointer_motion =
         [=] (wf::post_input_event_signal<wlr_pointer_motion_event> *ev)
     {
@@ -188,10 +256,13 @@
     {
         wf::get_core().connect(&pointer_motion);
         wf::get_core().connect(&pointer_motion_absolute);
+        output->connect(&workspace_changed);
+        output->connect(&plugin_changed);
     }
 
     void fini() override
     {
+        workspace_focus_idle.disconnect();
         change_output_focus.disconnect();
         change_view_focus.disconnect();
     }
--- a/metadata/follow-focus.xml
+++ b/metadata/follow-focus.xml
@@ -6,6 +6,11 @@
 		<option name="change_view" type="bool">
 			<_short>View focus follows mouse</_short>
 			<_long>When the mouse pointer is moved, the view focus changes to the view under the pointer.</_long>
+			<default>true</default>
+		</option>
+		<option name="focus_on_workspace_change" type="bool">
+			<_short>Focus the window under the pointer after switching workspaces</_short>
+			<_long>When view focus follows the mouse, refocus after the workspace animation finishes even if the pointer has not moved. Uses the normal focus delay and raise policy.</_long>
 			<default>true</default>
 		</option>
 		<option name="change_output" type="bool">