git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit5a94fa177bcd271b2dc000d16fe357c716a86bf0
parentdbbc744096
authorIsaac Freund <[email protected]>
date2024-06-28 10:42
river: remove river-layout-v3

 river/Cursor.zig        |   6 --
 river/Layout.zig        | 210 ------------------------------------------------
 river/LayoutDemand.zig  | 157 ------------------------------------
 river/LayoutManager.zig |  88 --------------------
 river/Output.zig        |  43 ----------
 river/Root.zig          |  63 +--------------
 river/Server.zig        |   5 --
 river/XdgToplevel.zig   |  15 ++--
 8 files changed, 7 insertions(+), 580 deletions(-)

diff --git a/river/Cursor.zig b/river/Cursor.zig
index d48da99..c873936 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -877,11 +877,6 @@ fn enterMode(cursor: *Cursor, mode: Mode, view: *View, xcursor_name: [*:0]const
 
     cursor.seat.focus(view);
 
-    if (view.current.output.?.layout != null) {
-        view.float_box = view.current.box;
-        view.pending.float = true;
-    }
-
     cursor.seat.wlr_seat.pointerNotifyClearFocus();
     cursor.setXcursor(xcursor_name);
 
@@ -1120,7 +1115,6 @@ pub fn updateState(cursor: *Cursor) void {
                     // These conditions are checked in Root.applyPending()
                     const output = data.view.current.output orelse return;
                     assert(data.view.current.tags & output.current.tags != 0);
-                    assert(data.view.current.float or output.layout == null);
                     assert(!data.view.current.fullscreen);
 
                     // Keep the cursor locked to the original offset from the edges of the view.
diff --git a/river/Layout.zig b/river/Layout.zig
deleted file mode 100644
index 6bd107f..0000000
--- a/river/Layout.zig
+++ /dev/null
@@ -1,210 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020 - 2021 The River Developers
-//
-// 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, version 3.
-//
-// 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 Layout = @This();
-
-const std = @import("std");
-const assert = std.debug.assert;
-const math = std.math;
-const mem = std.mem;
-const wlr = @import("wlroots");
-const wayland = @import("wayland");
-const wl = wayland.server.wl;
-const river = wayland.server.river;
-
-const server = &@import("main.zig").server;
-const util = @import("util.zig");
-
-const Output = @import("Output.zig");
-const View = @import("View.zig");
-const LayoutDemand = @import("LayoutDemand.zig");
-
-const log = std.log.scoped(.layout);
-
-layout_v3: *river.LayoutV3,
-namespace: []const u8,
-output: *Output,
-
-pub fn create(client: *wl.Client, version: u32, id: u32, output: *Output, namespace: []const u8) !void {
-    const layout_v3 = try river.LayoutV3.create(client, version, id);
-
-    if (namespaceInUse(namespace, output, client)) {
-        layout_v3.sendNamespaceInUse();
-        layout_v3.setHandler(?*anyopaque, handleRequestInert, null, null);
-        return;
-    }
-
-    const node = try util.gpa.create(std.TailQueue(Layout).Node);
-    errdefer util.gpa.destroy(node);
-    node.data = .{
-        .layout_v3 = layout_v3,
-        .namespace = try util.gpa.dupe(u8, namespace),
-        .output = output,
-    };
-    output.layouts.append(node);
-
-    layout_v3.setHandler(*Layout, handleRequest, handleDestroy, &node.data);
-
-    // If the namespace matches that of the output, set the layout as
-    // the active one of the output and arrange it.
-    if (mem.eql(u8, namespace, output.layoutNamespace())) {
-        output.layout = &node.data;
-        server.root.applyPending();
-    }
-}
-
-/// Returns true if the given namespace is already in use on the given output
-/// or on another output by a different client.
-fn namespaceInUse(namespace: []const u8, output: *Output, client: *wl.Client) bool {
-    var output_it = server.root.active_outputs.iterator(.forward);
-    while (output_it.next()) |o| {
-        var layout_it = output.layouts.first;
-        if (o == output) {
-            // On this output, no other layout can have our namespace.
-            while (layout_it) |layout_node| : (layout_it = layout_node.next) {
-                if (mem.eql(u8, namespace, layout_node.data.namespace)) return true;
-            }
-        } else {
-            // Layouts on other outputs may share the namespace, if they come from the same client.
-            while (layout_it) |layout_node| : (layout_it = layout_node.next) {
-                if (mem.eql(u8, namespace, layout_node.data.namespace) and
-                    client != layout_node.data.layout_v3.getClient()) return true;
-            }
-        }
-    }
-    return false;
-}
-
-/// This exists to handle layouts that have been rendered inert (due to the
-/// namespace already being in use) until the client destroys them.
-fn handleRequestInert(layout_v3: *river.LayoutV3, request: river.LayoutV3.Request, _: ?*anyopaque) void {
-    if (request == .destroy) layout_v3.destroy();
-}
-
-/// Send a layout demand to the client
-pub fn startLayoutDemand(layout: *Layout, views: u32) void {
-    log.debug(
-        "starting layout demand '{s}' on output '{s}'",
-        .{ layout.namespace, layout.output.wlr_output.name },
-    );
-
-    assert(layout.output.inflight.layout_demand == null);
-    layout.output.inflight.layout_demand = LayoutDemand.init(layout, views) catch {
-        log.err("failed starting layout demand", .{});
-        return;
-    };
-
-    layout.layout_v3.sendLayoutDemand(
-        views,
-        @intCast(layout.output.usable_box.width),
-        @intCast(layout.output.usable_box.height),
-        layout.output.pending.tags,
-        layout.output.inflight.layout_demand.?.serial,
-    );
-
-    server.root.inflight_layout_demands += 1;
-}
-
-fn handleRequest(layout_v3: *river.LayoutV3, request: river.LayoutV3.Request, layout: *Layout) void {
-    switch (request) {
-        .destroy => layout_v3.destroy(),
-
-        // We receive this event when the client wants to push a view dimension proposal
-        // to the layout demand matching the serial.
-        .push_view_dimensions => |req| {
-            log.debug(
-                "layout '{s}' on output '{s}' pushed view dimensions: {} {} {} {}",
-                .{ layout.namespace, layout.output.wlr_output.name, req.x, req.y, req.width, req.height },
-            );
-
-            if (layout.output.inflight.layout_demand) |*layout_demand| {
-                // We can't raise a protocol error when the serial is old/wrong
-                // because we do not keep track of old serials server-side.
-                // Therefore, simply ignore requests with old/wrong serials.
-                if (layout_demand.serial != req.serial) return;
-                layout_demand.pushViewDimensions(
-                    req.x,
-                    req.y,
-                    @min(math.maxInt(u31), req.width),
-                    @min(math.maxInt(u31), req.height),
-                );
-            }
-        },
-
-        // We receive this event when the client wants to mark the proposed layout
-        // of the layout demand matching the serial as done.
-        .commit => |req| {
-            log.debug(
-                "layout '{s}' on output '{s}' commited",
-                .{ layout.namespace, layout.output.wlr_output.name },
-            );
-
-            if (layout.output.inflight.layout_demand) |*layout_demand| {
-                // We can't raise a protocol error when the serial is old/wrong
-                // because we do not keep track of old serials server-side.
-                // Therefore, simply ignore requests with old/wrong serials.
-                if (layout_demand.serial == req.serial) layout_demand.apply(layout);
-            }
-
-            const new_name = mem.sliceTo(req.layout_name, 0);
-            if (layout.output.layout_name == null or
-                !mem.eql(u8, layout.output.layout_name.?, new_name))
-            {
-                const owned = util.gpa.dupeZ(u8, new_name) catch {
-                    log.err("out of memory", .{});
-                    return;
-                };
-                if (layout.output.layout_name) |name| util.gpa.free(name);
-                layout.output.layout_name = owned;
-            }
-        },
-    }
-}
-
-fn handleDestroy(_: *river.LayoutV3, layout: *Layout) void {
-    layout.destroy();
-}
-
-pub fn destroy(layout: *Layout) void {
-    log.debug(
-        "destroying layout '{s}' on output '{s}'",
-        .{ layout.namespace, layout.output.wlr_output.name },
-    );
-
-    // Remove layout from the list
-    const node: *std.TailQueue(Layout).Node = @fieldParentPtr("data", layout);
-    layout.output.layouts.remove(node);
-
-    // If we are the currently active layout of an output, clean up.
-    if (layout.output.layout == layout) {
-        layout.output.layout = null;
-        if (layout.output.inflight.layout_demand) |*layout_demand| {
-            layout_demand.deinit();
-            layout.output.inflight.layout_demand = null;
-            server.root.notifyLayoutDemandDone();
-        }
-
-        if (layout.output.layout_name) |name| {
-            util.gpa.free(name);
-            layout.output.layout_name = null;
-        }
-    }
-
-    layout.layout_v3.setHandler(?*anyopaque, handleRequestInert, null, null);
-
-    util.gpa.free(layout.namespace);
-    util.gpa.destroy(node);
-}
diff --git a/river/LayoutDemand.zig b/river/LayoutDemand.zig
deleted file mode 100644
index 920d502..0000000
--- a/river/LayoutDemand.zig
+++ /dev/null
@@ -1,157 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020 - 2021 The River Developers
-//
-// 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, version 3.
-//
-// 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 LayoutDemand = @This();
-
-const std = @import("std");
-const assert = std.debug.assert;
-const wlr = @import("wlroots");
-const wayland = @import("wayland");
-const wl = wayland.server.wl;
-
-const server = &@import("main.zig").server;
-const util = @import("util.zig");
-
-const Layout = @import("Layout.zig");
-const Server = @import("Server.zig");
-const Output = @import("Output.zig");
-const View = @import("View.zig");
-
-const log = std.log.scoped(.layout);
-
-const Error = error{ViewDimensionMismatch};
-
-const timeout_ms = 100;
-
-serial: u32,
-/// Number of views for which dimensions have not been pushed.
-/// This will go negative if the client pushes too many dimensions.
-views: i32,
-/// Proposed view dimensions
-view_boxen: []wlr.Box,
-timeout_timer: *wl.EventSource,
-
-pub fn init(layout: *Layout, views: u32) !LayoutDemand {
-    const event_loop = server.wl_server.getEventLoop();
-    const timeout_timer = try event_loop.addTimer(*Layout, handleTimeout, layout);
-    errdefer timeout_timer.remove();
-    try timeout_timer.timerUpdate(timeout_ms);
-
-    return LayoutDemand{
-        .serial = server.wl_server.nextSerial(),
-        .views = @intCast(views),
-        .view_boxen = try util.gpa.alloc(wlr.Box, views),
-        .timeout_timer = timeout_timer,
-    };
-}
-
-pub fn deinit(demand: *const LayoutDemand) void {
-    demand.timeout_timer.remove();
-    util.gpa.free(demand.view_boxen);
-}
-
-/// Destroy the LayoutDemand on timeout.
-/// All further responses to the event will simply be ignored.
-fn handleTimeout(layout: *Layout) c_int {
-    log.info(
-        "layout demand for layout '{s}' on output '{s}' timed out",
-        .{ layout.namespace, layout.output.wlr_output.name },
-    );
-    layout.output.inflight.layout_demand.?.deinit();
-    layout.output.inflight.layout_demand = null;
-
-    server.root.notifyLayoutDemandDone();
-
-    return 0;
-}
-
-/// Push a set of proposed view dimensions and position to the list
-pub fn pushViewDimensions(demand: *LayoutDemand, x: i32, y: i32, width: u31, height: u31) void {
-    // The client pushed too many dimensions
-    if (demand.views <= 0) {
-        demand.views -= 1;
-        return;
-    }
-
-    demand.view_boxen[demand.view_boxen.len - @as(usize, @intCast(demand.views))] = .{
-        .x = x,
-        .y = y,
-        .width = width,
-        .height = height,
-    };
-
-    demand.views -= 1;
-}
-
-/// Apply the proposed layout to the output
-pub fn apply(demand: *LayoutDemand, layout: *Layout) void {
-    // Note: output.layout may not be equal to layout here if the layout
-    // namespace changes while a transactions is inflight.
-    const output = layout.output;
-
-    // Whether the layout demand succeeds or fails, we are done with it and
-    // need to clean up
-    defer {
-        output.inflight.layout_demand.?.deinit();
-        output.inflight.layout_demand = null;
-        server.root.notifyLayoutDemandDone();
-    }
-
-    // Check that the number of proposed dimensions is correct.
-    if (demand.views != 0) {
-        log.err(
-            "proposed dimension count ({}) does not match view count ({}), aborting layout demand",
-            .{ -demand.views + @as(i32, @intCast(demand.view_boxen.len)), demand.view_boxen.len },
-        );
-        layout.layout_v3.postError(
-            .count_mismatch,
-            "number of proposed view dimensions must match number of views",
-        );
-        return;
-    }
-
-    // Apply proposed layout to the inflight state of the target views
-    var it = output.inflight.wm_stack.iterator(.forward);
-    var i: u32 = 0;
-    while (it.next()) |view| {
-        if (!view.inflight.float and !view.inflight.fullscreen and
-            view.inflight.tags & output.inflight.tags != 0)
-        {
-            const proposed = &demand.view_boxen[i];
-
-            // Here we apply the offset to align the coords with the origin of the
-            // usable area and shrink the dimensions to accommodate the border size.
-            const border_width = if (view.inflight.ssd) server.config.border_width else 0;
-            view.inflight.box = .{
-                .x = proposed.x + output.usable_box.x + border_width,
-                .y = proposed.y + output.usable_box.y + border_width,
-                .width = proposed.width - 2 * border_width,
-                .height = proposed.height - 2 * border_width,
-            };
-
-            view.applyConstraints(&view.inflight.box);
-
-            // State flowing "backwards" like this is pretty ugly, but I don't
-            // see a better way to sync this up right now.
-            if (!view.pending.float and !view.pending.fullscreen) {
-                view.pending.box = view.inflight.box;
-            }
-
-            i += 1;
-        }
-    }
-    assert(i == demand.view_boxen.len);
-}
diff --git a/river/LayoutManager.zig b/river/LayoutManager.zig
deleted file mode 100644
index d994d28..0000000
--- a/river/LayoutManager.zig
+++ /dev/null
@@ -1,88 +0,0 @@
-// This file is part of river, a dynamic tiling wayland compositor.
-//
-// Copyright 2020 - 2021 The River Developers
-//
-// 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, version 3.
-//
-// 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 LayoutManager = @This();
-
-const std = @import("std");
-const mem = std.mem;
-const wlr = @import("wlroots");
-const wayland = @import("wayland");
-const wl = wayland.server.wl;
-const river = wayland.server.river;
-
-const server = &@import("main.zig").server;
-const util = @import("util.zig");
-
-const Layout = @import("Layout.zig");
-const Server = @import("Server.zig");
-const Output = @import("Output.zig");
-
-const log = std.log.scoped(.layout);
-
-global: *wl.Global,
-server_destroy: wl.Listener(*wl.Server) = wl.Listener(*wl.Server).init(handleServerDestroy),
-
-pub fn init(layout_manager: *LayoutManager) !void {
-    layout_manager.* = .{
-        .global = try wl.Global.create(server.wl_server, river.LayoutManagerV3, 2, ?*anyopaque, null, bind),
-    };
-
-    server.wl_server.addDestroyListener(&layout_manager.server_destroy);
-}
-
-fn handleServerDestroy(listener: *wl.Listener(*wl.Server), _: *wl.Server) void {
-    const layout_manager: *LayoutManager = @fieldParentPtr("server_destroy", listener);
-    layout_manager.global.destroy();
-}
-
-fn bind(client: *wl.Client, _: ?*anyopaque, version: u32, id: u32) void {
-    const layout_manager_v3 = river.LayoutManagerV3.create(client, version, id) catch {
-        client.postNoMemory();
-        log.err("out of memory", .{});
-        return;
-    };
-    layout_manager_v3.setHandler(?*anyopaque, handleRequest, null, null);
-}
-
-fn handleRequest(
-    layout_manager_v3: *river.LayoutManagerV3,
-    request: river.LayoutManagerV3.Request,
-    _: ?*anyopaque,
-) void {
-    switch (request) {
-        .destroy => layout_manager_v3.destroy(),
-
-        .get_layout => |req| {
-            // Ignore if the output is inert
-            const wlr_output = wlr.Output.fromWlOutput(req.output) orelse return;
-            const output: *Output = @ptrFromInt(wlr_output.data);
-
-            log.debug("bind layout '{s}' on output '{s}'", .{ req.namespace, output.wlr_output.name });
-
-            Layout.create(
-                layout_manager_v3.getClient(),
-                layout_manager_v3.getVersion(),
-                req.id,
-                output,
-                mem.sliceTo(req.namespace, 0),
-            ) catch {
-                layout_manager_v3.getClient().postNoMemory();
-                log.err("out of memory", .{});
-                return;
-            };
-        },
-    }
-}
diff --git a/river/Output.zig b/river/Output.zig
index d391314..e1382ca 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -31,8 +31,6 @@ const server = &@import("main.zig").server;
 const util = @import("util.zig");
 
 const LayerSurface = @import("LayerSurface.zig");
-const Layout = @import("Layout.zig");
-const LayoutDemand = @import("LayoutDemand.zig");
 const LockSurface = @import("LockSurface.zig");
 const SceneNodeData = @import("SceneNodeData.zig");
 const View = @import("View.zig");
@@ -150,7 +148,6 @@ inflight: struct {
     wm_stack: wl.list.Head(View, .inflight_wm_stack_link),
     /// The view to be made fullscreen, if any.
     fullscreen: ?*View = null,
-    layout_demand: ?LayoutDemand = null,
 },
 
 /// The current state represented by the scene graph.
@@ -169,28 +166,6 @@ previous_tags: u32 = 1 << 0,
 
 attach_mode: ?Config.AttachMode = null,
 
-/// List of all layouts
-layouts: std.TailQueue(Layout) = .{},
-
-/// The current layout namespace of the output. If null,
-/// config.default_layout_namespace should be used instead.
-/// Call handleLayoutNamespaceChange() after setting this.
-layout_namespace: ?[]const u8 = null,
-
-/// The last set layout name.
-layout_name: ?[:0]const u8 = null,
-
-/// Active layout, or null if views are un-arranged.
-///
-/// If null, views which are manually moved or resized (with the pointer or
-/// or command) will not be automatically set to floating. Everything is
-/// already floating, so this would be an unexpected change of a views state
-/// the user will only notice once a layout affects the views. So instead we
-/// "snap back" all manually moved views the next time a layout is active.
-/// This is similar to dwms behvaviour. Note that this of course does not
-/// affect already floating views.
-layout: ?*Layout = null,
-
 destroy: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleDestroy),
 request_state: wl.Listener(*wlr.Output.event.RequestState) = wl.Listener(*wlr.Output.event.RequestState).init(handleRequestState),
 frame: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleFrame),
