summaryrefslogtreecommitdiff
path: root/gui-wm/wayfire/files/wayfire-0.11.0-r71-switch-tile-exclusivity.patch
blob: 53489523c71b75e3c8820d9906e99fd27c843dae (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
diff --git a/plugins/cube/cube.cpp b/plugins/cube/cube.cpp
index 3b4b857..813a459 100644
--- a/plugins/cube/cube.cpp
+++ b/plugins/cube/cube.cpp
@@ -907,13 +907,13 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer
         output->render->schedule_redraw();
     }
 
-    void animate_workspace_delta(wf::point_t delta,
+    bool animate_workspace_delta(wf::point_t delta,
         wf::point_t anchor_workspace,
         wayfire_toplevel_view fixed_view)
     {
         if (!activate())
         {
-            return;
+            return false;
         }
 
         end_mouse_overview();
@@ -957,14 +957,15 @@ class wayfire_cube : public wf::per_output_plugin_instance_t, public wf::pointer
         start_animation();
         update_view_matrix();
         output->render->schedule_redraw();
+        return true;
     }
 
     wf::signal::connection_t<cube_workspace_animation_signal>
         on_cube_workspace_animation = [=] (cube_workspace_animation_signal *ev)
     {
-        animate_workspace_delta(ev->delta, ev->anchor_workspace,
-            ev->fixed_view);
-        ev->carried_out = true;
+        // Report failure so vswitch can fall back to its own animation.
+        ev->carried_out = animate_workspace_delta(ev->delta,
+            ev->anchor_workspace, ev->fixed_view);
     };
 
     wf::signal::connection_t<cube_render_pause_signal>
diff --git a/plugins/cube/meson.build b/plugins/cube/meson.build
index 48ea276..af57b9a 100644
--- a/plugins/cube/meson.build
+++ b/plugins/cube/meson.build
@@ -2,5 +2,7 @@ animiate = shared_module('cube',
                          ['cube.cpp', 'cubemap.cpp', 'skydome.cpp', 'simple-background.cpp', 'warp-background.cpp', 'hyperspace-background.cpp'],
                          include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, ipc_include_dirs],
                          dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep],
+                         link_args: ['-Wl,--version-script=' + meson.project_source_root() / 'plugins/common/plugin-exports.map'],
+                         link_depends: '../../plugins/common/plugin-exports.map',
                          install: true,
                          install_dir: join_paths(get_option('libdir'), 'wayfire'))
diff --git a/plugins/grid/grid.cpp b/plugins/grid/grid.cpp
index ed24b42..46bf79e 100644
--- a/plugins/grid/grid.cpp
+++ b/plugins/grid/grid.cpp
@@ -294,6 +294,8 @@ class wayfire_grid : public wf::plugin_interface_t, public wf::per_output_tracke
   public:
     void init() override
     {
+        wf::get_core().store_data(std::make_unique<wf::custom_data_t>(),
+            wf::grid::grid_loaded_marker);
         init_output_tracking();
         // Older metadata leaves new ini options untyped, or absent. Promote
         // them before loading activators, preserving any configured binding.
@@ -465,6 +467,7 @@ class wayfire_grid : public wf::plugin_interface_t, public wf::per_output_tracke
     void fini() override
     {
         fini_output_tracking();
+        wf::get_core().erase_data(wf::grid::grid_loaded_marker);
     }
 
     bool can_adjust_view(wayfire_toplevel_view view)
diff --git a/plugins/grid/meson.build b/plugins/grid/meson.build
index e107495..71c5746 100644
--- a/plugins/grid/meson.build
+++ b/plugins/grid/meson.build
@@ -5,6 +5,8 @@ all_deps = [wlroots, pixman, wfconfig, wftouch, cairo, json, plugin_pch_dep]
 shared_module('grid', ['grid.cpp'],
         include_directories: all_include_dirs,
         dependencies: all_deps,
+        link_args: ['-Wl,--version-script=' + meson.project_source_root() / 'plugins/common/plugin-exports.map'],
+        link_depends: '../../plugins/common/plugin-exports.map',
         install: true,
         install_dir: conf_data.get('PLUGIN_PATH'))
 
diff --git a/plugins/grid/wayfire/plugins/grid.hpp b/plugins/grid/wayfire/plugins/grid.hpp
index d981735..1da956e 100644
--- a/plugins/grid/wayfire/plugins/grid.hpp
+++ b/plugins/grid/wayfire/plugins/grid.hpp
@@ -23,6 +23,13 @@ enum move_op_t
     MOVE_OP_FINISH_PREVIEW = 3,
 };
 
