aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Cursor.zig62
-rw-r--r--river/View.zig16
-rw-r--r--river/XdgToplevel.zig9
-rw-r--r--river/render.zig31
4 files changed, 67 insertions, 51 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index dd1f51b..fd6ff76 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -434,24 +434,46 @@ fn surfaceAt(self: Self, lx: f64, ly: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
var oy = ly;
server.root.output_layout.outputCoords(wlr_output, &ox, &oy);
+ // Find the first visible fullscreen view in the stack if there is one
+ var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
+ const fullscreen_view = while (it.next()) |view| {
+ if (view.current.fullscreen) break view;
+ } else null;
+
// Check surfaces in the reverse order they are rendered in:
- // 1. overlay layer (+ popups)
- // 2. top, bottom, background popups
- // 3. top layer
- // 4. views
- // 5. bottom, background layers
+ //
+ // fullscreen:
+ // 1. overlay layer toplevels and popups
+ // 2. xwayland unmanaged stuff
+ // 3. fullscreen view toplevels and popups
+ //
+ // non-fullscreen:
+ // 1. overlay layer toplevels and popups
+ // 2. top, bottom, background layer popups
+ // 3. top layer toplevels
+ // 4. xwayland unmanaged stuff
+ // 5. view toplevels and popups
+ // 6. bottom, background layer toplevels
+
if (layerSurfaceAt(output.getLayer(.overlay).*, ox, oy, sx, sy)) |s| return s;
- for ([_]zwlr.LayerShellV1.Layer{ .top, .bottom, .background }) |layer| {
- if (layerPopupSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
- }
+ if (fullscreen_view) |view| {
+ if (build_options.xwayland) if (xwaylandUnmanagedSurfaceAt(ly, lx, sx, sy)) |s| return s;
+ if (view.surfaceAt(ox, oy, sx, sy)) |s| return s;
+ } else {
+ for ([_]zwlr.LayerShellV1.Layer{ .top, .bottom, .background }) |layer| {
+ if (layerPopupSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
+ }
- if (layerSurfaceAt(output.getLayer(.top).*, ox, oy, sx, sy)) |s| return s;
+ if (layerSurfaceAt(output.getLayer(.top).*, ox, oy, sx, sy)) |s| return s;
- if (viewSurfaceAt(output.*, ox, oy, sx, sy)) |s| return s;
+ if (build_options.xwayland) if (xwaylandUnmanagedSurfaceAt(lx, ly, sx, sy)) |s| return s;
- for ([_]zwlr.LayerShellV1.Layer{ .bottom, .background }) |layer| {
- if (layerSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
+ if (viewSurfaceAt(output, ox, oy, sx, sy)) |s| return s;
+
+ for ([_]zwlr.LayerShellV1.Layer{ .bottom, .background }) |layer| {
+ if (layerSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
+ }
}
return null;
@@ -488,7 +510,7 @@ fn layerSurfaceAt(layer: std.TailQueue(LayerSurface), ox: f64, oy: f64, sx: *f64
}
/// Find the topmost visible view surface (incl. popups) at ox,oy.
-fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
+fn viewSurfaceAt(output: *const Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
// focused, floating views
var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
while (it.next()) |view| {
@@ -520,6 +542,20 @@ fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Sur
return null;
}
+fn xwaylandUnmanagedSurfaceAt(lx: f64, ly: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
+ var it = server.root.xwayland_unmanaged_views.first;
+ while (it) |node| : (it = node.next) {
+ const xwayland_surface = node.data.xwayland_surface;
+ if (xwayland_surface.surface.?.surfaceAt(
+ lx - @intToFloat(f64, xwayland_surface.x),
+ ly - @intToFloat(f64, xwayland_surface.y),
+ sx,
+ sy,
+ )) |found| return found;
+ }
+ return null;
+}
+
fn surfaceAtFilter(view: *View, filter_tags: u32) bool {
return !view.destroying and view.current.tags & filter_tags != 0;
}
diff --git a/river/View.zig b/river/View.zig
index 79ddc1a..378008c 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -242,9 +242,9 @@ pub fn dropSavedBuffers(self: *Self) void {
}
pub fn saveBuffers(self: *Self) void {
- std.debug.assert(self.saved_buffers.items.len == 0);
+ assert(self.saved_buffers.items.len == 0);
self.saved_surface_box = self.surface_box;
- self.surface.?.forEachSurface(*std.ArrayList(SavedBuffer), saveBuffersIterator, &self.saved_buffers);
+ self.forEachSurface(*std.ArrayList(SavedBuffer), saveBuffersIterator, &self.saved_buffers);
}
fn saveBuffersIterator(
@@ -322,15 +322,21 @@ pub fn setResizing(self: Self, resizing: bool) void {
}
}
-pub inline fn forEachPopupSurface(
+/// Iterates over all surfaces, subsurfaces, and popups in the tree
+pub inline fn forEachSurface(
self: Self,
comptime T: type,
iterator: fn (surface: *wlr.Surface, sx: c_int, sy: c_int, data: T) callconv(.C) void,
user_data: T,
) void {
switch (self.impl) {
- .xdg_toplevel => |xdg_toplevel| xdg_toplevel.forEachPopupSurface(T, iterator, user_data),
- .xwayland_view => {},
+ .xdg_toplevel => |xdg_toplevel| {
+ xdg_toplevel.xdg_surface.forEachSurface(T, iterator, user_data);
+ },
+ .xwayland_view => {
+ assert(build_options.xwayland);
+ self.surface.?.forEachSurface(T, iterator, user_data);
+ },
}
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index c74a0f0..7431e05 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -124,15 +124,6 @@ pub fn setResizing(self: Self, resizing: bool) void {
_ = self.xdg_surface.role_data.toplevel.setResizing(resizing);
}
-pub inline fn forEachPopupSurface(
- self: Self,
- comptime T: type,
- iterator: fn (surface: *wlr.Surface, sx: c_int, sy: c_int, data: T) callconv(.C) void,
- user_data: T,
-) void {
- self.xdg_surface.forEachPopupSurface(T, iterator, user_data);
-}
-
/// Return the surface at output coordinates ox, oy and set sx, sy to the
/// corresponding surface-relative coordinates, if there is a surface.
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
diff --git a/river/render.zig b/river/render.zig
index 2b25bde..8bbdac7 100644
--- a/river/render.zig
+++ b/river/render.zig
@@ -80,7 +80,6 @@ pub fn renderOutput(output: *Output) void {
renderer.clear(&[_]f32{ 0, 0, 0, 1 });
renderView(output, view, &now);
if (build_options.xwayland) renderXwaylandUnmanaged(output, &now);
- if (!view.destroying) renderViewPopups(output, view, &now);
} else {
// No fullscreen view, so render normal layers/views
renderer.clear(&server.config.background_color);
@@ -126,13 +125,6 @@ pub fn renderOutput(output: *Output) void {
renderLayer(output, output.getLayer(.top).*, &now, .toplevels);
- // Render popups of focused views
- it = ViewStack(View).iter(output.views.last, .reverse, output.current.tags, renderFilter);
- while (it.next()) |view| {
- if (view.current.focus == 0 or view.destroying) continue;
- renderViewPopups(output, view, &now);
- }
-
renderLayer(output, output.getLayer(.background).*, &now, .popups);
renderLayer(output, output.getLayer(.bottom).*, &now, .popups);
renderLayer(output, output.getLayer(.top).*, &now, .popups);
@@ -200,6 +192,7 @@ fn renderLayer(
}
}
+/// Render all surfaces in the view's surface tree, including subsurfaces and popups
fn renderView(output: *const Output, view: *View, now: *os.timespec) void {
// If we have saved buffers, we are in the middle of a transaction
// and need to render those buffers until the transaction is complete.
@@ -217,29 +210,19 @@ fn renderView(output: *const Output, view: *View, now: *os.timespec) void {
saved_buffer.transform,
);
} else {
- // Since there is no stashed buffer, we are not in the middle of
- // a transaction and may simply render each toplevel surface.
+ // Since there are no stashed buffers, we are not in the middle of
+ // a transaction and may simply render the most recent buffers provided
+ // by the client.
var rdata = SurfaceRenderData{
.output = output,
.output_x = view.current.box.x - view.surface_box.x,
.output_y = view.current.box.y - view.surface_box.y,
.when = now,
};
-
- view.surface.?.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
+ view.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
}
}
-fn renderViewPopups(output: *const Output, view: *View, now: *os.timespec) void {
- var rdata = SurfaceRenderData{
- .output = output,
- .output_x = view.current.box.x - view.surface_box.x,
- .output_y = view.current.box.y - view.surface_box.y,
- .when = now,
- };
- view.forEachPopupSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
-}
-
fn renderDragIcons(output: *const Output, now: *os.timespec) void {
const output_box = server.root.output_layout.getBox(output.wlr_output).?;
@@ -263,8 +246,8 @@ fn renderDragIcons(output: *const Output, now: *os.timespec) void {
fn renderXwaylandUnmanaged(output: *const Output, now: *os.timespec) void {
const output_box = server.root.output_layout.getBox(output.wlr_output).?;
- var it = server.root.xwayland_unmanaged_views.first;
- while (it) |node| : (it = node.next) {
+ var it = server.root.xwayland_unmanaged_views.last;
+ while (it) |node| : (it = node.prev) {
const xwayland_surface = node.data.xwayland_surface;
var rdata = SurfaceRenderData{