@@ -407,8 +382,6 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
     assert(output.pending.wm_stack.empty());
     assert(output.inflight.focus_stack.empty());
     assert(output.inflight.wm_stack.empty());
-    assert(output.inflight.layout_demand == null);
-    assert(output.layouts.len == 0);
 
     output.all_link.remove();
 
@@ -419,8 +392,6 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
 
     output.tree.node.destroy();
 
-    if (output.layout_namespace) |namespace| util.gpa.free(namespace);
-
     output.wlr_output.data = 0;
 
     util.gpa.destroy(output);
@@ -627,20 +598,6 @@ fn setTitle(output: Output) void {
     }
 }
 
-pub fn handleLayoutNamespaceChange(output: *Output) void {
-    // The user changed the layout namespace of this output. Try to find a
-    // matching layout.
-    var it = output.layouts.first;
-    output.layout = while (it) |node| : (it = node.next) {
-        if (mem.eql(u8, output.layoutNamespace(), node.data.namespace)) break &node.data;
-    } else null;
-    server.root.applyPending();
-}
-
-pub fn layoutNamespace(output: Output) []const u8 {
-    return output.layout_namespace orelse server.config.default_layout_namespace;
-}
-
 pub fn attachMode(output: Output) Config.AttachMode {
     return output.attach_mode orelse server.config.default_attach_mode;
 }