+/**
+ * Core custom data name present while the Grid plugin is loaded, so that
+ * move-snap leaves view_tile_request_signal to Grid regardless of load order.
+ * Checked by name only: custom data types do not compare across plugin builds.
+ */
+static constexpr const char *grid_loaded_marker = "wf-grid-plugin-loaded";
+
 /**
  * name: request
  * on: core
diff --git a/plugins/single_plugins/meson.build b/plugins/single_plugins/meson.build
index f2acc10..716b824 100644
--- a/plugins/single_plugins/meson.build
+++ b/plugins/single_plugins/meson.build
@@ -18,11 +18,19 @@ extra_libs = {
     'vswipe': [workspace_wall],
 }
 
+# Export only the plugin entry points, so that live-swapped revisions do not
+# bind to each other's inline/template symbols.
+export_map = 'plugins/common/plugin-exports.map'
+export_map_plugins = ['move']
+
 foreach plugin : plugins
   plugin_module = shared_module(plugin, plugin + '.cpp',
       include_directories: all_include_dirs,
       dependencies: all_deps,
       link_with: extra_libs.get(plugin, []),
+      link_args: plugin in export_map_plugins ?
+          ['-Wl,--version-script=' + meson.project_source_root() / export_map] : [],
+      link_depends: plugin in export_map_plugins ? '../../' + export_map : [],
       install: true,
       install_dir: conf_data.get('PLUGIN_PATH'))
 
diff --git a/plugins/single_plugins/move-snap.hpp b/plugins/single_plugins/move-snap.hpp
index ddcb70f..2c2fce5 100644
--- a/plugins/single_plugins/move-snap.hpp
+++ b/plugins/single_plugins/move-snap.hpp
@@ -9,6 +9,7 @@
 #include <wayfire/workspace-set.hpp>
 #include <wayfire/toplevel.hpp>
 #include <wayfire/plugins/common/move-drag-interface.hpp>
+#include <wayfire/plugins/grid.hpp>
 #include <wayfire/plugins/wobbly/wobbly-signal.hpp>
 #include <chrono>
 #include "move-snap-map.hpp"
@@ -300,7 +301,8 @@ class move_snap_t : public wf::per_output_tracker_mixin_t<>
     // Without Grid, ordinary tiling reflows still preserve half/quarter sizes.
     wf::signal::connection_t<wf::view_tile_request_signal> on_tile = [this] (auto *ev)
     {
-        if (ev->carried_out || !eligible(ev->view) || !ev->edges) return;
+        if (ev->carried_out || wf::get_core().has_data(wf::grid::grid_loaded_marker)) return;
+        if (!eligible(ev->view) || !ev->edges) return;
         int slot = wf::grid::get_slot_from_tiled_edges(ev->edges);
         if (!slot) return;
         auto area = wf::window_scope_workarea(ev->view);
diff --git a/plugins/tile/tile-plugin.cpp b/plugins/tile/tile-plugin.cpp
index 5d66c4d..ab03b2f 100644
--- a/plugins/tile/tile-plugin.cpp
+++ b/plugins/tile/tile-plugin.cpp
@@ -183,10 +183,26 @@ class tile_output_plugin_t : public wf::pointer_interaction_t, public wf::custom
         ev->carried_out = true;
         stop_controller(true);
         auto& data = tile_workspace_set_data_t::get(ev->view->get_wset());
-        data.reconcile_view(ev->view, ev->workspace);
+        reconcile_requested_view(data, ev->view, ev->workspace);
         data.update_root_size();
     };
 
+    /**
+     * Most tile/fullscreen requests carry the output's current workspace, not
+     * the view's. Only an explicit window-scope reflow may move the node to
+     * another workspace; otherwise just reconcile its region on its own one.
+     */
+    void reconcile_requested_view(tile_workspace_set_data_t& data,
+        wayfire_toplevel_view view, wf::point_t requested)
+    {
+        auto vp = view->has_data<wf::window_scope_reflow_t>() ?
+            std::optional<wf::point_t>{requested} : data.workspace_of(view);
+        if (vp)
+        {
+            data.reconcile_view(view, *vp);
+        }
+    }
+
     wf::signal::connection_t<view_fullscreen_request_signal> on_fullscreen_request =
         [=] (view_fullscreen_request_signal *ev)
     {
@@ -196,8 +212,9 @@ class tile_output_plugin_t : public wf::pointer_interaction_t, public wf::custom
         }
 
         ev->carried_out = true;
-        tile_workspace_set_data_t::get(ev->view->get_wset()).reconcile_view(ev->view, ev->workspace);
-        tile_workspace_set_data_t::get(ev->view->get_wset()).set_view_fullscreen(ev->view, ev->state);
+        auto& data = tile_workspace_set_data_t::get(ev->view->get_wset());
+        reconcile_requested_view(data, ev->view, ev->workspace);
+        data.set_view_fullscreen(ev->view, ev->state);
     };
 
     void change_view_workspace(wayfire_toplevel_view view, std::optional<wf::point_t> vp = {})
