aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--river/Cursor.zig8
-rw-r--r--river/Seat.zig13
-rw-r--r--river/XwaylandUnmanaged.zig19
3 files changed, 33 insertions, 7 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index da1b8d6..73f48a4 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -315,7 +315,13 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
self.seat.focus(null);
}
},
- .xwayland_unmanaged => assert(build_options.xwayland),
+ .xwayland_unmanaged => |xwayland_unmanaged| {
+ if (build_options.xwayland) {
+ self.seat.setFocusRaw(.{ .xwayland_unmanaged = xwayland_unmanaged });
+ } else {
+ unreachable;
+ }
+ },
}
_ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
diff --git a/river/Seat.zig b/river/Seat.zig
index ebe23bb..baf1056 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -38,12 +38,14 @@ const Output = @import("Output.zig");
const SeatStatus = @import("SeatStatus.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
+const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
const log = std.log.scoped(.seat);
const PointerConstraint = @import("PointerConstraint.zig");
const FocusTarget = union(enum) {
view: *View,
+ xwayland_unmanaged: *XwaylandUnmanaged,
layer: *LayerSurface,
none: void,
};
@@ -206,7 +208,8 @@ fn pendingFilter(view: *View, filter_tags: u32) bool {
}
/// Switch focus to the target, handling unfocus and input inhibition
-/// properly. This should only be called directly if dealing with layers.
+/// properly. This should only be called directly if dealing with layers or
+/// unmanaged xwayland views.
pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
// If the target is already focused, do nothing
if (std.meta.eql(new_focus, self.focused)) return;
@@ -214,6 +217,10 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
// Obtain the target surface
const target_surface = switch (new_focus) {
.view => |target_view| target_view.surface.?,
+ .xwayland_unmanaged => |target_xwayland_unmanaged| blk: {
+ assert(build_options.xwayland);
+ break :blk target_xwayland_unmanaged.xwayland_surface.surface;
+ },
.layer => |target_layer| target_layer.wlr_layer_surface.surface,
.none => null,
};
@@ -228,7 +235,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
view.pending.focus -= 1;
if (view.pending.focus == 0) view.setActivated(false);
},
- .layer, .none => {},
+ .xwayland_unmanaged, .layer, .none => {},
}
// Set the new focus
@@ -240,7 +247,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
target_view.pending.urgent = false;
},
.layer => |target_layer| assert(self.focused_output == target_layer.output),
- .none => {},
+ .xwayland_unmanaged, .none => {},
}
self.focused = new_focus;
diff --git a/river/XwaylandUnmanaged.zig b/river/XwaylandUnmanaged.zig
index e19d353..96f6f3f 100644
--- a/river/XwaylandUnmanaged.zig
+++ b/river/XwaylandUnmanaged.zig
@@ -78,19 +78,32 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
xwayland_surface.surface.?.events.commit.add(&self.commit);
- // TODO: handle keyboard focus
- // if (wlr_xwayland_or_surface_wants_focus(self.xwayland_surface)) { ...
+ if (self.xwayland_surface.overrideRedirectWantsFocus()) {
+ server.input_manager.defaultSeat().setFocusRaw(.{ .xwayland_unmanaged = self });
+ }
}
/// Called when the surface is unmapped and will no longer be displayed.
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
const self = @fieldParentPtr(Self, "unmap", listener);
- // Remove self from the list of unmanged views in the root
+ // Remove self from the list of unmanaged views in the root
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
server.root.xwayland_unmanaged_views.remove(node);
self.commit.link.remove();
+
+ // If the unmapped surface is currently focused, reset focus to the most
+ // appropriate view.
+ 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 == .xwayland_unmanaged and seat.focused.xwayland_unmanaged == self) {
+ seat.focus(null);
+ }
+ }
+
+ server.root.startTransaction();
}
fn handleCommit(_: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {