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
|
--- a/metadata/grid.xml
+++ b/metadata/grid.xml
@@ -26,8 +26,8 @@
<default>true</default>
</option>
<option name="zone_gap" type="int">
- <_short>Monitor-zone outer gap</_short>
- <_long>Inset each physical monitor zone by this many logical pixels after panel reservations. Applies to physical-scope maximize, placement, tiling and zone drag previews. Fullscreen uses the whole selected monitor without gaps.</_long>
+ <_short>Window gap</_short>
+ <_long>Leave this many logical pixels between adjacent half or quarter slots, and around each physical monitor workarea after panel reservations. Grid keyboard placement, Move drag previews and drop targets share this gap. Monitor-specific zone_gap values override it. Fullscreen uses the whole selected monitor without gaps.</_long>
<default>0</default>
<min>0</min>
</option>
--- 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>Outer gap for Grid windows constrained to this monitor inside a combined output. -1 inherits grid/zone_gap. Does not affect ordinary maximize or fullscreen.</_long>
+ <_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>
<default>-1</default>
<min>-1</min>
<max>1000</max>
--- a/plugins/grid/grid.cpp
+++ b/plugins/grid/grid.cpp
@@ -89,7 +89,8 @@
wf::option_wrapper_t<std::string> default_scope{"core/window_scope"}, scope_rules{"core/window_scope_rules"};
wf::geometry_t slot_dimensions(wayfire_toplevel_view view, int n)
{
- auto normal = wf::grid::get_slot_dimensions(wf::window_scope_workarea(view), n);
+ auto normal = wf::grid::get_slot_dimensions(wf::window_scope_workarea(view), n,
+ wf::grid::get_slot_gap(view));
auto cycle = view->get_data<grid_size_cycle_data_t>();
if (!cycle || cycle->slot != n || !cycle->step)
{
--- a/plugins/grid/wayfire/plugins/grid.hpp
+++ b/plugins/grid/wayfire/plugins/grid.hpp
@@ -3,6 +3,11 @@
#include <wayfire/toplevel-view.hpp>
#include <wayfire/output.hpp>
#include <wayfire/workarea.hpp>
+#include <wayfire/core.hpp>
+#include <wayfire/config-backend.hpp>
+#include <wayfire/output-layout.hpp>
+#include <wayfire/window-scope.hpp>
+#include <cmath>
namespace wf
{
@@ -120,6 +125,57 @@
* 4 5 6
* 1 2 3
* */
+/** Resolve the same gap used by physical_zone_workarea(), including overrides. */
+static inline int get_slot_gap(wf::output_t *output, const std::string& monitor)
+{
+ int gap = 0;
+ if (auto option = wf::get_core().config->get_option("grid/zone_gap"))
+ gap = std::stoi(option->get_value_str());
+ const auto name = monitor.empty() ? std::string(output->handle->name) : monitor;
+ for (auto& [head, state] : wf::get_core().output_layout->get_current_configuration())
+ {
+ if (name != head->name) continue;
+ auto section = wf::get_core().config_backend->get_output_section(head);
+ if (auto option = section->get_option_or("zone_gap"))
+ {
+ int local = std::stoi(option->get_value_str());
+ if (local >= 0) gap = local;
+ }
+ break;
+ }
+ return std::max(0, gap);
+}
+
+static inline int get_slot_gap(wayfire_toplevel_view view)
+{
+ auto zone = wf::window_scope_zone(view);
+ return get_slot_gap(view->get_output(), zone ? zone->name : std::string{});
+}
+
+/** Split the available area around one shared gap, preserving the outer edges.
+ * Odd pixels belong to the right/bottom slot; even an oversized gap leaves
+ * positive slot dimensions. The workarea already includes any outer inset.
+ */
+static inline wf::geometry_t get_slot_dimensions(wf::geometry_t area, int n, int gap)
+{
+ auto split = [gap] (double& origin, double& extent, bool far)
+ {
+ const double seam = std::clamp<double>(gap, 0, std::max(0.0, extent - 2));
+ const double first = extent >= 2 ? std::floor((extent - seam) / 2) : extent / 2;
+ if (far)
+ {
+ origin += first + seam;
+ extent -= first + seam;
+ } else
+ {
+ extent = first;
+ }
+ };
+ if (n % 3 == 1 || n % 3 == 0) split(area.x, area.width, n % 3 == 0);
+ if (n >= 7 || n <= 3) split(area.y, area.height, n <= 3);
+ return area;
+}
+
inline wf::geometry_t get_slot_dimensions(wf::geometry_t area, int n)
{
int w2 = area.width / 2;
--- a/plugins/single_plugins/move-snap-map.hpp
+++ b/plugins/single_plugins/move-snap-map.hpp
@@ -142,7 +142,8 @@
r.geometry = r.geometry + origin;
wf::json_t region; region["geometry"] = wf::ipc::geometry_to_json(r.geometry);
region["slot"] = names[r.slot];
- region["target"] = wf::ipc::geometry_to_json(wf::grid::get_slot_dimensions(area, r.slot) + origin);
+ region["target"] = wf::ipc::geometry_to_json(wf::grid::get_slot_dimensions(area, r.slot,
+ wf::grid::get_slot_gap(output, name)) + origin);
monitor["regions"].append(region); render_regions.push_back(r);
}
reply["monitors"].append(monitor);
--- a/plugins/single_plugins/move-snap.hpp
+++ b/plugins/single_plugins/move-snap.hpp
@@ -158,7 +158,8 @@
result.whole_monitor = whole && !result.monitor.empty();
result.slot = result.whole_monitor ? wf::grid::SLOT_CENTER : snap_slot(area, ev->input, edge, corner);
if (!result.slot) return {};
- result.geometry = wf::grid::get_slot_dimensions(area, result.slot);
+ result.geometry = wf::grid::get_slot_dimensions(area, result.slot,
+ wf::grid::get_slot_gap(ev->output, result.monitor));
if (result.geometry.width <= 0 || result.geometry.height <= 0) return {};
result.view = ev->view->weak_from_this();
result.output = ev->output;
@@ -303,7 +304,7 @@
int slot = wf::grid::get_slot_from_tiled_edges(ev->edges);
if (!slot) return;
auto area = wf::window_scope_workarea(ev->view);
- auto g = wf::grid::get_slot_dimensions(area, slot);
+ auto g = wf::grid::get_slot_dimensions(area, slot, wf::grid::get_slot_gap(ev->view));
auto output = ev->view->get_output();
auto delta = ev->workspace - output->wset()->get_current_workspace();
g.x += delta.x * output->get_screen_size().width;
|