diff --git a/river/Root.zig b/river/Root.zig
index 4f9c5ff..76af321 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -107,8 +107,6 @@ all_outputs: wl.list.Head(Output, .all_link),
 /// it's turned off by dpms)
 active_outputs: wl.list.Head(Output, .active_link),
 
-/// Number of layout demands before sending configures to clients.
-inflight_layout_demands: u32 = 0,
 /// Number of inflight configures sent in the current transaction.
 inflight_configures: u32 = 0,
 transaction_timeout: *wl.EventSource,
@@ -338,13 +336,6 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
         }
     }
 
-    if (output.inflight.layout_demand) |layout_demand| {
-        layout_demand.deinit();
-        output.inflight.layout_demand = null;
-        root.notifyLayoutDemandDone();
-    }
-    while (output.layouts.first) |node| node.data.destroy();
-
     // We must call reconfigureDevices here to unmap devices that might be mapped to this output
     // in order to prevent a segfault in wlroots.
     server.input_manager.reconfigureDevices();
@@ -430,7 +421,7 @@ pub fn applyPending(root: *Root) void {
     }
 
     // If there is already a transaction inflight, wait until it completes.
-    if (root.inflight_layout_demands > 0 or root.inflight_configures > 0) {
+    if (root.inflight_configures > 0) {
         root.pending_state_dirty = true;
         return;
     }
@@ -508,33 +499,6 @@ pub fn applyPending(root: *Root) void {
         }
     }
 
