xwayland-unmanaged: handle focus on map/cursor button
This implements keyboard focus on map for unmanaged Xwayland views using wlroot's heuristic approach as well as keyboard focus on cursor button click.
This commit is contained in:
parent
0dd5ad032c
commit
7b554bde68
@ -315,7 +315,13 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
|
|||||||
self.seat.focus(null);
|
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);
|
_ = self.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
|
||||||
|
|
||||||
|
@ -38,12 +38,14 @@ const Output = @import("Output.zig");
|
|||||||
const SeatStatus = @import("SeatStatus.zig");
|
const SeatStatus = @import("SeatStatus.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
const ViewStack = @import("view_stack.zig").ViewStack;
|
const ViewStack = @import("view_stack.zig").ViewStack;
|
||||||
|
const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.seat);
|
const log = std.log.scoped(.seat);
|
||||||
const PointerConstraint = @import("PointerConstraint.zig");
|
const PointerConstraint = @import("PointerConstraint.zig");
|
||||||
|
|
||||||
const FocusTarget = union(enum) {
|
const FocusTarget = union(enum) {
|
||||||
view: *View,
|
view: *View,
|
||||||
|
xwayland_unmanaged: *XwaylandUnmanaged,
|
||||||
layer: *LayerSurface,
|
layer: *LayerSurface,
|
||||||
none: void,
|
none: void,
|
||||||
};
|
};
|
||||||
@ -206,7 +208,8 @@ fn pendingFilter(view: *View, filter_tags: u32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Switch focus to the target, handling unfocus and input inhibition
|
/// 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 {
|
pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
||||||
// If the target is already focused, do nothing
|
// If the target is already focused, do nothing
|
||||||
if (std.meta.eql(new_focus, self.focused)) return;
|
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
|
// Obtain the target surface
|
||||||
const target_surface = switch (new_focus) {
|
const target_surface = switch (new_focus) {
|
||||||
.view => |target_view| target_view.surface.?,
|
.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,
|
.layer => |target_layer| target_layer.wlr_layer_surface.surface,
|
||||||
.none => null,
|
.none => null,
|
||||||
};
|
};
|
||||||
@ -228,7 +235,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
view.pending.focus -= 1;
|
view.pending.focus -= 1;
|
||||||
if (view.pending.focus == 0) view.setActivated(false);
|
if (view.pending.focus == 0) view.setActivated(false);
|
||||||
},
|
},
|
||||||
.layer, .none => {},
|
.xwayland_unmanaged, .layer, .none => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new focus
|
// Set the new focus
|
||||||
@ -240,7 +247,7 @@ pub fn setFocusRaw(self: *Self, new_focus: FocusTarget) void {
|
|||||||
target_view.pending.urgent = false;
|
target_view.pending.urgent = false;
|
||||||
},
|
},
|
||||||
.layer => |target_layer| assert(self.focused_output == target_layer.output),
|
.layer => |target_layer| assert(self.focused_output == target_layer.output),
|
||||||
.none => {},
|
.xwayland_unmanaged, .none => {},
|
||||||
}
|
}
|
||||||
self.focused = new_focus;
|
self.focused = new_focus;
|
||||||
|
|
||||||
|
@ -78,19 +78,32 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
|
|||||||
|
|
||||||
xwayland_surface.surface.?.events.commit.add(&self.commit);
|
xwayland_surface.surface.?.events.commit.add(&self.commit);
|
||||||
|
|
||||||
// TODO: handle keyboard focus
|
if (self.xwayland_surface.overrideRedirectWantsFocus()) {
|
||||||
// if (wlr_xwayland_or_surface_wants_focus(self.xwayland_surface)) { ...
|
server.input_manager.defaultSeat().setFocusRaw(.{ .xwayland_unmanaged = self });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called when the surface is unmapped and will no longer be displayed.
|
/// Called when the surface is unmapped and will no longer be displayed.
|
||||||
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
|
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
|
||||||
const self = @fieldParentPtr(Self, "unmap", listener);
|
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);
|
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
||||||
server.root.xwayland_unmanaged_views.remove(node);
|
server.root.xwayland_unmanaged_views.remove(node);
|
||||||
|
|
||||||
self.commit.link.remove();
|
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 {
|
fn handleCommit(_: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
|
Loading…
Reference in New Issue
Block a user