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{