diff --git a/river/Cursor.zig b/river/Cursor.zig index e826952..eeae028 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -286,8 +286,7 @@ fn processMotion(self: Self, time: u32) void { fn surfaceAt(self: Self, lx: f64, ly: f64, sx: *f64, sy: *f64) ?*c.wlr_surface { // Find the output to check const root = self.seat.input_manager.server.root; - const wlr_output = c.wlr_output_layout_output_at(root.wlr_output_layout, lx, ly) orelse - return null; + const wlr_output = c.wlr_output_layout_output_at(root.wlr_output_layout, lx, ly) orelse return null; const output = util.voidCast(Output, wlr_output.*.data orelse return null); // Get output-local coords from the layout coords @@ -304,36 +303,21 @@ fn surfaceAt(self: Self, lx: f64, ly: f64, sx: *f64, sy: *f64) ?*c.wlr_surface { }; // Check overlay layer incl. popups - if (layerSurfaceAt(output.*, output.layers[layer_idxs[0]], ox, oy, sx, sy, false)) |surface| { - return surface; - } + if (layerSurfaceAt(output.*, output.layers[layer_idxs[0]], ox, oy, sx, sy, false)) |s| return s; // Check top-background popups only - for (layer_idxs[1..4]) |layer_idx| { - if (layerSurfaceAt(output.*, output.layers[layer_idx], ox, oy, sx, sy, true)) |surface| { - return surface; - } - } + for (layer_idxs[1..4]) |idx| + if (layerSurfaceAt(output.*, output.layers[idx], ox, oy, sx, sy, true)) |s| return s; // Check top layer - if (layerSurfaceAt(output.*, output.layers[layer_idxs[1]], ox, oy, sx, sy, false)) |surface| { - return surface; - } + if (layerSurfaceAt(output.*, output.layers[layer_idxs[1]], ox, oy, sx, sy, false)) |s| return s; - // Check floating views then normal views - if (viewSurfaceAt(output.*, ox, oy, sx, sy, true)) |surface| { - return surface; - } - if (viewSurfaceAt(output.*, ox, oy, sx, sy, false)) |surface| { - return surface; - } + // Check views + if (viewSurfaceAt(output.*, ox, oy, sx, sy)) |s| return s; // Check the bottom-background layers - for (layer_idxs[2..4]) |layer_idx| { - if (layerSurfaceAt(output.*, output.layers[layer_idx], ox, oy, sx, sy, false)) |surface| { - return surface; - } - } + for (layer_idxs[2..4]) |idx| + if (layerSurfaceAt(output.*, output.layers[idx], ox, oy, sx, sy, false)) |s| return s; return null; } @@ -373,18 +357,10 @@ fn layerSurfaceAt( return null; } -/// Find the topmost visible view surface (incl. popups) at ox,oy. Will -/// check only floating views if floating is true. -fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64, floating: bool) ?*c.wlr_surface { +/// Find the topmost visible view surface (incl. popups) at ox,oy. +fn viewSurfaceAt(output: Output, ox: f64, oy: f64, sx: *f64, sy: *f64) ?*c.wlr_surface { var it = ViewStack(View).iterator(output.views.first, output.current_focused_tags); - while (it.next()) |node| { - const view = &node.view; - if (view.floating != floating) { - continue; - } - if (view.surfaceAt(ox, oy, sx, sy)) |found| { - return found; - } - } - return null; + return while (it.next()) |node| { + if (node.view.surfaceAt(ox, oy, sx, sy)) |found| break found; + } else null; } diff --git a/river/Output.zig b/river/Output.zig index 36eb343..f1f4419 100644 --- a/river/Output.zig +++ b/river/Output.zig @@ -181,8 +181,7 @@ fn layoutFull(self: *Self, visible_count: u32, output_tags: u32) void { var it = ViewStack(View).pendingIterator(self.views.first, output_tags); while (it.next()) |node| { const view = &node.view; - if (view.floating) continue; - view.pending_box = full_box; + if (view.mode == .layout) view.pending_box = full_box; } } @@ -287,9 +286,10 @@ fn layoutExternal(self: *Self, visible_count: u32, output_tags: u32) !void { var view_it = ViewStack(View).pendingIterator(self.views.first, output_tags); while (view_it.next()) |node| { const view = &node.view; - if (view.floating) continue; - view.pending_box = view_boxen.items[i]; - i += 1; + if (view.mode == .layout) { + view.pending_box = view_boxen.items[i]; + i += 1; + } } } @@ -310,8 +310,7 @@ pub fn arrangeViews(self: *Self) void { var count: u32 = 0; var it = ViewStack(View).pendingIterator(self.views.first, output_tags); while (it.next()) |node| { - if (node.view.floating) continue; - count += 1; + if (node.view.mode == .layout) count += 1; } break :blk count; }; diff --git a/river/View.zig b/river/View.zig index ca9bed0..a50957e 100644 --- a/river/View.zig +++ b/river/View.zig @@ -29,16 +29,18 @@ const Output = @import("Output.zig"); const Root = @import("Root.zig"); const ViewStack = @import("view_stack.zig").ViewStack; const XdgToplevel = @import("XdgToplevel.zig"); -const XwaylandView = if (build_options.xwayland) - @import("XwaylandView.zig") -else - @import("VoidView.zig"); +const XwaylandView = if (build_options.xwayland) @import("XwaylandView.zig") else @import("VoidView.zig"); const Impl = union(enum) { xdg_toplevel: XdgToplevel, xwayland_view: XwaylandView, }; +const Mode = enum { + layout, + float, +}; + const SavedBuffer = struct { wlr_buffer: *c.wlr_buffer, box: Box, @@ -54,8 +56,8 @@ output: *Output, /// This is non-null exactly when the view is mapped wlr_surface: ?*c.wlr_surface, -/// If the view is floating or not -floating: bool, +/// The current mode of the view +mode: Mode, /// True if the view is currently focused by at least one seat focused: bool, @@ -92,6 +94,7 @@ pub fn init(self: *Self, output: *Output, tags: u32, surface: var) void { self.output = output; self.wlr_surface = null; + self.mode = .layout; self.focused = false; @@ -196,21 +199,27 @@ pub fn setFocused(self: *Self, focused: bool) void { } } -/// 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 = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.width) - - @intCast(i32, self.natural_width), 2)), - .y = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.height) - - @intCast(i32, self.natural_height), 2)), - .width = self.natural_width, - .height = self.natural_height, - }; - } else if (!float and self.floating) { - self.floating = false; +/// Set the mode of the view to the given mode +pub fn setMode(self: *Self, mode: Mode) void { + switch (self.mode) { + .layout => switch (mode) { + .layout => {}, + .float => { + self.mode = .float; + self.pending_box = Box{ + .x = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.width) - + @intCast(i32, self.natural_width), 2)), + .y = std.math.max(0, @divTrunc(@intCast(i32, self.output.usable_box.height) - + @intCast(i32, self.natural_height), 2)), + .width = self.natural_width, + .height = self.natural_height, + }; + }, + }, + .float => switch (mode) { + .float => {}, + .layout => self.mode = .layout, + }, } } diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index ea8858d..dbbcb9d 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -152,7 +152,6 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { c.wl_signal_add(&self.wlr_xdg_surface.events.new_popup, &self.listen_new_popup); view.wlr_surface = self.wlr_xdg_surface.surface; - view.floating = false; view.natural_width = @intCast(u32, self.wlr_xdg_surface.geometry.width); view.natural_height = @intCast(u32, self.wlr_xdg_surface.geometry.height); @@ -172,7 +171,7 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { for (root.server.config.float_filter.items) |filter_app_id| { // Make views with app_ids listed in the float filter float if (std.mem.eql(u8, std.mem.span(app_id), std.mem.span(filter_app_id))) { - view.setFloating(true); + view.setMode(.float); break; } } else if ((wlr_xdg_toplevel.parent != null) or @@ -180,7 +179,7 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { (state.min_width == state.max_width or state.min_height == state.max_height))) { // If the toplevel has a parent or is of fixed size make it float - view.setFloating(true); + view.setMode(.float); } // If the toplevel has no parent, inform it that it is tiled. This diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index 9195d83..6ac5840 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -140,7 +140,6 @@ fn handleMap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { c.wl_signal_add(&self.wlr_xwayland_surface.surface.*.events.commit, &self.listen_commit); view.wlr_surface = self.wlr_xwayland_surface.surface; - view.floating = false; view.natural_width = self.wlr_xwayland_surface.width; view.natural_height = self.wlr_xwayland_surface.height; diff --git a/river/command/toggle_float.zig b/river/command/toggle_float.zig index 26e725a..4ade683 100644 --- a/river/command/toggle_float.zig +++ b/river/command/toggle_float.zig @@ -30,7 +30,10 @@ pub fn toggleFloat( ) Error!void { if (args.len > 1) return Error.TooManyArguments; if (seat.focused_view) |view| { - view.setFloating(!view.floating); + switch (view.mode) { + .layout => view.setMode(.float), + .float => view.setMode(.layout), + } view.output.root.arrange(); } } diff --git a/river/command/zoom.zig b/river/command/zoom.zig index 702698d..e21e038 100644 --- a/river/command/zoom.zig +++ b/river/command/zoom.zig @@ -36,8 +36,8 @@ pub fn zoom( const output = seat.focused_output; const focused_node = @fieldParentPtr(ViewStack(View).Node, "view", current_focus); - // Don't zoom floating views - if (current_focus.floating) return; + // Only zoom views that are part of the layout + if (current_focus.mode != .layout) return; var it = ViewStack(View).iterator(output.views.first, output.current_focused_tags); const zoom_node = if (focused_node == it.next())