Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
XdgPopup: improve output selection
The current logic is poorly thought out and can end up placing popups
on outputs which the parent surface does not overlap at all.
Use the output with maximum overlap with the xdg popup's anchor rect.
References: https://codeberg.org/vyivel/croissant
river/OutputManager.zig | 20 ++++++++++++++++++++
river/XdgPopup.zig | 8 ++++----
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/river/OutputManager.zig b/river/OutputManager.zig
index d2437ef..088bbfb 100644
--- a/river/OutputManager.zig
+++ b/river/OutputManager.zig
@@ -466,3 +466,23 @@ fn sendConfig(om: *OutputManager) !void {
// compared to the last config set.
om.wlr_output_manager.setConfiguration(config);
}
+
+// Returning a wlr.Output rather than Output is more convenient at the callsites.
+pub fn maxOverlapOutput(om: *OutputManager, box: *const wlr.Box) ?*wlr.Output {
+ var max_overlap_area: i32 = 0;
+ var max_overlap_output: ?*wlr.Output = null;
+ var it = om.outputs.iterator(.forward);
+ while (it.next()) |output| {
+ const wlr_output = output.wlr_output orelse continue;
+ var overlap: wlr.Box = undefined;
+ om.output_layout.getBox(wlr_output, &overlap);
+ if (overlap.empty()) continue; // output not in layout
+ _ = overlap.intersection(&overlap, box);
+ const overlap_area = overlap.width * overlap.height;
+ if (overlap_area > max_overlap_area) {
+ max_overlap_area = overlap_area;
+ max_overlap_output = wlr_output;
+ }
+ }
+ return max_overlap_output;
+}
diff --git a/river/XdgPopup.zig b/river/XdgPopup.zig
index c072d9a..a1ff7cc 100644
--- a/river/XdgPopup.zig
+++ b/river/XdgPopup.zig
@@ -92,10 +92,10 @@ fn handleReposition(listener: *wl.Listener(void)) void {
var root_ly: c_int = undefined;
_ = xdg_popup.root.node.coords(&root_lx, &root_ly);
- const wlr_output = server.om.outputAt(
- @floatFromInt(root_lx + xdg_popup.wlr_popup.scheduled.geometry.x),
- @floatFromInt(root_ly + xdg_popup.wlr_popup.scheduled.geometry.y),
- ) orelse return;
+ var anchor = xdg_popup.wlr_popup.scheduled.rules.anchor_rect;
+ anchor.x += root_lx;
+ anchor.y += root_ly;
+ const wlr_output = server.om.maxOverlapOutput(&anchor) orelse return;
var box: wlr.Box = undefined;
server.om.output_layout.getBox(wlr_output, &box);