diff --git a/plugins/tile/tile-wset.hpp b/plugins/tile/tile-wset.hpp
index a695bc3..6a6f17a 100644
--- a/plugins/tile/tile-wset.hpp
+++ b/plugins/tile/tile-wset.hpp
@@ -117,8 +117,27 @@ class tile_workspace_set_data_t : public wf::custom_data_t
         return output->workarea->get_workarea();
     }
 
+    wf::point_t clamp_workspace(wf::point_t vp)
+    {
+        auto size = wset.lock()->get_workspace_grid_size();
+        return {std::clamp(vp.x, 0, size.width - 1), std::clamp(vp.y, 0, size.height - 1)};
+    }
+
+    /** The workspace whose (virtual or physical) root holds the view's node. */
+    std::optional<wf::point_t> workspace_of(wayfire_toplevel_view view)
+    {
+        auto node = tile::view_node_t::get_node(view);
+        if (!node) return {};
+        auto root = tile::get_root(node);
+        std::optional<wf::point_t> result;
+        for_each_root([&] (auto& candidate, auto vp, const auto&)
+        { if (candidate.get() == root.get()) result = vp; });
+        return result;
+    }
+
     std::unique_ptr<tile::tree_node_t>& root_at(wf::point_t vp, const std::string& monitor = "")
     {
+        vp = clamp_workspace(vp);
         if (monitor.empty()) return roots[vp.x][vp.y];
         auto& grid = physical_roots[monitor];
         auto size = wset.lock()->get_workspace_grid_size();
@@ -166,6 +185,7 @@ class tile_workspace_set_data_t : public wf::custom_data_t
     {
         auto node = tile::view_node_t::get_node(view);
         if (!node) return;
+        vp = clamp_workspace(vp);
         auto& destination = root_at(vp, region_for(view));
         if (tile::get_root(node).get() == destination.get()) return;
         autocommit_transaction_t tx;
diff --git a/plugins/vswitch/vswitch.cpp b/plugins/vswitch/vswitch.cpp
index 34b63be..3ad44e8 100644
--- a/plugins/vswitch/vswitch.cpp
+++ b/plugins/vswitch/vswitch.cpp
@@ -387,6 +387,15 @@ class vswitch : public wf::per_output_plugin_instance_t
             on_done();
         }
 
+        /** The workspace has already changed: slide in from @old_ws. */
+        void slide_from(wf::point_t old_ws)
+        {
+            auto cws = output->wset()->get_current_workspace();
+            animation.dx.set(old_ws.x - cws.x, 0);
+            animation.dy.set(old_ws.y - cws.y, 0);
+            animation.start();
+        }
+
       private:
         std::function<void()> on_done;
     };
@@ -665,27 +674,36 @@ class vswitch : public wf::per_output_plugin_instance_t
 
         if (!is_active())
         {
+            // Respect plugin exclusivity (expo, scale, ...) like upstream's
+            // start_switch() did.
+            if (!output->can_activate_plugin(&grab_interface))
+            {
+                return false;
+            }
+
             if (fixed_view)
             {
                 clear_held_window_dim();
                 wf::vswitch::move_view(fixed_view, target_ws);
                 output->wset()->set_workspace(target_ws);
                 wf::get_core().seat->focus_view(view);
-
-                cube_workspace_animation_signal ev;
-                ev.delta = animation_delta;
-                ev.anchor_workspace = cws;
-                ev.fixed_view = fixed_view;
-                output->emit(&ev);
-                return true;
+            } else
+            {
+                output->wset()->set_workspace(target_ws);
             }
 
-            output->wset()->set_workspace(target_ws);
             cube_workspace_animation_signal ev;
             ev.delta = animation_delta;
             ev.anchor_workspace = cws;
-            ev.fixed_view = nullptr;
+            ev.fixed_view = fixed_view;
             output->emit(&ev);
+
+            // Without a cube to animate it, use vswitch's own slide.
+            if (!ev.carried_out && start_switch())
+            {
+                algorithm->slide_from(cws);
+            }
+
             return true;
         }
 
@@ -695,8 +713,7 @@ class vswitch : public wf::per_output_plugin_instance_t
         }
 
         algorithm->set_overlay_view(toplevel_cast(view));
-        algorithm->set_target_workspace(
-            output->wset()->get_current_workspace() + delta);
+        algorithm->set_target_workspace(target_ws);
 
         return true;
     }
@@ -781,15 +798,6 @@ class vswitch : public wf::per_output_plugin_instance_t
             return;
         }
 
-        if (!ev->fixed_views.empty())
-        {
-            cube_workspace_animation_signal cube_ev;
-            cube_ev.delta = ev->new_viewport - ev->old_viewport;
-            cube_ev.anchor_workspace = ev->old_viewport;
-            cube_ev.fixed_view = ev->fixed_views[0];
-            output->emit(&cube_ev);
-        }
-
         if (is_active())
         {
             ev->carried_out = add_direction(ev->new_viewport - ev->old_viewport);