From 3cbd95fadcb7119336981607b51a3084b9c6aac7 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 28 Jun 2020 21:42:39 +0200 Subject: [PATCH] river: implement toggle-fullscreen The command works, but behaves a little strangely. Also, fullscreen views are not yet rendered on an opqaue backdrop. --- river/Output.zig | 36 ++++++++++++++++------------- river/View.zig | 10 ++++++++ river/VoidView.zig | 4 ++++ river/XdgToplevel.zig | 4 ++++ river/XwaylandView.zig | 4 ++++ river/command.zig | 1 + river/command/toggle_fullscreen.zig | 36 +++++++++++++++++++++++++++++ 7 files changed, 79 insertions(+), 16 deletions(-) create mode 100644 river/command/toggle_fullscreen.zig diff --git a/river/Output.zig b/river/Output.zig index 5b6855e..e4e688a 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -297,29 +297,33 @@ fn layoutExternal(self: *Self, visible_count: u32, output_tags: u32) !void { /// pending state, the changes are not appplied until a transaction is started /// and completed. pub fn arrangeViews(self: *Self) void { - // If the output has a zero dimension, trying to arrange would cause - // an underflow and is pointless anyway. - if (self.usable_box.width == 0 or self.usable_box.height == 0) return; - const output_tags = if (self.pending_focused_tags) |tags| tags else self.current_focused_tags; - const visible_count = blk: { - var count: u32 = 0; - var it = ViewStack(View).pendingIterator(self.views.first, output_tags); - while (it.next()) |node| { - if (!node.view.pending.float and !node.view.pending.fullscreen) count += 1; + const full_area = Box.fromWlrBox(c.wlr_output_layout_get_box(self.root.wlr_output_layout, self.wlr_output).*); + + // Make fullscreen views take the full area, count up views that will be + // arranged by the layout. + var layout_count: u32 = 0; + var it = ViewStack(View).pendingIterator(self.views.first, output_tags); + while (it.next()) |node| { + const view = &node.view; + if (view.pending.fullscreen) { + view.pending.box = full_area; + } else if (!view.pending.float) { + layout_count += 1; } - break :blk count; - }; + } - if (visible_count == 0) return; + // If the usable area has a zero dimension, trying to arrange the layout + // would cause an underflow and is pointless anyway. + if (layout_count == 0 or self.usable_box.width == 0 or self.usable_box.height == 0) return; - if (std.mem.eql(u8, self.layout, "full")) return layoutFull(self, visible_count, output_tags); + if (std.mem.eql(u8, self.layout, "full")) return layoutFull(self, layout_count, output_tags); - layoutExternal(self, visible_count, output_tags) catch |err| { + layoutExternal(self, layout_count, output_tags) catch |err| { switch (err) { LayoutError.BadExitCode => log.err(.layout, "layout command exited with non-zero return code", .{}), LayoutError.BadWindowConfiguration => log.err(.layout, "invalid window configuration", .{}), @@ -327,11 +331,11 @@ pub fn arrangeViews(self: *Self) void { else => log.err(.layout, "'{}' error while trying to use external layout", .{err}), } log.err(.layout, "falling back to internal layout", .{}); - layoutFull(self, visible_count, output_tags); + layoutFull(self, layout_count, output_tags); }; } -/// Arrange all layer surfaces of this output and addjust the usable aread +/// Arrange all layer surfaces of this output and adjust the usable area pub fn arrangeLayers(self: *Self) void { const full_box = blk: { var width: c_int = undefined; diff --git a/river/View.zig b/river/View.zig index 5d9cd52..e3995a8 100644 --- a/river/View.zig +++ b/river/View.zig @@ -197,6 +197,16 @@ pub fn setFocused(self: *Self, focused: bool) void { } } +/// Set the pending state to fullscren and inform the client. Should be +/// followed by starting a transaction to apply the pending state. +pub fn setFullscreen(self: *Self, fullscreen: bool) void { + self.pending.fullscreen = fullscreen; + switch (self.impl) { + .xdg_toplevel => |xdg_toplevel| xdg_toplevel.setFullscreen(fullscreen), + .xwayland_view => |xwayland_view| xwayland_view.setFullscreen(fullscreen), + } +} + /// Move a view from one output to another, sending the required enter/leave /// events. pub fn sendToOutput(self: *Self, destination_output: *Output) void { diff --git a/river/VoidView.zig b/river/VoidView.zig index 81392ff..d9bd3d4 100644 --- a/river/VoidView.zig +++ b/river/VoidView.zig @@ -35,6 +35,10 @@ pub fn setActivated(self: Self, activated: bool) void { unreachable; } +pub fn setFullscreen(self: Self, fullscreen: bool) void { + unreachable; +} + pub fn close(self: Self) void { unreachable; } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index 7243454..647c85e 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -88,6 +88,10 @@ pub fn setActivated(self: Self, activated: bool) void { _ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, activated); } +pub fn setFullscreen(self: Self, fullscreen: bool) void { + _ = c.wlr_xdg_toplevel_set_fullscreen(self.wlr_xdg_surface, fullscreen); +} + /// Close the view. This will lead to the unmap and destroy events being sent pub fn close(self: Self) void { c.wlr_xdg_toplevel_send_close(self.wlr_xdg_surface); diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 1cd0143..0f6cc82 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -83,6 +83,10 @@ pub fn setActivated(self: Self, activated: bool) void { c.wlr_xwayland_surface_activate(self.wlr_xwayland_surface, activated); } +pub fn setFullscreen(self: Self, fullscreen: bool) void { + c.wlr_xwayland_surface_set_fullscreen(self.wlr_xwayland_surface, fullscreen); +} + /// Close the view. This will lead to the unmap and destroy events being sent pub fn close(self: Self) void { c.wlr_xwayland_surface_close(self.wlr_xwayland_surface); diff --git a/river/command.zig b/river/command.zig index d5e0b6e..f71f18f 100644 --- a/river/command.zig +++ b/river/command.zig @@ -81,6 +81,7 @@ const str_to_impl_fn = [_]struct { .{ .name = "toggle-focused-tags", .impl = impl.toggleFocusedTags }, .{ .name = "toggle-view-tags", .impl = impl.toggleViewTags }, .{ .name = "zoom", .impl = impl.zoom }, + .{ .name = "toggle-fullscreen", .impl = impl.toggleFullscreen }, }; // zig fmt: on diff --git a/river/command/toggle_fullscreen.zig b/river/command/toggle_fullscreen.zig new file mode 100644 index 0000000..0b3acc7 --- /dev/null +++ b/river/command/toggle_fullscreen.zig @@ -0,0 +1,36 @@ +// This file is part of river, a dynamic tiling wayland compositor. +// +// Copyright 2020 Isaac Freund +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +const std = @import("std"); + +const Error = @import("../command.zig").Error; +const Seat = @import("../Seat.zig"); + +/// Toggle fullscreen state of the currently focused view +pub fn toggleFullscreen( + allocator: *std.mem.Allocator, + seat: *Seat, + args: []const []const u8, + out: *?[]const u8, +) Error!void { + if (args.len > 1) return Error.TooManyArguments; + + if (seat.focused_view) |view| { + view.setFullscreen(!view.pending.fullscreen); + view.output.root.arrange(); + } +}