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

commitc4b79e180bf4bed419cb41914ad02ab0dc8a0a1b
parentc7e74b2f0a
authorIsaac Freund <[email protected]>
date2024-06-28 15:24
Output: remove wm_stack

 river/Cursor.zig                |  29 +-----
 river/ForeignToplevelHandle.zig |   8 +-
 river/InputPopup.zig            |   2 +-
 river/Output.zig                |  35 +------
 river/Root.zig                  | 209 ++++++++--------------------------------
 river/View.zig                  | 101 +++----------------
 river/XdgPopup.zig              |   2 +-
 river/XwaylandView.zig          |  20 ++--
 8 files changed, 66 insertions(+), 340 deletions(-)

diff --git a/river/Cursor.zig b/river/Cursor.zig
index 6e1778c..10a3327 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -704,9 +704,6 @@ fn handleRequestSetCursor(
 }
 
 pub fn startMove(cursor: *Cursor, view: *View) void {
-    // Guard against assertion in enterMode()
-    if (view.current.output == null) return;
-
     if (cursor.constraint) |constraint| {
         if (constraint.state == .active) constraint.deactivate();
     }
@@ -720,9 +717,6 @@ pub fn startMove(cursor: *Cursor, view: *View) void {
 }
 
 pub fn startResize(cursor: *Cursor, view: *View, proposed_edges: ?wlr.Edges) void {
-    // Guard against assertions in computeEdges() and enterMode()
-    if (view.current.output == null) return;
-
     if (cursor.constraint) |constraint| {
         if (constraint.state == .active) constraint.deactivate();
     }
@@ -759,11 +753,8 @@ fn computeEdges(cursor: *const Cursor, view: *const View) wlr.Edges {
     const min_handle_size = 20;
     const box = &view.current.box;
 
-    var output_box: wlr.Box = undefined;
-    server.root.output_layout.getBox(view.current.output.?.wlr_output, &output_box);
-
-    const sx = @as(i32, @intFromFloat(cursor.wlr_cursor.x)) - output_box.x - box.x;
-    const sy = @as(i32, @intFromFloat(cursor.wlr_cursor.y)) - output_box.y - box.y;
+    const sx = @as(i32, @intFromFloat(cursor.wlr_cursor.x)) - box.x;
+    const sy = @as(i32, @intFromFloat(cursor.wlr_cursor.y)) - box.y;
 
     var edges: wlr.Edges = .{};
 
@@ -878,19 +869,9 @@ fn processMotion(cursor: *Cursor, device: *wlr.InputDevice, time: u32, delta_x:
             // based on the dimensions actually committed by the client.
             const border_width = if (data.view.pending.ssd) server.config.border_width else 0;
 
-            const output = data.view.current.output orelse {
-                data.view.pending.resizing = false;
-
-                cursor.mode = .passthrough;
-                cursor.passthrough(time);
-
-                server.root.applyPending();
-                return;
-            };
-
-            var output_width: i32 = undefined;
-            var output_height: i32 = undefined;
-            output.wlr_output.effectiveResolution(&output_width, &output_height);
+            // TODO
+            const output_width: i32 = 1920;
+            const output_height: i32 = 1080;
 
             const constraints = &data.view.constraints;
             const box = &data.view.pending.box;
diff --git a/river/ForeignToplevelHandle.zig b/river/ForeignToplevelHandle.zig
index a49c8a1..97a1c90 100644
--- a/river/ForeignToplevelHandle.zig
+++ b/river/ForeignToplevelHandle.zig
@@ -71,14 +71,8 @@ pub fn update(handle: *ForeignToplevelHandle) void {
 
     const wlr_handle = handle.wlr_handle orelse return;
 
-    if (view.inflight.output != view.current.output) {
-        if (view.current.output) |output| wlr_handle.outputLeave(output.wlr_output);
-        if (view.inflight.output) |output| wlr_handle.outputEnter(output.wlr_output);
-    }
-
     wlr_handle.setActivated(view.inflight.focus != 0);
-    wlr_handle.setFullscreen(view.inflight.output != null and
-        view.inflight.output.?.inflight.fullscreen == view);
+    wlr_handle.setFullscreen(view.inflight.fullscreen);
 }
 
 /// Only honors the request if the view is already visible on the seat's
diff --git a/river/InputPopup.zig b/river/InputPopup.zig
index 0e35753..6503ddf 100644
--- a/river/InputPopup.zig
+++ b/river/InputPopup.zig
@@ -108,7 +108,7 @@ pub fn update(input_popup: *InputPopup) void {
     const focused = SceneNodeData.fromSurface(focused_surface) orelse return;
 
     const output = switch (focused.data) {
-        .view => |view| view.current.output orelse return,
+        .view => @panic("TODO"),
         .layer_surface => |layer_surface| layer_surface.output,
         .lock_surface => |lock_surface| lock_surface.getOutput(),
         // Xwayland doesn't use the text-input protocol
diff --git a/river/Output.zig b/river/Output.zig
index 4072609..d8994bd 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -38,12 +38,6 @@ const Config = @import("Config.zig");
 
 const log = std.log.scoped(.output);
 
-pub const PendingState = struct {
-    /// The stack of views acted upon by window management commands such
-    /// as focus-view, zoom, etc.
-    wm_stack: wl.list.Head(View, .pending_wm_stack_link),
-};
-
 wlr_output: *wlr.Output,
 scene_output: *wlr.SceneOutput,
 
@@ -108,30 +102,15 @@ lock_render_state: enum {
 /// This request is handled while rendering the next frame in handleFrame().
 gamma_dirty: bool = false,
 
-/// The state of the output that is directly acted upon/modified through user input.
-///
-/// Pending state will be copied to the inflight state and communicated to clients
-/// to be applied as a single atomic transaction across all clients as soon as any
-/// in progress transaction has been completed.
-///
-/// Any time pending state is modified Root.applyPending() must be called
-/// before yielding back to the event loop.
-pending: PendingState,
-
 /// The state most recently sent to the layout generator and clients.
 /// This state is immutable until all clients have replied and the transaction
 /// is completed, at which point this inflight state is copied to current.
 inflight: struct {
-    /// See pending.wm_stack
-    wm_stack: wl.list.Head(View, .inflight_wm_stack_link),
     /// The view to be made fullscreen, if any.
     fullscreen: ?*View = null,
-},
+} = .{},
 
 /// The current state represented by the scene graph.
-/// There is no need to have a current wm_stack copy as this
-/// information is transferred from the inflight state to the scene graph
-/// as an inflight transaction completes.
 current: struct {
     /// The currently fullscreen view, if any.
     fullscreen: ?*View = null,
@@ -221,12 +200,6 @@ pub fn create(wlr_output: *wlr.Output) !void {
             .overlay = try normal_content.createSceneTree(),
             .popups = try normal_content.createSceneTree(),
         },
-        .pending = .{
-            .wm_stack = undefined,
-        },
-        .inflight = .{
-            .wm_stack = undefined,
-        },
         .usable_box = .{
             .x = 0,
             .y = 0,
@@ -236,9 +209,6 @@ pub fn create(wlr_output: *wlr.Output) !void {
     };
     wlr_output.data = @intFromPtr(output);
 
-    output.pending.wm_stack.init();
-    output.inflight.wm_stack.init();
-
     _ = try output.layers.fullscreen.createSceneRect(width, height, &[_]f32{ 0, 0, 0, 1.0 });
     output.layers.fullscreen.node.setEnabled(false);
 
@@ -344,9 +314,6 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
     // Remove the destroyed output from root if it wasn't already removed
     server.root.deactivateOutput(output);
 
-    assert(output.pending.wm_stack.empty());
-    assert(output.inflight.wm_stack.empty());
-
     output.all_link.remove();
 
     output.destroy.link.remove();
diff --git a/river/Root.zig b/river/Root.zig
index 82e9839..22bd4f3 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -52,28 +52,30 @@ layers: struct {
     override_redirect: if (build_options.xwayland) *wlr.SceneTree else void,
 },
 
+wm: struct {
+    pending: struct {
+        render_list: wl.list.Head(View, .pending_render_list_link),
+    },
+
+    inflight: struct {
+        render_list: wl.list.Head(View, .inflight_render_list_link),
+    },
+},
+
 /// This is kind of like an imaginary output where views start and end their life.
 hidden: struct {
     /// This tree is always disabled.
     tree: *wlr.SceneTree,
 
     pending: struct {
-        wm_stack: wl.list.Head(View, .pending_wm_stack_link),
+        render_list: wl.list.Head(View, .pending_render_list_link),
     },
 
     inflight: struct {
-        wm_stack: wl.list.Head(View, .inflight_wm_stack_link),
+        render_list: wl.list.Head(View, .inflight_render_list_link),
     },
 },
 
-/// This is used to store views when no actual outputs are available.
-/// This must be separate from hidden to ensure we don't mix views that are
-/// in the process of being mapped/unmapped with the mapped views in these lists.
-/// There is no need for inflight lists, instead the inflight links of views are
-/// remove()'d from their current list and init()'d so they may be remove()'d again
-/// when an output becomes available and they are moved to the output's inflight lists.
-fallback_pending: Output.PendingState,
-
 views: wl.list.Head(View, .link),
 
 new_output: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleNewOutput),
@@ -139,18 +141,23 @@ pub fn init(root: *Root) !void {
             .outputs = outputs,
             .override_redirect = override_redirect,
         },
+        .wm = .{
+            .pending = .{
+                .render_list = undefined,
+            },
+            .inflight = .{
+                .render_list = undefined,
+            },
+        },
         .hidden = .{
             .tree = hidden_tree,
             .pending = .{
-                .wm_stack = undefined,
+                .render_list = undefined,
             },
             .inflight = .{
-                .wm_stack = undefined,
+                .render_list = undefined,
             },
         },
-        .fallback_pending = .{
-            .wm_stack = undefined,
-        },
         .views = undefined,
         .output_layout = output_layout,
         .all_outputs = undefined,
@@ -163,10 +170,10 @@ pub fn init(root: *Root) !void {
         .gamma_control_manager = try wlr.GammaControlManagerV1.create(server.wl_server),
         .transaction_timeout = transaction_timeout,
     };
-    root.hidden.pending.wm_stack.init();
-    root.hidden.inflight.wm_stack.init();
-
-    root.fallback_pending.wm_stack.init();
+    root.wm.pending.render_list.init();
+    root.wm.inflight.render_list.init();
+    root.hidden.pending.render_list.init();
+    root.hidden.inflight.render_list.init();
 
     root.views.init();
     root.all_outputs.init();
@@ -259,47 +266,6 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
     output.active_link.remove();
     output.active_link.init();
 
-    {
-        var it = output.inflight.wm_stack.safeIterator(.forward);
-        while (it.next()) |view| {
-            view.inflight.output = null;
-            view.current.output = null;
-
-            view.tree.node.reparent(root.hidden.tree);
-            view.popup_tree.node.reparent(root.hidden.tree);
-
-            view.inflight_wm_stack_link.remove();
-            view.inflight_wm_stack_link.init();
-
-            if (view.inflight_transaction) {
-                view.commitTransaction();
-            }
-
-            // Store outputs connector name so that views can be moved back to
-            // reconnecting outputs. Skip if there is already a connector name
-            // stored to better handle the case of multiple outputs being
-            // removed sequentially.
-            if (view.output_before_evac == null) {
-                const name = mem.span(output.wlr_output.name);
-                view.output_before_evac = util.gpa.dupe(u8, name) catch null;
-            }
-        }
-    }
-    // Use the first output in the list as fallback. If the last real output
-    // is being removed, store the views in Root.fallback_pending.
-    const fallback_output = blk: {
-        var it = root.active_outputs.iterator(.forward);
-        break :blk it.next();
-    };
-    if (fallback_output) |fallback| {
-        var it = output.pending.wm_stack.safeIterator(.reverse);
-        while (it.next()) |view| view.setPendingOutput(fallback);
-    } else {
-        var it = output.pending.wm_stack.iterator(.forward);
-        while (it.next()) |view| view.pending.output = null;
-        root.fallback_pending.wm_stack.prependList(&output.pending.wm_stack);
-    }
-
     // Close all layer surfaces on the removed output
     for ([_]zwlr.LayerShellV1.Layer{ .overlay, .top, .bottom, .background }) |layer| {
         const tree = output.layerSurfaceTree(layer);
@@ -326,8 +292,6 @@ pub fn activateOutput(root: *Root, output: *Output) void {
         while (it.next()) |o| if (o == output) return;
     }
 
-    const first = root.active_outputs.empty();
-
     root.active_outputs.append(output);
 
     // This arranges outputs from left-to-right in the order they appear. The
@@ -341,35 +305,6 @@ pub fn activateOutput(root: *Root, output: *Output) void {
         // possible to handle after updating to 0.17.
         @panic("TODO handle allocation failure here");
     };
-
-    // If we previously had no outputs, move all views to the new output and focus it.
-    if (first) {
-        const log = std.log.scoped(.output_manager);
-        log.debug("moving views from fallback stacks to new output", .{});
-
-        {
-            var it = root.fallback_pending.wm_stack.safeIterator(.reverse);
-            while (it.next()) |view| view.setPendingOutput(output);
-        }
-    } else {
-        // Otherwise check if any views were previously evacuated from an output
-        // with the same (connector-)name and move them back.
-        var it = root.views.iterator(.forward);
-        while (it.next()) |view| {
-            const name = view.output_before_evac orelse continue;
-            if (mem.eql(u8, name, mem.span(output.wlr_output.name))) {
-                if (view.pending.output != output) {
-                    view.setPendingOutput(output);
-                }
-                util.gpa.free(name);
-                view.output_before_evac = null;
-            }
-        }
-    }
-    assert(root.fallback_pending.wm_stack.empty());
-
-    // Enforce map-to-output configuration for the newly active output.
-    server.input_manager.reconfigureDevices();
 }
 
 /// Trigger asynchronous application of pending state for all outputs and views.
@@ -394,45 +329,10 @@ pub fn applyPending(root: *Root) void {
     root.pending_state_dirty = false;
 
     {
-        var it = root.hidden.pending.wm_stack.iterator(.forward);
+        var it = root.hidden.pending.render_list.iterator(.forward);
         while (it.next()) |view| {
-            assert(view.pending.output == null);
-            view.inflight.output = null;
-            view.inflight_wm_stack_link.remove();
-            root.hidden.inflight.wm_stack.append(view);
-        }
-    }
-
-    {
-        var output_it = root.active_outputs.iterator(.forward);
-        while (output_it.next()) |output| {
-            // Iterate the focus stack in order to ensure the currently focused/most
-            // recently focused view that requests fullscreen is given fullscreen.
-            output.inflight.fullscreen = null;
-            {
-                var it = output.pending.wm_stack.iterator(.forward);
-                while (it.next()) |view| {
-                    assert(view.pending.output == output);
-
-                    if (!view.current.fullscreen and view.pending.fullscreen) {
-                        view.post_fullscreen_box = view.pending.box;
-                        view.pending.box = .{ .x = 0, .y = 0, .width = undefined, .height = undefined };
-                        output.wlr_output.effectiveResolution(&view.pending.box.width, &view.pending.box.height);
-                    } else if (view.current.fullscreen and !view.pending.fullscreen) {
-                        view.pending.box = view.post_fullscreen_box;
-                        view.pending.clampToOutput();
-                    }
-
-                    if (output.inflight.fullscreen == null and view.pending.fullscreen) {
-                        output.inflight.fullscreen = view;
-                    }
-
-                    view.inflight_wm_stack_link.remove();
-                    output.inflight.wm_stack.append(view);
-
-                    view.inflight = view.pending;
-                }
-            }
+            view.inflight_render_list_link.remove();
+            root.hidden.inflight.render_list.append(view);
         }
     }
 
@@ -444,9 +344,7 @@ pub fn applyPending(root: *Root) void {
             switch (cursor.mode) {
                 .passthrough, .down => {},
                 inline .move, .resize => |data| {
-                    if (data.view.inflight.output == null or
-                        data.view.inflight.fullscreen)
-                    {
+                    if (data.view.inflight.fullscreen) {
                         cursor.mode = .passthrough;
                         data.view.pending.resizing = false;
                         data.view.inflight.resizing = false;
@@ -464,11 +362,9 @@ pub fn applyPending(root: *Root) void {
 fn sendConfigures(root: *Root) void {
     assert(root.inflight_configures == 0);
 
-    // Iterate over all views of all outputs
-    var output_it = root.active_outputs.iterator(.forward);
-    while (output_it.next()) |output| {
-        var wm_stack_it = output.inflight.wm_stack.iterator(.forward);
-        while (wm_stack_it.next()) |view| {
+    {
+        var it = root.wm.inflight.render_list.iterator(.forward);
+        while (it.next()) |view| {
             assert(!view.inflight_transaction);
             view.inflight_transaction = true;
 
@@ -527,49 +423,20 @@ fn commitTransaction(root: *Root) void {
     std.log.scoped(.transaction).debug("commiting transaction", .{});
 
     {
-        var it = root.hidden.inflight.wm_stack.safeIterator(.forward);
+        var it = root.hidden.inflight.render_list.safeIterator(.forward);
         while (it.next()) |view| {
-            assert(view.inflight.output == null);
-            view.current.output = null;
-
             view.tree.node.reparent(root.hidden.tree);
             view.popup_tree.node.reparent(root.hidden.tree);
         }
     }
 
-    var output_it = root.active_outputs.iterator(.forward);
-    while (output_it.next()) |output| {
-        var wm_stack_it = output.inflight.wm_stack.iterator(.forward);
-        while (wm_stack_it.next()) |view| {
-            assert(view.inflight.output == output);
-
-            if (view.current.output != view.inflight.output or
-                (output.current.fullscreen == view and output.inflight.fullscreen != view))
-            {
-                view.tree.node.reparent(output.layers.wm);
-                view.popup_tree.node.reparent(output.layers.popups);
-            }
-
-            view.tree.node.reparent(output.layers.wm);
-
+    {
+        var it = root.wm.inflight.render_list.iterator(.forward);
+        while (it.next()) |view| {
             view.commitTransaction();
 
             view.tree.node.setEnabled(true);
             view.popup_tree.node.setEnabled(true);
-            if (output.inflight.fullscreen != view) {
-                // TODO this approach for syncing the order will likely cause over-damaging.
-                view.tree.node.lowerToBottom();
-            }
-        }
-
-        if (output.inflight.fullscreen != output.current.fullscreen) {
-            if (output.inflight.fullscreen) |view| {
-                assert(view.inflight.output == output);
-                assert(view.current.output == output);
-                view.tree.node.reparent(output.layers.fullscreen);
-            }
-            output.current.fullscreen = output.inflight.fullscreen;
-            output.layers.fullscreen.node.setEnabled(output.current.fullscreen != null);
         }
     }
 
@@ -580,7 +447,7 @@ fn commitTransaction(root: *Root) void {
 
     {
         // This must be done after updating cursor state in case the view was the target of move/resize.
-        var it = root.hidden.inflight.wm_stack.safeIterator(.forward);
+        var it = root.hidden.inflight.render_list.safeIterator(.forward);
         while (it.next()) |view| {
             view.dropSavedSurfaceTree();
             if (view.destroying) view.destroy(.assert);
diff --git a/river/View.zig b/river/View.zig
index 67d147f..883e059 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -55,11 +55,6 @@ const Impl = union(enum) {
 };
 
 pub const State = struct {
-    /// The output the view is currently assigned to.
-    /// May be null if there are no outputs or for newly created views.
-    /// Must be set using setPendingOutput()
-    output: ?*Output = null,
-
     /// The output-relative coordinates of the view and dimensions requested by river.
     box: wlr.Box = .{ .x = 0, .y = 0, .width = 0, .height = 0 },
 
@@ -76,11 +71,8 @@ pub const State = struct {
     pub fn move(state: *State, delta_x: i32, delta_y: i32) void {
         const border_width = if (state.ssd) server.config.border_width else 0;
 
-        var output_width: i32 = math.maxInt(i32);
-        var output_height: i32 = math.maxInt(i32);
-        if (state.output) |output| {
-            output.wlr_output.effectiveResolution(&output_width, &output_height);
-        }
+        const output_width = math.maxInt(i32);
+        const output_height = math.maxInt(i32);
 
         const max_x = output_width - state.box.width - border_width;
         state.box.x += delta_x;
@@ -142,13 +134,13 @@ destroying: bool = false,
 /// Any time pending state is modified Root.applyPending() must be called
 /// before yielding back to the event loop.
 pending: State = .{},
-pending_wm_stack_link: wl.list.Link,
+pending_render_list_link: wl.list.Link,
 
 /// The state most recently sent to the layout generator and clients.
 /// This state is immutable until all clients have replied and the transaction
 /// is completed, at which point this inflight state is copied to current.
 inflight: State = .{},
-inflight_wm_stack_link: wl.list.Link,
+inflight_render_list_link: wl.list.Link,
 
 /// The current state represented by the scene graph.
 current: State = .{},
@@ -192,13 +184,13 @@ pub fn create(impl: Impl) error{OutOfMemory}!*View {
         },
         .popup_tree = popup_tree,
 
-        .pending_wm_stack_link = undefined,
-        .inflight_wm_stack_link = undefined,
+        .pending_render_list_link = undefined,
+        .inflight_render_list_link = undefined,
     };
 
     server.root.views.prepend(view);
-    server.root.hidden.pending.wm_stack.prepend(view);
-    server.root.hidden.inflight.wm_stack.prepend(view);
+    server.root.hidden.pending.render_list.prepend(view);
+    server.root.hidden.inflight.render_list.prepend(view);
 
     view.tree.node.setEnabled(false);
     view.popup_tree.node.setEnabled(false);
@@ -227,8 +219,8 @@ pub fn destroy(view: *View, when: enum { lazy, assert }) void {
         view.popup_tree.node.destroy();
 
         view.link.remove();
-        view.pending_wm_stack_link.remove();
-        view.inflight_wm_stack_link.remove();
+        view.pending_render_list_link.remove();
+        view.inflight_render_list_link.remove();
 
         if (view.output_before_evac) |name| util.gpa.free(name);
 
@@ -354,31 +346,6 @@ pub fn updateSceneState(view: *View) void {
     view.tree.node.setPosition(box.x, box.y);
     view.popup_tree.node.setPosition(box.x, box.y);
 
-    var output_box: wlr.Box = .{ .x = 0, .y = 0, .width = 0, .height = 0 };
-    if (view.current.output) |output| {
-        output.wlr_output.effectiveResolution(&output_box.width, &output_box.height);
-    }
-
-    {
-        var surface_clip: wlr.Box = output_box;
-
-        // The clip is applied relative to the root node of the subsurface tree.
-        surface_clip.x -= box.x;
-        surface_clip.y -= box.y;
-
-        switch (view.impl) {
-            .toplevel => |toplevel| {
-                surface_clip.x += toplevel.geometry.x;
-                surface_clip.y += toplevel.geometry.y;
-            },
-            .xwayland_view, .none => {},
-        }
-
-        if (!view.surface_tree.children.empty()) {
-            view.surface_tree.node.subsurfaceTreeSetClip(&surface_clip);
-        }
-    }
-
     {
         const config = &server.config;
         const border_width: c_int = config.border_width;
@@ -414,12 +381,6 @@ pub fn updateSceneState(view: *View) void {
         };
 
         for (&view.borders, &border_boxes) |border, *border_box| {
-            border_box.x += box.x;
-            border_box.y += box.y;
-            _ = border_box.intersection(border_box, &output_box);
-            border_box.x -= box.x;
-            border_box.y -= box.y;
-
             border.node.setEnabled(view.current.ssd and !view.current.fullscreen);
             border.node.setPosition(border_box.x, border_box.y);
             border.setSize(border_box.width, border_box.height);
@@ -493,18 +454,6 @@ fn saveSurfaceTreeIter(
     saved.setTransform(buffer.transform);
 }
 
-pub fn setPendingOutput(view: *View, output: *Output) void {
-    view.pending.output = output;
-    view.pending_wm_stack_link.remove();
-
-    output.pending.wm_stack.prepend(view);
-
-    if (view.pending.fullscreen) {
-        view.pending.box = .{ .x = 0, .y = 0, .width = undefined, .height = undefined };
-        output.wlr_output.effectiveResolution(&view.pending.box.width, &view.pending.box.height);
-    }
-}
-
 pub fn close(view: View) void {
     switch (view.impl) {
         .toplevel => |toplevel| toplevel.wlr_toplevel.sendClose(),
@@ -556,31 +505,6 @@ pub fn map(view: *View) !void {
 
     view.foreign_toplevel_handle.map();
 
-    if (true) @panic("TODO");
-    const output = undefined;
-
-    if (output) |o| {
-        // Center the initial pending box on the output
-        view.pending.box.x = @divTrunc(@max(0, o.usable_box.width - view.pending.box.width), 2);
-        view.pending.box.y = @divTrunc(@max(0, o.usable_box.height - view.pending.box.height), 2);
-    }
-
-    if (output) |o| {
-        view.setPendingOutput(o);
-
-        var it = server.input_manager.seats.first;
-        while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(view);
-    } else {
-        log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
-
-        view.pending_wm_stack_link.remove();
-
-        server.root.fallback_pending.wm_stack.prepend(view);
-
-        view.inflight_wm_stack_link.remove();
-        view.inflight_wm_stack_link.init();
-    }
-
     view.float_box = view.pending.box;
 
     server.root.applyPending();
@@ -593,9 +517,8 @@ pub fn unmap(view: *View) void {
     if (!view.saved_surface_tree.node.enabled) view.saveSurfaceTree();
 
     {
-        view.pending.output = null;
-        view.pending_wm_stack_link.remove();
-        server.root.hidden.pending.wm_stack.prepend(view);
+        view.pending_render_list_link.remove();
+        server.root.hidden.pending.render_list.prepend(view);
     }
 
     assert(view.mapped and !view.destroying);
diff --git a/river/XdgPopup.zig b/river/XdgPopup.zig
index 3467210..911f8d4 100644
--- a/river/XdgPopup.zig
+++ b/river/XdgPopup.zig
@@ -96,7 +96,7 @@ fn handleReposition(listener: *wl.Listener(void)) void {
     const xdg_popup: *XdgPopup = @fieldParentPtr("reposition", listener);
 
     const output = switch (SceneNodeData.fromNode(&xdg_popup.root.node).?.data) {
-        .view => |view| view.current.output orelse return,
+        .view => |_| @panic("TODO"),
         .layer_surface => |layer_surface| layer_surface.output,
         else => unreachable,
     };
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index c70d03f..c4e6662 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -86,35 +86,29 @@ pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
 
 /// Always returns false as we do not care about frame perfection for Xwayland views.
 pub fn configure(xwayland_view: XwaylandView) bool {
-    const output = xwayland_view.view.inflight.output orelse return false;
-
-    var output_box: wlr.Box = undefined;
-    server.root.output_layout.getBox(output.wlr_output, &output_box);
-
     const inflight = &xwayland_view.view.inflight;
     const current = &xwayland_view.view.current;
 
-    if (xwayland_view.xwayland_surface.x == inflight.box.x + output_box.x and
-        xwayland_view.xwayland_surface.y == inflight.box.y + output_box.y and
+    if (xwayland_view.xwayland_surface.x == inflight.box.x and
+        xwayland_view.xwayland_surface.y == inflight.box.y and
         xwayland_view.xwayland_surface.width == inflight.box.width and
         xwayland_view.xwayland_surface.height == inflight.box.height and
-        (inflight.focus != 0) == (current.focus != 0) and
-        (output.inflight.fullscreen == xwayland_view.view) ==
-        (current.output != null and current.output.?.current.fullscreen == xwayland_view.view))
+        (inflight.focus != 0) == (current.focus != 0))
+        // TODO fullscreen
     {
         return false;
     }
 
     xwayland_view.xwayland_surface.configure(
-        math.lossyCast(i16, inflight.box.x + output_box.x),
-        math.lossyCast(i16, inflight.box.y + output_box.y),
+        math.lossyCast(i16, inflight.box.x),
+        math.lossyCast(i16, inflight.box.y),
         math.lossyCast(u16, inflight.box.width),
         math.lossyCast(u16, inflight.box.height),
     );
 
     xwayland_view.setActivated(inflight.focus != 0);
 
-    xwayland_view.xwayland_surface.setFullscreen(output.inflight.fullscreen == xwayland_view.view);
+    if (false) xwayland_view.xwayland_surface.setFullscreen();
 
     return false;
 }