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
|
Plain outputs get the grid/zone_gap inset around their workarea, like a physical zone of a combined
output: maximize, half and quarter slots, Move drag previews and drop targets. Stitched layouts unchanged.
diff --git a/metadata/output.xml b/metadata/output.xml
index 34bc29b..041af82 100644
--- a/metadata/output.xml
+++ b/metadata/output.xml
@@ -10,7 +10,7 @@
</option>
<option name="zone_gap" type="int">
<_short>Physical monitor zone gap</_short>
- <_long>Gap between adjacent snapped windows on this monitor and around its workarea inside a combined output. -1 inherits grid/zone_gap. Applies to Grid keyboard placement and Move drag previews and drop targets. Fullscreen has no gap.</_long>
+ <_long>Gap between adjacent snapped windows on this monitor and around its workarea, whether it is its own output or part of a combined output. -1 inherits grid/zone_gap. Applies to Grid keyboard placement and Move drag previews and drop targets. Fullscreen has no gap.</_long>
<default>-1</default>
<min>-1</min>
<max>1000</max>
diff --git a/plugins/single_plugins/move-snap-map.hpp b/plugins/single_plugins/move-snap-map.hpp
index 56acac4..a55249d 100644
--- a/plugins/single_plugins/move-snap-map.hpp
+++ b/plugins/single_plugins/move-snap-map.hpp
@@ -154,7 +154,7 @@ class move_snap_map_t
auto layout = output->get_data<wf::output_stitch_layout_t>();
if (selected_scope == "physical" && layout && !layout->zones.empty())
for (auto& zone : layout->zones) add(output, zone.name, zone.geometry, wf::physical_zone_workarea(output, zone));
- else add(output, output->handle->name, output->get_relative_geometry(), output->workarea->get_workarea());
+ else add(output, output->handle->name, output->get_relative_geometry(), wf::unzoned_workarea(output));
}
return reply;
}
diff --git a/plugins/single_plugins/move-snap.hpp b/plugins/single_plugins/move-snap.hpp
index 2c2fce5..18bc85d 100644
--- a/plugins/single_plugins/move-snap.hpp
+++ b/plugins/single_plugins/move-snap.hpp
@@ -134,7 +134,7 @@ class move_snap_t : public wf::per_output_tracker_mixin_t<>
{
destination_t result;
if (!enabled || !eligible(ev->view) || !ev->output || !(ev->output->get_relative_geometry() & ev->input)) return result;
- auto area = ev->output->workarea->get_workarea();
+ auto area = wf::unzoned_workarea(ev->output);
auto policy = wf::window_scope_policy(ev->view);
const bool whole = shift_zones && (wf::get_core().seat->get_keyboard_modifiers() & WLR_MODIFIER_SHIFT);
if (auto layout = ev->output->get_data<wf::output_stitch_layout_t>();
diff --git a/src/api/wayfire/window-scope.hpp b/src/api/wayfire/window-scope.hpp
index 7bc952b..73f8d3e 100644
--- a/src/api/wayfire/window-scope.hpp
+++ b/src/api/wayfire/window-scope.hpp
@@ -14,6 +14,9 @@ std::optional<output_stitch_zone_t> window_scope_zone_peek(wayfire_toplevel_view
wf::geometry_t window_scope_workarea(wayfire_toplevel_view view);
wf::geometry_t window_scope_fullscreen(wayfire_toplevel_view view);
wf::geometry_t physical_zone_workarea(wf::output_t *output, const output_stitch_zone_t& zone);
+/** The workarea outside physical zones. A plain output is one monitor, so it gets the same grid/zone_gap
+ * inset as a physical zone; the virtual scope of a combined output stays edge to edge. */
+wf::geometry_t unzoned_workarea(wf::output_t *output);
void prepare_window_scope(wayfire_toplevel_view view);
void update_window_scope_after_move(wayfire_toplevel_view view);
void apply_window_scope(wayfire_toplevel_view view, std::optional<wf::point_t> workspace = {});
diff --git a/src/core/window-scope.cpp b/src/core/window-scope.cpp
index c5b42f8..c7be4b6 100644
--- a/src/core/window-scope.cpp
+++ b/src/core/window-scope.cpp
@@ -155,13 +155,12 @@ std::optional<output_stitch_zone_t> window_scope_zone_peek(wayfire_toplevel_view
return {};
}
-wf::geometry_t physical_zone_workarea(wf::output_t *output, const output_stitch_zone_t& zone)
+/** Inset a monitor's workarea by grid/zone_gap, or by its [output:NAME] zone_gap when that is not negative. */
+static wf::geometry_t inset_by_zone_gap(wf::geometry_t area, const std::string& monitor)
{
- auto area = geometry_intersection(zone.geometry, output->workarea->get_workarea());
- if (area.width <= 0 || area.height <= 0) area = zone.geometry;
int gap = 0;
if (auto option = get_core().config->get_option("grid/zone_gap")) gap = std::stoi(option->get_value_str());
- if (auto section = get_core().config->get_section("output:" + zone.name))
+ if (auto section = get_core().config->get_section("output:" + monitor))
{
if (auto option = section->get_option_or("zone_gap"))
{
@@ -173,10 +172,23 @@ wf::geometry_t physical_zone_workarea(wf::output_t *output, const output_stitch_
double gy = std::clamp<double>(gap, 0, std::max(0.0, std::floor((area.height - 1) / 2)));
return {area.x + gx, area.y + gy, area.width - 2 * gx, area.height - 2 * gy};
}
+wf::geometry_t physical_zone_workarea(wf::output_t *output, const output_stitch_zone_t& zone)
+{
+ auto area = geometry_intersection(zone.geometry, output->workarea->get_workarea());
+ if (area.width <= 0 || area.height <= 0) area = zone.geometry;
+ return inset_by_zone_gap(area, zone.name);
+}
+wf::geometry_t unzoned_workarea(wf::output_t *output)
+{
+ auto area = output->workarea->get_workarea();
+ auto layout = output->get_data<output_stitch_layout_t>();
+ if (layout && !layout->zones.empty()) return area;
+ return inset_by_zone_gap(area, output->to_string());
+}
wf::geometry_t window_scope_workarea(wayfire_toplevel_view view)
{
if (auto zone = window_scope_zone(view)) return physical_zone_workarea(view->get_output(), *zone);
- return view->get_output()->workarea->get_workarea();
+ return unzoned_workarea(view->get_output());
}
wf::geometry_t window_scope_fullscreen(wayfire_toplevel_view view)
{
|