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

commita9917926d403d2e8d1d6ce58af5b4310192fb050
parent445e66aed6
authorIsaac Freund <[email protected]>
date2024-06-28 13:59
river: remove focus stack

 protocol/river-window-management-v1.xml |  4 ++
 river/Cursor.zig                        | 14 -------
 river/LayerSurface.zig                  |  3 +-
 river/Output.zig                        | 15 +------
 river/Root.zig                          | 72 ++++++---------------------------
 river/Seat.zig                          | 40 +-----------------
 river/Server.zig                        |  8 ++--
 river/View.zig                          | 20 +--------
 8 files changed, 28 insertions(+), 148 deletions(-)

diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
index fd6ed4b..32a1993 100644
--- a/protocol/river-window-management-v1.xml
+++ b/protocol/river-window-management-v1.xml
@@ -925,6 +925,10 @@
     <description summary="a extension of wl_seat for window management">
       This object extends the wl_seat object with the features necessary for
       window management.
+
+      TODO:
+        - touch input
+        - tablet input
     </description>
 
     <request name="destroy" type="destructor">
diff --git a/river/Cursor.zig b/river/Cursor.zig
index c5ee407..6e1778c 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -373,8 +373,6 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
                 },
             };
         }
-    } else {
-        cursor.updateOutputFocus(cursor.wlr_cursor.x, cursor.wlr_cursor.y);
     }
 
     server.root.applyPending();
@@ -387,7 +385,6 @@ fn updateKeyboardFocus(cursor: Cursor, result: Root.AtResult) void {
             cursor.seat.focus(view);
         },
         .layer_surface => |layer_surface| {
-            cursor.seat.focusOutput(layer_surface.output);
             // If a keyboard inteactive layer surface has been clicked on,
             // give it keyboard focus.
             if (layer_surface.wlr_layer_surface.current.keyboard_interactive != .none) {
@@ -405,15 +402,6 @@ fn updateKeyboardFocus(cursor: Cursor, result: Root.AtResult) void {
     }
 }
 
-/// Focus the output at the given layout coordinates, if any
-/// Requires a call to Root.applyPending()
-fn updateOutputFocus(cursor: Cursor, lx: f64, ly: f64) void {
-    if (server.root.output_layout.outputAt(lx, ly)) |wlr_output| {
-        const output: *Output = @ptrFromInt(wlr_output.data);
-        cursor.seat.focusOutput(output);
-    }
-}
-
 fn handlePinchBegin(
     listener: *wl.Listener(*wlr.Pointer.event.PinchBegin),
     event: *wlr.Pointer.event.PinchBegin,
@@ -519,8 +507,6 @@ fn handleTouchDown(
                 result.sy,
             );
         }
-    } else {
-        cursor.updateOutputFocus(lx, ly);
     }
 
     server.root.applyPending();
diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig
index d20d159..af97e46 100644
--- a/river/LayerSurface.zig
+++ b/river/LayerSurface.zig
@@ -176,7 +176,8 @@ fn handleKeyboardInteractiveExclusive(output: *Output, consider: ?*LayerSurface)
     while (it) |node| : (it = node.next) {
         const seat = &node.data;
 
-        if (seat.focused_output == output) {
+        if (true) @panic("TODO");
+        if (false) {
             if (to_focus) |s| {
                 // If we found a surface on the output that requires focus, grab the focus of all
                 // seats that are focusing that output.
diff --git a/river/Output.zig b/river/Output.zig
index 2e561fe..4072609 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -39,11 +39,6 @@ const Config = @import("Config.zig");
 const log = std.log.scoped(.output);
 
 pub const PendingState = struct {
-    /// The stack of views in focus/rendering order.
-    ///
-    /// This list is used to update the rendering order of nodes in the scene
-    /// graph when the pending state is committed.
-    focus_stack: wl.list.Head(View, .pending_focus_stack_link),
     /// 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),
@@ -127,8 +122,6 @@ pending: PendingState,
 /// 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.focus_stack
-    focus_stack: wl.list.Head(View, .inflight_focus_stack_link),
     /// See pending.wm_stack
     wm_stack: wl.list.Head(View, .inflight_wm_stack_link),
     /// The view to be made fullscreen, if any.
@@ -136,7 +129,7 @@ inflight: struct {
 },
 
 /// The current state represented by the scene graph.
-/// There is no need to have a current focus_stack/wm_stack copy as this
+/// 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 {
@@ -229,11 +222,9 @@ pub fn create(wlr_output: *wlr.Output) !void {
             .popups = try normal_content.createSceneTree(),
         },
         .pending = .{
-            .focus_stack = undefined,
             .wm_stack = undefined,
         },
         .inflight = .{
-            .focus_stack = undefined,
             .wm_stack = undefined,
         },
         .usable_box = .{
@@ -245,9 +236,7 @@ pub fn create(wlr_output: *wlr.Output) !void {
     };
     wlr_output.data = @intFromPtr(output);
 
-    output.pending.focus_stack.init();
     output.pending.wm_stack.init();
-    output.inflight.focus_stack.init();
     output.inflight.wm_stack.init();
 
     _ = try output.layers.fullscreen.createSceneRect(width, height, &[_]f32{ 0, 0, 0, 1.0 });
@@ -355,9 +344,7 @@ 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.focus_stack.empty());
     assert(output.pending.wm_stack.empty());
-    assert(output.inflight.focus_stack.empty());
     assert(output.inflight.wm_stack.empty());
 
     output.all_link.remove();
diff --git a/river/Root.zig b/river/Root.zig
index ad6afa7..82e9839 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -58,12 +58,10 @@ hidden: struct {
     tree: *wlr.SceneTree,
 
     pending: struct {
-        focus_stack: wl.list.Head(View, .pending_focus_stack_link),
         wm_stack: wl.list.Head(View, .pending_wm_stack_link),
     },
 
     inflight: struct {
-        focus_stack: wl.list.Head(View, .inflight_focus_stack_link),
         wm_stack: wl.list.Head(View, .inflight_wm_stack_link),
     },
 },
@@ -144,16 +142,13 @@ pub fn init(root: *Root) !void {
         .hidden = .{
             .tree = hidden_tree,
             .pending = .{
-                .focus_stack = undefined,
                 .wm_stack = undefined,
             },
             .inflight = .{
-                .focus_stack = undefined,
                 .wm_stack = undefined,
             },
         },
         .fallback_pending = .{
-            .focus_stack = undefined,
             .wm_stack = undefined,
         },
         .views = undefined,
@@ -168,12 +163,9 @@ pub fn init(root: *Root) !void {
         .gamma_control_manager = try wlr.GammaControlManagerV1.create(server.wl_server),
         .transaction_timeout = transaction_timeout,
     };
-    root.hidden.pending.focus_stack.init();
     root.hidden.pending.wm_stack.init();
-    root.hidden.inflight.focus_stack.init();
     root.hidden.inflight.wm_stack.init();
 
-    root.fallback_pending.focus_stack.init();
     root.fallback_pending.wm_stack.init();
 
     root.views.init();
@@ -268,7 +260,7 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
     output.active_link.init();
 
     {
-        var it = output.inflight.focus_stack.safeIterator(.forward);
+        var it = output.inflight.wm_stack.safeIterator(.forward);
         while (it.next()) |view| {
             view.inflight.output = null;
             view.current.output = null;
@@ -276,9 +268,6 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
             view.tree.node.reparent(root.hidden.tree);
             view.popup_tree.node.reparent(root.hidden.tree);
 
-            view.inflight_focus_stack_link.remove();
-            view.inflight_focus_stack_link.init();
-
             view.inflight_wm_stack_link.remove();
             view.inflight_wm_stack_link.init();
 
@@ -303,12 +292,11 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
         break :blk it.next();
     };
     if (fallback_output) |fallback| {
-        var it = output.pending.focus_stack.safeIterator(.reverse);
+        var it = output.pending.wm_stack.safeIterator(.reverse);
         while (it.next()) |view| view.setPendingOutput(fallback);
     } else {
-        var it = output.pending.focus_stack.iterator(.forward);
+        var it = output.pending.wm_stack.iterator(.forward);
         while (it.next()) |view| view.pending.output = null;
-        root.fallback_pending.focus_stack.prependList(&output.pending.focus_stack);
         root.fallback_pending.wm_stack.prependList(&output.pending.wm_stack);
     }
 
@@ -324,15 +312,6 @@ pub fn deactivateOutput(root: *Root, output: *Output) void {
         }
     }
 
-    // If any seat has the removed output focused, focus the fallback one
-    var seat_it = server.input_manager.seats.first;
-    while (seat_it) |seat_node| : (seat_it = seat_node.next) {
-        const seat = &seat_node.data;
-        if (seat.focused_output == output) {
-            seat.focusOutput(fallback_output);
-        }
-    }
-
     // 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();
@@ -372,14 +351,6 @@ pub fn activateOutput(root: *Root, output: *Output) void {
             var it = root.fallback_pending.wm_stack.safeIterator(.reverse);
             while (it.next()) |view| view.setPendingOutput(output);
         }
-        {
-            // Focus the new output with all seats
-            var it = server.input_manager.seats.first;
-            while (it) |seat_node| : (it = seat_node.next) {
-                const seat = &seat_node.data;
-                seat.focusOutput(output);
-            }
-        }
     } else {
         // Otherwise check if any views were previously evacuated from an output
         // with the same (connector-)name and move them back.
@@ -395,7 +366,6 @@ pub fn activateOutput(root: *Root, output: *Output) void {
             }
         }
     }
-    assert(root.fallback_pending.focus_stack.empty());
     assert(root.fallback_pending.wm_stack.empty());
 
     // Enforce map-to-output configuration for the newly active output.
@@ -424,18 +394,10 @@ pub fn applyPending(root: *Root) void {
     root.pending_state_dirty = false;
 
     {
-        var it = root.hidden.pending.focus_stack.iterator(.forward);
+        var it = root.hidden.pending.wm_stack.iterator(.forward);
         while (it.next()) |view| {
             assert(view.pending.output == null);
             view.inflight.output = null;
-            view.inflight_focus_stack_link.remove();
-            root.hidden.inflight.focus_stack.append(view);
-        }
-    }
-
-    {
-        var it = root.hidden.pending.wm_stack.iterator(.forward);
-        while (it.next()) |view| {
             view.inflight_wm_stack_link.remove();
             root.hidden.inflight.wm_stack.append(view);
         }
@@ -448,7 +410,7 @@ pub fn applyPending(root: *Root) void {
             // recently focused view that requests fullscreen is given fullscreen.
             output.inflight.fullscreen = null;
             {
-                var it = output.pending.focus_stack.iterator(.forward);
+                var it = output.pending.wm_stack.iterator(.forward);
                 while (it.next()) |view| {
                     assert(view.pending.output == output);
 
@@ -465,18 +427,10 @@ pub fn applyPending(root: *Root) void {
                         output.inflight.fullscreen = view;
                     }
 
-                    view.inflight_focus_stack_link.remove();
-                    output.inflight.focus_stack.append(view);
-
-                    view.inflight = view.pending;
-                }
-            }
-
-            {
-                var it = output.pending.wm_stack.iterator(.forward);
-                while (it.next()) |view| {
                     view.inflight_wm_stack_link.remove();
                     output.inflight.wm_stack.append(view);
+
+                    view.inflight = view.pending;
                 }
             }
         }
@@ -513,8 +467,8 @@ fn sendConfigures(root: *Root) void {
     // Iterate over all views of all outputs
     var output_it = root.active_outputs.iterator(.forward);
     while (output_it.next()) |output| {
-        var focus_stack_it = output.inflight.focus_stack.iterator(.forward);
-        while (focus_stack_it.next()) |view| {
+        var wm_stack_it = output.inflight.wm_stack.iterator(.forward);
+        while (wm_stack_it.next()) |view| {
             assert(!view.inflight_transaction);
             view.inflight_transaction = true;
 
@@ -573,7 +527,7 @@ fn commitTransaction(root: *Root) void {
     std.log.scoped(.transaction).debug("commiting transaction", .{});
 
     {
-        var it = root.hidden.inflight.focus_stack.safeIterator(.forward);
+        var it = root.hidden.inflight.wm_stack.safeIterator(.forward);
         while (it.next()) |view| {
             assert(view.inflight.output == null);
             view.current.output = null;
@@ -585,8 +539,8 @@ fn commitTransaction(root: *Root) void {
 
     var output_it = root.active_outputs.iterator(.forward);
     while (output_it.next()) |output| {
-        var focus_stack_it = output.inflight.focus_stack.iterator(.forward);
-        while (focus_stack_it.next()) |view| {
+        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
@@ -626,7 +580,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.focus_stack.safeIterator(.forward);
+        var it = root.hidden.inflight.wm_stack.safeIterator(.forward);
         while (it.next()) |view| {
             view.dropSavedSurfaceTree();
             if (view.destroying) view.destroy(.assert);
diff --git a/river/Seat.zig b/river/Seat.zig
index b01b5fe..7d5ec0f 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -78,9 +78,6 @@ repeating_mapping: ?*const Mapping = null,
 
 keyboard_groups: std.TailQueue(KeyboardGroup) = .{},
 
-/// Currently focused output. Null only when there are no outputs at all.
-focused_output: ?*Output = null,
-
 focused: FocusTarget = .none,
 
 /// The currently in progress drag operation type.
@@ -145,12 +142,7 @@ pub fn deinit(seat: *Seat) void {
 /// Set the current focus. If a visible view is passed it will be focused.
 /// If null is passed, the top view in the stack of the focused output will be focused.
 /// Requires a call to Root.applyPending()
-pub fn focus(seat: *Seat, _target: ?*View) void {
-    var target = _target;
-
-    // Don't change focus if there are no outputs.
-    if (seat.focused_output == null) return;
-
+pub fn focus(seat: *Seat, target: ?*View) void {
     // Views may not receive focus while locked.
     if (server.lock_manager.state != .unlocked) return;
 
@@ -172,25 +164,8 @@ pub fn focus(seat: *Seat, _target: ?*View) void {
         }
     }
 
-    if (target) |view| {
-        if (view.pending.output.? != seat.focused_output.?) {
-            // If the view is not on the currently focused output, focus it
-            seat.focusOutput(view.pending.output.?);
-        }
-    }
-
-    // If null, set the target to the first currently visible view in the focus stack if any
-    if (target == null) {
-        var it = seat.focused_output.?.pending.focus_stack.iterator(.forward);
-        target = while (it.next()) |view| {
-            break view;
-        } else null;
-    }
-
     // Focus the target view or clear the focus if target is null
     if (target) |view| {
-        view.pending_focus_stack_link.remove();
-        seat.focused_output.?.pending.focus_stack.prepend(view);
         seat.setFocusRaw(.{ .view = view });
     } else {
         seat.setFocusRaw(.{ .none = {} });
@@ -222,14 +197,10 @@ pub fn setFocusRaw(seat: *Seat, new_focus: FocusTarget) void {
     switch (new_focus) {
         .view => |target_view| {
             assert(server.lock_manager.state != .locked);
-            assert(seat.focused_output == target_view.pending.output);
             target_view.pending.focus += 1;
             target_view.pending.urgent = false;
         },
-        .layer => |target_layer| {
-            assert(server.lock_manager.state != .locked);
-            assert(seat.focused_output == target_layer.output);
-        },
+        .layer => assert(server.lock_manager.state != .locked),
         .lock_surface => assert(server.lock_manager.state != .unlocked),
         .override_redirect, .none => {},
     }
@@ -291,13 +262,6 @@ fn keyboardNotifyEnter(seat: *Seat, wlr_surface: *wlr.Surface) void {
     }
 }
 
-/// Focus the given output, notifying any listening clients of the change.
-pub fn focusOutput(seat: *Seat, output: ?*Output) void {
-    if (seat.focused_output == output) return;
-
-    seat.focused_output = output;
-}
-
 pub fn handleActivity(seat: Seat) void {
     server.input_manager.idle_notifier.notifyActivity(seat.wlr_seat);
 }
diff --git a/river/Server.zig b/river/Server.zig
index a9acf82..d46cb4f 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -344,9 +344,7 @@ fn handleNewToplevelDecoration(
     XdgDecoration.init(wlr_decoration);
 }
 
-fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
-    const server: *Server = @fieldParentPtr("new_layer_surface", listener);
-
+fn handleNewLayerSurface(_: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
     log.debug(
         "new layer surface: namespace {s}, layer {s}, anchor {b:0>4}, size {},{}, margin {},{},{},{}, exclusive_zone {}",
         .{
@@ -366,7 +364,9 @@ fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_
     // If the new layer surface does not have an output assigned to it, use the
     // first output or close the surface if none are available.
     if (wlr_layer_surface.output == null) {
-        const output = server.input_manager.defaultSeat().focused_output orelse {
+        if (true) @panic("TODO");
+
+        const output = null orelse {
             log.err("no output available for layer surface '{s}'", .{wlr_layer_surface.namespace});
             wlr_layer_surface.destroy();
             return;
diff --git a/river/View.zig b/river/View.zig
index 74353df..67d147f 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -142,14 +142,12 @@ destroying: bool = false,
 /// Any time pending state is modified Root.applyPending() must be called
 /// before yielding back to the event loop.
 pending: State = .{},
-pending_focus_stack_link: wl.list.Link,
 pending_wm_stack_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_focus_stack_link: wl.list.Link,
 inflight_wm_stack_link: wl.list.Link,
 
 /// The current state represented by the scene graph.
@@ -195,15 +193,11 @@ pub fn create(impl: Impl) error{OutOfMemory}!*View {
         .popup_tree = popup_tree,
 
         .pending_wm_stack_link = undefined,
-        .pending_focus_stack_link = undefined,
         .inflight_wm_stack_link = undefined,
-        .inflight_focus_stack_link = undefined,
     };
 
     server.root.views.prepend(view);
-    server.root.hidden.pending.focus_stack.prepend(view);
     server.root.hidden.pending.wm_stack.prepend(view);
-    server.root.hidden.inflight.focus_stack.prepend(view);
     server.root.hidden.inflight.wm_stack.prepend(view);
 
     view.tree.node.setEnabled(false);
@@ -233,9 +227,7 @@ pub fn destroy(view: *View, when: enum { lazy, assert }) void {
         view.popup_tree.node.destroy();
 
         view.link.remove();
-        view.pending_focus_stack_link.remove();
         view.pending_wm_stack_link.remove();
-        view.inflight_focus_stack_link.remove();
         view.inflight_wm_stack_link.remove();
 
         if (view.output_before_evac) |name| util.gpa.free(name);
@@ -504,10 +496,8 @@ fn saveSurfaceTreeIter(
 pub fn setPendingOutput(view: *View, output: *Output) void {
     view.pending.output = output;
     view.pending_wm_stack_link.remove();
-    view.pending_focus_stack_link.remove();
 
     output.pending.wm_stack.prepend(view);
-    output.pending.focus_stack.prepend(view);
 
     if (view.pending.fullscreen) {
         view.pending.box = .{ .x = 0, .y = 0, .width = undefined, .height = undefined };
@@ -566,7 +556,8 @@ pub fn map(view: *View) !void {
 
     view.foreign_toplevel_handle.map();
 
-    const output = server.input_manager.defaultSeat().focused_output;
+    if (true) @panic("TODO");
+    const output = undefined;
 
     if (output) |o| {
         // Center the initial pending box on the output
@@ -583,16 +574,11 @@ pub fn map(view: *View) !void {
         log.debug("no output available for newly mapped view, adding to fallback stacks", .{});
 
         view.pending_wm_stack_link.remove();
-        view.pending_focus_stack_link.remove();
 
         server.root.fallback_pending.wm_stack.prepend(view);
-        server.root.fallback_pending.focus_stack.prepend(view);
 
         view.inflight_wm_stack_link.remove();
         view.inflight_wm_stack_link.init();
-
-        view.inflight_focus_stack_link.remove();
-        view.inflight_focus_stack_link.init();
     }
 
     view.float_box = view.pending.box;
@@ -608,9 +594,7 @@ pub fn unmap(view: *View) void {
 
     {
         view.pending.output = null;
-        view.pending_focus_stack_link.remove();
         view.pending_wm_stack_link.remove();
-        server.root.hidden.pending.focus_stack.prepend(view);
         server.root.hidden.pending.wm_stack.prepend(view);
     }