aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/command.zig1
-rw-r--r--src/command/toggle_float.zig13
-rw-r--r--src/config.zig8
-rw-r--r--src/output.zig10
-rw-r--r--src/render.zig20
-rw-r--r--src/view.zig32
6 files changed, 83 insertions, 1 deletions
diff --git a/src/command.zig b/src/command.zig
index 01e9c33..d14831a 100644
--- a/src/command.zig
+++ b/src/command.zig
@@ -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");
diff --git a/src/command/toggle_float.zig b/src/command/toggle_float.zig
new file mode 100644
index 0000000..38250b8
--- /dev/null
+++ b/src/command/toggle_float.zig
@@ -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();
+ }
+}
diff --git a/src/config.zig b/src/config.zig
index f09dc1a..caa6cd6 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -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 = {} },
+ });
}
};
diff --git a/src/output.zig b/src/output.zig
index 9979870..a2b7de9 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -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);
diff --git a/src/render.zig b/src/render.zig
index 99bddc1..d8b46ec 100644
--- a/src/render.zig
+++ b/src/render.zig
@@ -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);
}
diff --git a/src/view.zig b/src/view.zig
index 9bde87d..3890013 100644
--- a/src/view.zig
+++ b/src/view.zig
@@ -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.