From 8cb5ca904195260e17ac0a64972a93f8205d9743 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 28 Feb 2023 22:56:12 +0100 Subject: [PATCH] river: fix various fullscreen related bugs --- deps/zig-wayland | 2 +- river/Output.zig | 2 + river/Root.zig | 199 +++++++++++++++------------- river/View.zig | 6 + river/command/toggle_fullscreen.zig | 3 + 5 files changed, 118 insertions(+), 94 deletions(-) diff --git a/deps/zig-wayland b/deps/zig-wayland index dd9ffa0..e9484c8 160000 --- a/deps/zig-wayland +++ b/deps/zig-wayland @@ -1 +1 @@ -Subproject commit dd9ffa05cca1b5001523a309c646738c65e86aeb +Subproject commit e9484c814801b520cbe4ed719cceb4d0a59f1341 diff --git a/river/Output.zig b/river/Output.zig index 0a921cf..adbded4 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -406,6 +406,8 @@ fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void { var it = self.layers.fullscreen.children.iterator(.forward); const background_color_rect = @fieldParentPtr(wlr.SceneRect, "node", it.next().?); background_color_rect.setSize(width, height); + + std.log.info("new output mode, width: {}, height: {}", .{ width, height }); } server.root.applyPending(); diff --git a/river/Root.zig b/river/Root.zig index 3a892bd..4f08d38 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -377,87 +377,102 @@ pub fn applyPending(root: *Self) void { } } - var output_it = root.outputs.first; - while (output_it) |node| : (output_it = node.next) { - const output = &node.data; + { + var output_it = root.outputs.first; + while (output_it) |node| : (output_it = node.next) { + const output = &node.data; - if (output.inflight.fullscreen) |view| { - if (!view.pending.fullscreen or view.pending.tags & output.pending.tags == 0) { - output.inflight.fullscreen = null; - - view.setFullscreen(false); - view.pending.box = view.post_fullscreen_box; - } - } - - // Iterate the focus stack in order to ensure the currently focused/most - // recently focused view that requests fullscreen is given fullscreen. - { - var it = output.pending.focus_stack.iterator(.forward); - while (it.next()) |view| { - assert(view.pending.output == output); - - if (view.current.float and !view.pending.float) { - // If switching from float to non-float, save the dimensions. - view.float_box = view.current.box; - } else if (!view.current.float and view.pending.float) { - // If switching from non-float to float, apply the saved float dimensions. - view.pending.box = view.float_box; - } - - if (output.inflight.fullscreen == null) { - if (view.pending.fullscreen and view.pending.tags & output.pending.tags != 0) { - output.inflight.fullscreen = view; - - view.setFullscreen(true); - view.post_fullscreen_box = view.pending.box; - view.pending.box = .{ - .x = 0, - .y = 0, - .width = undefined, - .height = undefined, - }; - output.wlr_output.effectiveResolution( - &view.pending.box.width, - &view.pending.box.height, - ); - } - } - - view.inflight_focus_stack_link.remove(); - output.inflight.focus_stack.append(view); - - view.inflight = view.pending; - } - } - - { - var it = output.pending.wm_stack.iterator(.forward); - while (it.next()) |view| { - view.inflight_wm_stack_link.remove(); - output.inflight.wm_stack.append(view); - } - } - - output.inflight.tags = output.pending.tags; - - assert(output.inflight.layout_demand == null); - if (output.layout) |layout| { - var layout_count: u32 = 0; + // Iterate the focus stack in order to ensure the currently focused/most + // recently focused view that requests fullscreen is given fullscreen. + var fullscreen_found = false; { - var it = output.inflight.wm_stack.iterator(.forward); + var it = output.pending.focus_stack.iterator(.forward); while (it.next()) |view| { - if (!view.inflight.float and !view.inflight.fullscreen and - view.inflight.tags & output.inflight.tags != 0) - { - layout_count += 1; + assert(view.pending.output == output); + + if (view.current.float and !view.pending.float) { + // If switching from float to non-float, save the dimensions. + view.float_box = view.current.box; + } else if (!view.current.float and view.pending.float) { + // If switching from non-float to float, apply the saved float dimensions. + view.pending.box = view.float_box; } + + if (!fullscreen_found and view.pending.fullscreen and + view.pending.tags & output.pending.tags != 0) + { + fullscreen_found = true; + if (output.inflight.fullscreen != view) { + if (output.inflight.fullscreen) |old| { + old.setFullscreen(false); + old.pending.box = old.post_fullscreen_box; + old.inflight.box = old.pending.box; + } + + output.inflight.fullscreen = view; + + view.setFullscreen(true); + view.post_fullscreen_box = view.pending.box; + view.pending.box = .{ + .x = 0, + .y = 0, + .width = undefined, + .height = undefined, + }; + output.wlr_output.effectiveResolution( + &view.pending.box.width, + &view.pending.box.height, + ); + view.inflight.box = view.pending.box; + } + } + + view.inflight_focus_stack_link.remove(); + output.inflight.focus_stack.append(view); + + view.inflight = view.pending; + } + } + if (!fullscreen_found) { + output.inflight.fullscreen = null; + } + + { + var it = output.pending.wm_stack.iterator(.forward); + while (it.next()) |view| { + view.inflight_wm_stack_link.remove(); + output.inflight.wm_stack.append(view); } } - if (layout_count > 0) { - // TODO don't do this if the count has not changed - layout.startLayoutDemand(layout_count); + output.inflight.tags = output.pending.tags; + } + } + + { + // Layout demands can't be sent until after the inflight stacks of + // all outputs have been updated. + var output_it = root.outputs.first; + while (output_it) |node| : (output_it = node.next) { + const output = &node.data; + assert(output.inflight.layout_demand == null); + if (output.layout) |layout| { + var layout_count: u32 = 0; + { + var it = output.inflight.wm_stack.iterator(.forward); + while (it.next()) |view| { + if (!view.inflight.float and !view.inflight.fullscreen and + view.inflight.tags & output.inflight.tags != 0) + { + layout_count += 1; + } + } + } + + if (layout_count > 0) { + // TODO don't do this if the count has not changed + layout.startLayoutDemand(layout_count); + } } } } @@ -570,29 +585,15 @@ fn commitTransaction(root: *Self) void { } output.current.tags = output.inflight.tags; - if (output.inflight.fullscreen != output.current.fullscreen) { - if (output.current.fullscreen) |view| { - if (view.inflight.output) |new_output| { - view.tree.node.reparent(new_output.layers.views); - } else { - view.tree.node.reparent(root.hidden.tree); - } - } - if (output.inflight.fullscreen) |view| { - assert(view.inflight.output == output); - view.tree.node.reparent(output.layers.fullscreen); - } - output.current.fullscreen = output.inflight.fullscreen; - output.layers.fullscreen.node.setEnabled(output.current.fullscreen != null); - } - var focus_stack_it = output.inflight.focus_stack.iterator(.forward); while (focus_stack_it.next()) |view| { assert(view.inflight.output == output); view.inflight_serial = null; - if (view.current.output != output) { + if (view.current.output != output or + (output.current.fullscreen == view and output.inflight.fullscreen != view)) + { view.tree.node.reparent(output.layers.views); view.popup_tree.node.reparent(output.layers.popups); } @@ -600,12 +601,24 @@ fn commitTransaction(root: *Self) void { const enabled = view.current.tags & output.current.tags != 0; view.tree.node.setEnabled(enabled); view.popup_tree.node.setEnabled(enabled); - // TODO this approach for syncing the order will likely cause over-damaging. - view.tree.node.lowerToBottom(); + if (output.inflight.fullscreen != view) { + // TODO this approach for syncing the order will likely cause over-damaging. + view.tree.node.lowerToBottom(); + } view.updateCurrent(); } + if (output.inflight.fullscreen != output.current.fullscreen) { + if (output.inflight.fullscreen) |view| { + assert(view.inflight.output == output); + assert(view.current.output == output); + view.tree.node.reparent(output.layers.fullscreen); + } + output.current.fullscreen = output.inflight.fullscreen; + output.layers.fullscreen.node.setEnabled(output.current.fullscreen != null); + } + output.status.handleTransactionCommit(output); } diff --git a/river/View.zig b/river/View.zig index 4182a04..399dcdd 100644 --- a/river/View.zig +++ b/river/View.zig @@ -193,19 +193,25 @@ pub fn updateCurrent(view: *Self) void { view.tree.node.setPosition(box.x, box.y); view.popup_tree.node.setPosition(box.x, box.y); + const enable_borders = view.draw_borders and !view.current.fullscreen; + const border_width: c_int = config.border_width; + view.borders.left.node.setEnabled(enable_borders); view.borders.left.node.setPosition(-border_width, -border_width); view.borders.left.setSize(border_width, box.height + 2 * border_width); view.borders.left.setColor(color); + view.borders.right.node.setEnabled(enable_borders); view.borders.right.node.setPosition(box.width, -border_width); view.borders.right.setSize(border_width, box.height + 2 * border_width); view.borders.right.setColor(color); + view.borders.top.node.setEnabled(enable_borders); view.borders.top.node.setPosition(0, -border_width); view.borders.top.setSize(box.width, border_width); view.borders.top.setColor(color); + view.borders.bottom.node.setEnabled(enable_borders); view.borders.bottom.node.setPosition(0, box.height); view.borders.bottom.setSize(box.width, border_width); view.borders.bottom.setColor(color); diff --git a/river/command/toggle_fullscreen.zig b/river/command/toggle_fullscreen.zig index 5dfef41..402cce3 100644 --- a/river/command/toggle_fullscreen.zig +++ b/river/command/toggle_fullscreen.zig @@ -33,6 +33,9 @@ pub fn toggleFullscreen( const view = seat.focused.view; view.pending.fullscreen = !view.pending.fullscreen; + // It is possible to end up with multiple fullscreen views in which + // case making one non-fullscreen should switch focus to the next. + seat.focus(null); server.root.applyPending(); } }