-    {
-        // Layout demands can't be sent until after the inflight stacks of
-        // all outputs have been updated.
-        var output_it = root.active_outputs.iterator(.forward);
-        while (output_it.next()) |output| {
-            assert(output.inflight.layout_demand == null);
-            if (output.layout) |layout| {
-                var layout_count: u32 = 0;
-                {
-                    var it = output.inflight.wm_stack.iterator(.forward);
-                    while (it.next()) |view| {
-                        if (!view.inflight.float and !view.inflight.fullscreen and
-                            view.inflight.tags & output.inflight.tags != 0)
-                        {
-                            layout_count += 1;
-                        }
-                    }
-                }
-
-                if (layout_count > 0) {
-                    // TODO don't do this if the count has not changed
-                    layout.startLayoutDemand(layout_count);
-                }
-            }
-        }
-    }
-
     {
         var it = server.input_manager.seats.first;
         while (it) |node| : (it = node.next) {
@@ -545,7 +509,6 @@ pub fn applyPending(root: *Root) void {
                 inline .move, .resize => |data| {
                     if (data.view.inflight.output == null or
                         data.view.inflight.tags & data.view.inflight.output.?.inflight.tags == 0 or
-                        (!data.view.inflight.float and data.view.inflight.output.?.layout != null) or
                         data.view.inflight.fullscreen)
                     {
                         cursor.mode = .passthrough;
@@ -559,23 +522,10 @@ pub fn applyPending(root: *Root) void {
         }
     }
 
-    if (root.inflight_layout_demands == 0) {
-        root.sendConfigures();
-    }
-}
-
-/// This function is used to inform the transaction system that a layout demand
-/// has either been completed or timed out. If it was the last pending layout
-/// demand in the current sequence, a transaction is started.
-pub fn notifyLayoutDemandDone(root: *Root) void {
-    root.inflight_layout_demands -= 1;
-    if (root.inflight_layout_demands == 0) {
-        root.sendConfigures();
-    }
+    root.sendConfigures();
 }
 
 fn sendConfigures(root: *Root) void {
-    assert(root.inflight_layout_demands == 0);
     assert(root.inflight_configures == 0);
 
     // Iterate over all views of all outputs
@@ -614,8 +564,6 @@ fn sendConfigures(root: *Root) void {
 }
 
 fn handleTransactionTimeout(root: *Root) c_int {
-    assert(root.inflight_layout_demands == 0);
-
     std.log.scoped(.transaction).err("timeout occurred, some imperfect frames may be shown", .{});
 
     root.inflight_configures = 0;
@@ -625,8 +573,6 @@ fn handleTransactionTimeout(root: *Root) c_int {
 }
 
 pub fn notifyConfigured(root: *Root) void {
-    assert(root.inflight_layout_demands == 0);
-
     root.inflight_configures -= 1;
     if (root.inflight_configures == 0) {
         // Disarm the timer, as we didn't timeout
@@ -640,7 +586,6 @@ pub fn notifyConfigured(root: *Root) void {
 /// layout. Should only be called after all clients have configured for
 /// the new layout. If called early imperfect frames may be drawn.
 fn commitTransaction(root: *Root) void {
-    assert(root.inflight_layout_demands == 0);
     assert(root.inflight_configures == 0);
 
     std.log.scoped(.transaction).debug("commiting transaction", .{});
@@ -675,8 +620,6 @@ fn commitTransaction(root: *Root) void {
             {
                 if (view.inflight.float) {
                     view.tree.node.reparent(output.layers.float);
-                } else {
-                    view.tree.node.reparent(output.layers.layout);
                 }
                 view.popup_tree.node.reparent(output.layers.popups);
             }
@@ -684,8 +627,6 @@ fn commitTransaction(root: *Root) void {
             if (view.current.float != view.inflight.float) {
                 if (view.inflight.float) {
                     view.tree.node.reparent(output.layers.float);
-                } else {
-                    view.tree.node.reparent(output.layers.layout);
                 }
             }
 
diff --git a/river/Server.zig b/river/Server.zig
index f0d626e..a9acf82 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -30,7 +30,6 @@ const Config = @import("Config.zig");
 const IdleInhibitManager = @import("IdleInhibitManager.zig");
 const InputManager = @import("InputManager.zig");
 const LayerSurface = @import("LayerSurface.zig");
-const LayoutManager = @import("LayoutManager.zig");
 const LockManager = @import("LockManager.zig");
 const Output = @import("Output.zig");
 const Root = @import("Root.zig");
@@ -85,7 +84,6 @@ foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
 input_manager: InputManager,
 root: Root,
 config: Config,
-layout_manager: LayoutManager,
 idle_inhibit_manager: IdleInhibitManager,
 lock_manager: LockManager,
 
@@ -157,7 +155,6 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
 
         .root = undefined,
         .input_manager = undefined,
-        .layout_manager = undefined,
         .idle_inhibit_manager = undefined,
         .lock_manager = undefined,
     };
@@ -179,7 +176,6 @@ pub fn init(server: *Server, runtime_xwayland: bool) !void {
 
     try server.root.init();
     try server.input_manager.init();
-    try server.layout_manager.init();
     try server.idle_inhibit_manager.init();
     try server.lock_manager.init();
 
@@ -315,7 +311,6 @@ fn blocklist(server: *Server, global: *const wl.Global) bool {
         global == server.screencopy_manager.global or
         global == server.export_dmabuf_manager.global or
         global == server.data_control_manager.global or
-        global == server.layout_manager.global or
         global == server.root.output_manager.global or
         global == server.root.power_manager.global or
         global == server.root.gamma_control_manager.global or
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index deca0b0..2e7695e 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -125,8 +125,8 @@ pub fn configure(toplevel: *XdgToplevel) bool {
     const inflight = &toplevel.view.inflight;
     const current = &toplevel.view.current;
 
-    const inflight_float = inflight.float or (inflight.output != null and inflight.output.?.layout == null);
-    const current_float = current.float or (current.output != null and current.output.?.layout == null);
+    const inflight_float = inflight.float;
+    const current_float = current.float;
 
     // We avoid a special case for newly mapped views which we have not yet
     // configured by setting the current width/height to the initial width/height
@@ -342,14 +342,13 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
 
             const size_changed = toplevel.geometry.width != old_geometry.width or
                 toplevel.geometry.height != old_geometry.height;
-            const no_layout = view.current.output != null and view.current.output.?.layout == null;
 
             if (size_changed) {
                 log.debug(
                     "client initiated size change: {}x{} -> {}x{}",
                     .{ old_geometry.width, old_geometry.height, toplevel.geometry.width, toplevel.geometry.height },
                 );
-                if (!(view.current.float or no_layout) and !view.current.fullscreen) {
+                if (!view.current.float and !view.current.fullscreen) {
                     // It seems that a disappointingly high number of clients have a buggy
                     // response to configure events. They ack the configure immediately but then
                     // proceed to make one or more wl_surface.commit requests with the old size
@@ -431,9 +430,7 @@ fn handleRequestMove(
     if (view.current.output) |current_output| {
         if (view.current.tags & current_output.current.tags == 0) return;
     }
-    if (view.pending.output) |pending_output| {
-        if (!(view.pending.float or pending_output.layout == null)) return;
-    }
+    if (!view.pending.float) return;
 
     // Moving windows with touch or tablet tool is not yet supported.
     if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) {
@@ -454,9 +451,7 @@ fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), ev
     if (view.current.output) |current_output| {
         if (view.current.tags & current_output.current.tags == 0) return;
     }
-    if (view.pending.output) |pending_output| {
-        if (!(view.pending.float or pending_output.layout == null)) return;
-    }
+    if (!view.pending.float) return;
 
     // Resizing windows with touch or tablet tool is not yet supported.
     if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) {