Implement floating views

This commit is contained in:
Isaac Freund 2020-04-22 22:50:03 +02:00
parent 94760394b4
commit 1362061c4c
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11
6 changed files with 83 additions and 1 deletions

View file

@ -29,3 +29,4 @@ pub usingnamespace @import("command/spawn.zig");
pub usingnamespace @import("command/toggle_tags.zig");
pub usingnamespace @import("command/toggle_view_tags.zig");
pub usingnamespace @import("command/zoom.zig");
pub usingnamespace @import("command/toggle_float.zig");

View file

@ -0,0 +1,13 @@
const c = @import("../c.zig");
const Arg = @import("../command.zig").Arg;
const Seat = @import("../seat.zig").Seat;
/// Make the focused view float or stop floating, depending on its current
/// state.
pub fn toggleFloat(seat: *Seat, arg: Arg) void {
if (seat.focused_view) |view| {
view.setFloating(!view.floating);
view.output.root.arrange();
}
}

View file

@ -189,5 +189,13 @@ pub const Config = struct {
.command = command.sendToOutput,
.arg = .{ .direction = .Prev },
});
// Mod+Space to toggle float
try self.keybinds.append(Keybind{
.keysym = c.XKB_KEY_space,
.modifiers = mod,
.command = command.toggleFloat,
.arg = .{ .none = {} },
});
}
};

View file

@ -148,7 +148,12 @@ pub const Output = struct {
const visible_count = blk: {
var count: u32 = 0;
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next() != null) count += 1;
while (it.next()) |node| {
if (node.view.floating) {
continue;
}
count += 1;
}
break :blk count;
};
@ -178,6 +183,9 @@ pub const Output = struct {
var it = ViewStack(View).pendingIterator(self.views.first, output_tags);
while (it.next()) |node| {
const view = &node.view;
if (view.floating) {
continue;
}
if (i < master_count) {
// Add the remainder to the first master to ensure every pixel of height is used
const master_height = @divTrunc(layout_height, master_count);

View file

@ -39,6 +39,26 @@ pub fn renderOutput(output: *Output) void {
if (view.current_box.width == 0 or view.current_box.height == 0) {
continue;
}
// Floating views are rendered on top of normal views
if (view.floating) {
continue;
}
renderView(output.*, view, &now);
renderBorders(output.*, view, &now);
}
// Render floating views
it = ViewStack(View).reverseIterator(output.views.last, output.current_focused_tags);
while (it.next()) |node| {
const view = &node.view;
// This check prevents a race condition when a frame is requested
// between mapping of a view and the first configure being handled.
if (view.current_box.width == 0 or view.current_box.height == 0) {
continue;
}
if (!view.floating) {
continue;
}
renderView(output.*, view, &now);
renderBorders(output.*, view, &now);
}

View file

@ -14,9 +14,16 @@ pub const View = struct {
mapped: bool,
/// If the view is floating or not
floating: bool,
current_box: Box,
pending_box: ?Box,
/// The dimensions the view would have taken if we didn't force it to tile
natural_width: u32,
natural_height: u32,
current_tags: u32,
pending_tags: ?u32,
@ -122,6 +129,22 @@ pub const View = struct {
}
}
/// If true is passsed, make the view float. If false, return it to the tiled
/// layout.
pub fn setFloating(self: *Self, float: bool) void {
if (float and !self.floating) {
self.floating = true;
self.pending_box = Box{
.x = @intCast(i32, (self.output.usable_box.width - self.natural_width) / 2),
.y = @intCast(i32, (self.output.usable_box.height - self.natural_height) / 2),
.width = self.natural_width,
.height = self.natural_height,
};
} else if (!float and self.floating) {
self.floating = false;
}
}
/// Move a view from one output to another, sending the required enter/leave
/// events.
pub fn sendToOutput(self: *Self, destination_output: *Output) void {
@ -161,6 +184,15 @@ pub const View = struct {
c.wl_signal_add(&self.wlr_xdg_surface.surface.*.events.commit, &self.listen_commit);
self.mapped = true;
self.floating = false;
self.natural_width = @intCast(u32, self.wlr_xdg_surface.geometry.width);
self.natural_height = @intCast(u32, self.wlr_xdg_surface.geometry.height);
if (self.natural_width == 0 and self.natural_height == 0) {
self.natural_width = @intCast(u32, self.wlr_xdg_surface.surface.*.current.width);
self.natural_height = @intCast(u32, self.wlr_xdg_surface.surface.*.current.height);
}
// Focus the newly mapped view. Note: if a seat is focusing a different output
// it will continue to do so.