render: sync with Cursor.surfaceAt(), draw all view popups
This was slightly out of sync with Cursor.surfaceAt() which did not fullscreen or xwayland unmanaged views properly. Also simplify things and improve correctness by always rendering all xdg popups. A view losing focus does not always mean that all popups will be destroyed.
This commit is contained in:
parent
a3c6571326
commit
f62eedb048
@ -434,25 +434,47 @@ fn surfaceAt(self: Self, lx: f64, ly: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
|
|||||||
var oy = ly;
|
var oy = ly;
|
||||||
server.root.output_layout.outputCoords(wlr_output, &ox, &oy);
|
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:
|
// Check surfaces in the reverse order they are rendered in:
|
||||||
// 1. overlay layer (+ popups)
|
//
|
||||||
// 2. top, bottom, background popups
|
// fullscreen:
|
||||||
// 3. top layer
|
// 1. overlay layer toplevels and popups
|
||||||
// 4. views
|
// 2. xwayland unmanaged stuff
|
||||||
// 5. bottom, background layers
|
// 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;
|
if (layerSurfaceAt(output.getLayer(.overlay).*, 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| {
|
for ([_]zwlr.LayerShellV1.Layer{ .top, .bottom, .background }) |layer| {
|
||||||
if (layerPopupSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
|
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;
|
||||||
|
|
||||||
|
if (viewSurfaceAt(output, ox, oy, sx, sy)) |s| return s;
|
||||||
|
|
||||||
for ([_]zwlr.LayerShellV1.Layer{ .bottom, .background }) |layer| {
|
for ([_]zwlr.LayerShellV1.Layer{ .bottom, .background }) |layer| {
|
||||||
if (layerSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
|
if (layerSurfaceAt(output.getLayer(layer).*, ox, oy, sx, sy)) |s| return s;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
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.
|
/// 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
|
// focused, floating views
|
||||||
var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
|
var it = ViewStack(View).iter(output.views.first, .forward, output.current.tags, surfaceAtFilter);
|
||||||
while (it.next()) |view| {
|
while (it.next()) |view| {
|
||||||
@ -520,6 +542,20 @@ fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Sur
|
|||||||
return null;
|
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 {
|
fn surfaceAtFilter(view: *View, filter_tags: u32) bool {
|
||||||
return !view.destroying and view.current.tags & filter_tags != 0;
|
return !view.destroying and view.current.tags & filter_tags != 0;
|
||||||
}
|
}
|
||||||
|
@ -242,9 +242,9 @@ pub fn dropSavedBuffers(self: *Self) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn saveBuffers(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.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(
|
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,
|
self: Self,
|
||||||
comptime T: type,
|
comptime T: type,
|
||||||
iterator: fn (surface: *wlr.Surface, sx: c_int, sy: c_int, data: T) callconv(.C) void,
|
iterator: fn (surface: *wlr.Surface, sx: c_int, sy: c_int, data: T) callconv(.C) void,
|
||||||
user_data: T,
|
user_data: T,
|
||||||
) void {
|
) void {
|
||||||
switch (self.impl) {
|
switch (self.impl) {
|
||||||
.xdg_toplevel => |xdg_toplevel| xdg_toplevel.forEachPopupSurface(T, iterator, user_data),
|
.xdg_toplevel => |xdg_toplevel| {
|
||||||
.xwayland_view => {},
|
xdg_toplevel.xdg_surface.forEachSurface(T, iterator, user_data);
|
||||||
|
},
|
||||||
|
.xwayland_view => {
|
||||||
|
assert(build_options.xwayland);
|
||||||
|
self.surface.?.forEachSurface(T, iterator, user_data);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +124,6 @@ pub fn setResizing(self: Self, resizing: bool) void {
|
|||||||
_ = self.xdg_surface.role_data.toplevel.setResizing(resizing);
|
_ = 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
|
/// Return the surface at output coordinates ox, oy and set sx, sy to the
|
||||||
/// corresponding surface-relative coordinates, if there is a surface.
|
/// corresponding surface-relative coordinates, if there is a surface.
|
||||||
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
|
pub fn surfaceAt(self: Self, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*wlr.Surface {
|
||||||
|
@ -80,7 +80,6 @@ pub fn renderOutput(output: *Output) void {
|
|||||||
renderer.clear(&[_]f32{ 0, 0, 0, 1 });
|
renderer.clear(&[_]f32{ 0, 0, 0, 1 });
|
||||||
renderView(output, view, &now);
|
renderView(output, view, &now);
|
||||||
if (build_options.xwayland) renderXwaylandUnmanaged(output, &now);
|
if (build_options.xwayland) renderXwaylandUnmanaged(output, &now);
|
||||||
if (!view.destroying) renderViewPopups(output, view, &now);
|
|
||||||
} else {
|
} else {
|
||||||
// No fullscreen view, so render normal layers/views
|
// No fullscreen view, so render normal layers/views
|
||||||
renderer.clear(&server.config.background_color);
|
renderer.clear(&server.config.background_color);
|
||||||
@ -126,13 +125,6 @@ pub fn renderOutput(output: *Output) void {
|
|||||||
|
|
||||||
renderLayer(output, output.getLayer(.top).*, &now, .toplevels);
|
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(.background).*, &now, .popups);
|
||||||
renderLayer(output, output.getLayer(.bottom).*, &now, .popups);
|
renderLayer(output, output.getLayer(.bottom).*, &now, .popups);
|
||||||
renderLayer(output, output.getLayer(.top).*, &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 {
|
fn renderView(output: *const Output, view: *View, now: *os.timespec) void {
|
||||||
// If we have saved buffers, we are in the middle of a transaction
|
// If we have saved buffers, we are in the middle of a transaction
|
||||||
// and need to render those buffers until the transaction is complete.
|
// 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,
|
saved_buffer.transform,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Since there is no stashed buffer, we are not in the middle of
|
// Since there are no stashed buffers, we are not in the middle of
|
||||||
// a transaction and may simply render each toplevel surface.
|
// a transaction and may simply render the most recent buffers provided
|
||||||
|
// by the client.
|
||||||
var rdata = SurfaceRenderData{
|
var rdata = SurfaceRenderData{
|
||||||
.output = output,
|
.output = output,
|
||||||
.output_x = view.current.box.x - view.surface_box.x,
|
.output_x = view.current.box.x - view.surface_box.x,
|
||||||
.output_y = view.current.box.y - view.surface_box.y,
|
.output_y = view.current.box.y - view.surface_box.y,
|
||||||
.when = now,
|
.when = now,
|
||||||
};
|
};
|
||||||
|
view.forEachSurface(*SurfaceRenderData, renderSurfaceIterator, &rdata);
|
||||||
view.surface.?.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 {
|
fn renderDragIcons(output: *const Output, now: *os.timespec) void {
|
||||||
const output_box = server.root.output_layout.getBox(output.wlr_output).?;
|
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 {
|
fn renderXwaylandUnmanaged(output: *const Output, now: *os.timespec) void {
|
||||||
const output_box = server.root.output_layout.getBox(output.wlr_output).?;
|
const output_box = server.root.output_layout.getBox(output.wlr_output).?;
|
||||||
|
|
||||||
var it = server.root.xwayland_unmanaged_views.first;
|
var it = server.root.xwayland_unmanaged_views.last;
|
||||||
while (it) |node| : (it = node.next) {
|
while (it) |node| : (it = node.prev) {
|
||||||
const xwayland_surface = node.data.xwayland_surface;
|
const xwayland_surface = node.data.xwayland_surface;
|
||||||
|
|
||||||
var rdata = SurfaceRenderData{
|
var rdata = SurfaceRenderData{
|
||||||
|
Loading…
Reference in New Issue
Block a user