diff --git a/river/InputManager.zig b/river/InputManager.zig index 2ec46f5..85e4dae 100644 --- a/river/InputManager.zig +++ b/river/InputManager.zig @@ -161,15 +161,6 @@ pub fn defaultSeat(self: Self) *Seat { return &self.seats.first.?.data; } -/// Must be called whenever a view is unmapped. -pub fn handleViewUnmap(self: Self, view: *View) void { - var it = self.seats.first; - while (it) |node| : (it = node.next) { - const seat = &node.data; - seat.handleViewUnmap(view); - } -} - /// Returns true if input is currently allowed on the passed surface. pub fn inputAllowed(self: Self, wlr_surface: *wlr.Surface) bool { return if (self.exclusive_client) |exclusive_client| diff --git a/river/Seat.zig b/river/Seat.zig index 95a5e3f..7b61827 100644 --- a/river/Seat.zig +++ b/river/Seat.zig @@ -149,27 +149,22 @@ pub fn focus(self: *Self, _target: ?*View) void { } else null; } + // Focus the target view or clear the focus if target is null if (target) |view| { - // Find or allocate a new node in the focus stack for the target view + // Find the node for this view in the focus stack and move it to the top. var it = self.focus_stack.first; while (it) |node| : (it = node.next) { - // If the view is found, move it to the top of the stack if (node.view == view) { const new_focus_node = self.focus_stack.remove(node); self.focus_stack.push(node); break; } } else { - // The view is not in the stack, so allocate a new node and prepend it - const new_focus_node = util.gpa.create(ViewStack(*View).Node) catch return; - new_focus_node.view = view; - self.focus_stack.push(new_focus_node); + // A node is added when new Views are mapped in Seat.handleViewMap() + unreachable; } - - // Focus the target view self.setFocusRaw(.{ .view = view }); } else { - // Otherwise clear the focus self.setFocusRaw(.{ .none = {} }); } } @@ -288,6 +283,13 @@ pub fn handleActivity(self: Self) void { server.input_manager.idle.notifyActivity(self.wlr_seat); } +pub fn handleViewMap(self: *Self, view: *View) !void { + const new_focus_node = try util.gpa.create(ViewStack(*View).Node); + new_focus_node.view = view; + self.focus_stack.append(new_focus_node); + self.focus(view); +} + /// Handle the unmapping of a view, removing it from the focus stack and /// setting the focus if needed. pub fn handleViewUnmap(self: *Self, view: *View) void { diff --git a/river/View.zig b/river/View.zig index bd5fd13..c3148b2 100644 --- a/river/View.zig +++ b/river/View.zig @@ -429,36 +429,30 @@ pub fn shouldTrackConfigure(self: Self) bool { } /// Called by the impl when the surface is ready to be displayed -pub fn map(self: *Self) void { +pub fn map(self: *Self) !void { log.debug("view '{s}' mapped", .{self.getTitle()}); if (self.foreign_toplevel_handle == null) { - self.foreign_toplevel_handle = wlr.ForeignToplevelHandleV1.create( - server.foreign_toplevel_manager, - ) catch { - log.crit("out of memory", .{}); - self.surface.?.resource.getClient().postNoMemory(); - return; - }; + const handle = try wlr.ForeignToplevelHandleV1.create(server.foreign_toplevel_manager); + self.foreign_toplevel_handle = handle; - self.foreign_toplevel_handle.?.events.request_activate.add(&self.foreign_activate); - self.foreign_toplevel_handle.?.events.request_fullscreen.add(&self.foreign_fullscreen); - self.foreign_toplevel_handle.?.events.request_close.add(&self.foreign_close); + handle.events.request_activate.add(&self.foreign_activate); + handle.events.request_fullscreen.add(&self.foreign_fullscreen); + handle.events.request_close.add(&self.foreign_close); - if (self.getTitle()) |s| self.foreign_toplevel_handle.?.setTitle(s); - if (self.getAppId()) |s| self.foreign_toplevel_handle.?.setAppId(s); + if (self.getTitle()) |s| handle.setTitle(s); + if (self.getAppId()) |s| handle.setAppId(s); - self.foreign_toplevel_handle.?.outputEnter(self.output.wlr_output); + handle.outputEnter(self.output.wlr_output); } // Add the view to the stack of its output const node = @fieldParentPtr(ViewStack(Self).Node, "view", self); self.output.views.attach(node, server.config.attach_mode); - // Focus the new view, assuming the seat is focusing the proper output - // and there isn't something else like a fullscreen view grabbing focus. + // Inform all seats that the view has been mapped so they can handle focus var it = server.input_manager.seats.first; - while (it) |seat_node| : (it = seat_node.next) seat_node.data.focus(self); + while (it) |seat_node| : (it = seat_node.next) try seat_node.data.handleViewMap(self); self.surface.?.sendEnter(self.output.wlr_output); @@ -480,10 +474,7 @@ pub fn unmap(self: *Self) void { // Inform all seats that the view has been unmapped so they can handle focus var it = server.input_manager.seats.first; - while (it) |node| : (it = node.next) { - const seat = &node.data; - seat.handleViewUnmap(self); - } + while (it) |seat_node| : (it = seat_node.next) seat_node.data.handleViewUnmap(self); self.output.sendViewTags(); diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig index baddfb8..454ce77 100644 --- a/river/XdgToplevel.zig +++ b/river/XdgToplevel.zig @@ -231,7 +231,10 @@ fn handleMap(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSurfa _ = toplevel.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); } - view.map(); + view.map() catch { + log.crit("out of memory", .{}); + xdg_surface.resource.getClient().postNoMemory(); + }; } /// Called when the surface is unmapped and will no longer be displayed. diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig index b25e689..e467dc2 100644 --- a/river/XwaylandView.zig +++ b/river/XwaylandView.zig @@ -207,7 +207,10 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl } } - view.map(); + view.map() catch { + std.log.crit("out of memory", .{}); + surface.resource.getClient().postNoMemory(); + }; } /// Called when the surface is unmapped and will no longer be displayed.