river: implement toggle-fullscreen

The command works, but behaves a little strangely. Also, fullscreen
views are not yet rendered on an opqaue backdrop.
This commit is contained in:
Isaac Freund 2020-06-28 21:42:39 +02:00
parent 82a444a7c0
commit 3cbd95fadc
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
7 changed files with 79 additions and 16 deletions

View File

@ -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 /// pending state, the changes are not appplied until a transaction is started
/// and completed. /// and completed.
pub fn arrangeViews(self: *Self) void { 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| const output_tags = if (self.pending_focused_tags) |tags|
tags tags
else else
self.current_focused_tags; self.current_focused_tags;
const visible_count = blk: { const full_area = Box.fromWlrBox(c.wlr_output_layout_get_box(self.root.wlr_output_layout, self.wlr_output).*);
var count: u32 = 0;
// 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); var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next()) |node| { while (it.next()) |node| {
if (!node.view.pending.float and !node.view.pending.fullscreen) count += 1; 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) { switch (err) {
LayoutError.BadExitCode => log.err(.layout, "layout command exited with non-zero return code", .{}), LayoutError.BadExitCode => log.err(.layout, "layout command exited with non-zero return code", .{}),
LayoutError.BadWindowConfiguration => log.err(.layout, "invalid window configuration", .{}), 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}), else => log.err(.layout, "'{}' error while trying to use external layout", .{err}),
} }
log.err(.layout, "falling back to internal layout", .{}); 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 { pub fn arrangeLayers(self: *Self) void {
const full_box = blk: { const full_box = blk: {
var width: c_int = undefined; var width: c_int = undefined;

View File

@ -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 /// Move a view from one output to another, sending the required enter/leave
/// events. /// events.
pub fn sendToOutput(self: *Self, destination_output: *Output) void { pub fn sendToOutput(self: *Self, destination_output: *Output) void {

View File

@ -35,6 +35,10 @@ pub fn setActivated(self: Self, activated: bool) void {
unreachable; unreachable;
} }
pub fn setFullscreen(self: Self, fullscreen: bool) void {
unreachable;
}
pub fn close(self: Self) void { pub fn close(self: Self) void {
unreachable; unreachable;
} }

View File

@ -88,6 +88,10 @@ pub fn setActivated(self: Self, activated: bool) void {
_ = c.wlr_xdg_toplevel_set_activated(self.wlr_xdg_surface, activated); _ = 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 /// Close the view. This will lead to the unmap and destroy events being sent
pub fn close(self: Self) void { pub fn close(self: Self) void {
c.wlr_xdg_toplevel_send_close(self.wlr_xdg_surface); c.wlr_xdg_toplevel_send_close(self.wlr_xdg_surface);

View File

@ -83,6 +83,10 @@ pub fn setActivated(self: Self, activated: bool) void {
c.wlr_xwayland_surface_activate(self.wlr_xwayland_surface, activated); 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 /// Close the view. This will lead to the unmap and destroy events being sent
pub fn close(self: Self) void { pub fn close(self: Self) void {
c.wlr_xwayland_surface_close(self.wlr_xwayland_surface); c.wlr_xwayland_surface_close(self.wlr_xwayland_surface);

View File

@ -81,6 +81,7 @@ const str_to_impl_fn = [_]struct {
.{ .name = "toggle-focused-tags", .impl = impl.toggleFocusedTags }, .{ .name = "toggle-focused-tags", .impl = impl.toggleFocusedTags },
.{ .name = "toggle-view-tags", .impl = impl.toggleViewTags }, .{ .name = "toggle-view-tags", .impl = impl.toggleViewTags },
.{ .name = "zoom", .impl = impl.zoom }, .{ .name = "zoom", .impl = impl.zoom },
.{ .name = "toggle-fullscreen", .impl = impl.toggleFullscreen },
}; };
// zig fmt: on // zig fmt: on

View File

@ -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 <https://www.gnu.org/licenses/>.
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();
}
}