river: fix various fullscreen related bugs

This commit is contained in:
Isaac Freund 2023-02-28 22:56:12 +01:00
parent e11d4dc0de
commit 8cb5ca9041
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
5 changed files with 118 additions and 94 deletions

2
deps/zig-wayland vendored

@ -1 +1 @@
Subproject commit dd9ffa05cca1b5001523a309c646738c65e86aeb Subproject commit e9484c814801b520cbe4ed719cceb4d0a59f1341

View File

@ -406,6 +406,8 @@ fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
var it = self.layers.fullscreen.children.iterator(.forward); var it = self.layers.fullscreen.children.iterator(.forward);
const background_color_rect = @fieldParentPtr(wlr.SceneRect, "node", it.next().?); const background_color_rect = @fieldParentPtr(wlr.SceneRect, "node", it.next().?);
background_color_rect.setSize(width, height); background_color_rect.setSize(width, height);
std.log.info("new output mode, width: {}, height: {}", .{ width, height });
} }
server.root.applyPending(); server.root.applyPending();

View File

@ -377,87 +377,102 @@ pub fn applyPending(root: *Self) void {
} }
} }
var output_it = root.outputs.first; {
while (output_it) |node| : (output_it = node.next) { var output_it = root.outputs.first;
const output = &node.data; while (output_it) |node| : (output_it = node.next) {
const output = &node.data;
if (output.inflight.fullscreen) |view| { // Iterate the focus stack in order to ensure the currently focused/most
if (!view.pending.fullscreen or view.pending.tags & output.pending.tags == 0) { // recently focused view that requests fullscreen is given fullscreen.
output.inflight.fullscreen = null; var fullscreen_found = false;
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;
{ {
var it = output.inflight.wm_stack.iterator(.forward); var it = output.pending.focus_stack.iterator(.forward);
while (it.next()) |view| { while (it.next()) |view| {
if (!view.inflight.float and !view.inflight.fullscreen and assert(view.pending.output == output);
view.inflight.tags & output.inflight.tags != 0)
{ if (view.current.float and !view.pending.float) {
layout_count += 1; // 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) { output.inflight.tags = output.pending.tags;
// TODO don't do this if the count has not changed }
layout.startLayoutDemand(layout_count); }
{
// 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; 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); var focus_stack_it = output.inflight.focus_stack.iterator(.forward);
while (focus_stack_it.next()) |view| { while (focus_stack_it.next()) |view| {
assert(view.inflight.output == output); assert(view.inflight.output == output);
view.inflight_serial = null; 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.tree.node.reparent(output.layers.views);
view.popup_tree.node.reparent(output.layers.popups); 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; const enabled = view.current.tags & output.current.tags != 0;
view.tree.node.setEnabled(enabled); view.tree.node.setEnabled(enabled);
view.popup_tree.node.setEnabled(enabled); view.popup_tree.node.setEnabled(enabled);
// TODO this approach for syncing the order will likely cause over-damaging. if (output.inflight.fullscreen != view) {
view.tree.node.lowerToBottom(); // TODO this approach for syncing the order will likely cause over-damaging.
view.tree.node.lowerToBottom();
}
view.updateCurrent(); 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); output.status.handleTransactionCommit(output);
} }

View File

@ -193,19 +193,25 @@ pub fn updateCurrent(view: *Self) void {
view.tree.node.setPosition(box.x, box.y); view.tree.node.setPosition(box.x, box.y);
view.popup_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; 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.node.setPosition(-border_width, -border_width);
view.borders.left.setSize(border_width, box.height + 2 * border_width); view.borders.left.setSize(border_width, box.height + 2 * border_width);
view.borders.left.setColor(color); view.borders.left.setColor(color);
view.borders.right.node.setEnabled(enable_borders);
view.borders.right.node.setPosition(box.width, -border_width); view.borders.right.node.setPosition(box.width, -border_width);
view.borders.right.setSize(border_width, box.height + 2 * border_width); view.borders.right.setSize(border_width, box.height + 2 * border_width);
view.borders.right.setColor(color); view.borders.right.setColor(color);
view.borders.top.node.setEnabled(enable_borders);
view.borders.top.node.setPosition(0, -border_width); view.borders.top.node.setPosition(0, -border_width);
view.borders.top.setSize(box.width, border_width); view.borders.top.setSize(box.width, border_width);
view.borders.top.setColor(color); view.borders.top.setColor(color);
view.borders.bottom.node.setEnabled(enable_borders);
view.borders.bottom.node.setPosition(0, box.height); view.borders.bottom.node.setPosition(0, box.height);
view.borders.bottom.setSize(box.width, border_width); view.borders.bottom.setSize(box.width, border_width);
view.borders.bottom.setColor(color); view.borders.bottom.setColor(color);

View File

@ -33,6 +33,9 @@ pub fn toggleFullscreen(
const view = seat.focused.view; const view = seat.focused.view;
view.pending.fullscreen = !view.pending.fullscreen; 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(); server.root.applyPending();
} }
} }