SceneNodeData: allow access from wlr_surfaces

This replaces the old View.fromWlrSurface function and is more general.

This commit also moves the xdg activation request_activate listener to
Server as it has no reason to be in View.
This commit is contained in:
Isaac Freund 2023-03-04 22:41:35 +01:00
parent ea4e589fdc
commit 44004e2d28
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
11 changed files with 80 additions and 53 deletions

View File

@ -7,8 +7,9 @@ const wl = @import("wayland").server.wl;
const server = &@import("main.zig").server;
const util = @import("util.zig");
const View = @import("View.zig");
const IdleInhibitor = @import("IdleInhibitor.zig");
const SceneNodeData = @import("SceneNodeData.zig");
const View = @import("View.zig");
idle_inhibit_manager: *wlr.IdleInhibitManagerV1,
new_idle_inhibitor: wl.Listener(*wlr.IdleInhibitorV1),
@ -32,17 +33,26 @@ pub fn idleInhibitCheckActive(self: *Self) void {
var inhibited = false;
var it = self.inhibitors.first;
while (it) |node| : (it = node.next) {
if (View.fromWlrSurface(node.data.inhibitor.surface)) |v| {
// If view is visible,
if (v.current.output != null and v.current.tags & v.current.output.?.current.tags != 0) {
const node_data = SceneNodeData.fromSurface(node.data.inhibitor.surface) orelse continue;
switch (node_data.data) {
.view => |view| {
if (view.current.output != null and
view.current.tags & view.current.output.?.current.tags != 0)
{
inhibited = true;
break;
}
},
.layer_surface => |layer_surface| {
if (layer_surface.wlr_layer_surface.mapped) {
inhibited = true;
break;
}
},
.lock_surface, .xwayland_override_redirect => {
inhibited = true;
break;
}
} else {
// If for whatever reason the inhibitor does not have a view, then
// assume it is visible.
inhibited = true;
break;
},
}
}

View File

@ -60,6 +60,8 @@ pub fn create(wlr_layer_surface: *wlr.LayerSurfaceV1) error{OutOfMemory}!void {
try SceneNodeData.attach(&layer_surface.scene_layer_surface.tree.node, .{ .layer_surface = layer_surface });
try SceneNodeData.attach(&layer_surface.popup_tree.node, .{ .layer_surface = layer_surface });
wlr_layer_surface.surface.data = @ptrToInt(&layer_surface.scene_layer_surface.tree.node);
wlr_layer_surface.events.destroy.add(&layer_surface.destroy);
wlr_layer_surface.events.map.add(&layer_surface.map);
wlr_layer_surface.events.unmap.add(&layer_surface.unmap);

View File

@ -51,6 +51,8 @@ pub fn create(wlr_lock_surface: *wlr.SessionLockSurfaceV1, lock: *wlr.SessionLoc
try SceneNodeData.attach(&tree.node, .{ .lock_surface = lock_surface });
wlr_lock_surface.surface.data = @ptrToInt(&tree.node);
wlr_lock_surface.output.events.mode.add(&lock_surface.output_mode);
wlr_lock_surface.events.map.add(&lock_surface.map);
wlr_lock_surface.events.destroy.add(&lock_surface.surface_destroy);

View File

@ -195,7 +195,7 @@ pub fn at(self: Self, lx: f64, ly: f64) ?AtResult {
break :blk null;
};
if (SceneNodeData.get(node_at)) |scene_node_data| {
if (SceneNodeData.fromNode(node_at)) |scene_node_data| {
return .{
.surface = surface,
.sx = sx,

View File

@ -50,7 +50,7 @@ pub fn attach(node: *wlr.SceneNode, data: Data) error{OutOfMemory}!void {
node.events.destroy.add(&scene_node_data.destroy);
}
pub fn get(node: *wlr.SceneNode) ?*SceneNodeData {
pub fn fromNode(node: *wlr.SceneNode) ?*SceneNodeData {
var it: ?*wlr.SceneNode = node;
while (it) |n| : (it = n.parent) {
if (@intToPtr(?*SceneNodeData, n.data)) |scene_node_data| {
@ -60,6 +60,15 @@ pub fn get(node: *wlr.SceneNode) ?*SceneNodeData {
return null;
}
pub fn fromSurface(surface: *wlr.Surface) ?*SceneNodeData {
if (surface.getRootSurface()) |root_surface| {
if (@intToPtr(?*wlr.SceneNode, root_surface.data)) |node| {
return fromNode(node);
}
}
return null;
}
fn handleDestroy(listener: *wl.Listener(void)) void {
const scene_node_data = @fieldParentPtr(SceneNodeData, "destroy", listener);

View File

@ -27,17 +27,18 @@ const util = @import("util.zig");
const Config = @import("Config.zig");
const Control = @import("Control.zig");
const DecorationManager = @import("DecorationManager.zig");
const IdleInhibitorManager = @import("IdleInhibitorManager.zig");
const InputManager = @import("InputManager.zig");
const LayerSurface = @import("LayerSurface.zig");
const LayoutManager = @import("LayoutManager.zig");
const LockManager = @import("LockManager.zig");
const Output = @import("Output.zig");
const Root = @import("Root.zig");
const SceneNodeData = @import("SceneNodeData.zig");
const StatusManager = @import("StatusManager.zig");
const XdgToplevel = @import("XdgToplevel.zig");
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
const XwaylandView = @import("XwaylandView.zig");
const IdleInhibitorManager = @import("IdleInhibitorManager.zig");
const log = std.log.scoped(.server);
@ -62,6 +63,7 @@ xwayland: if (build_options.xwayland) *wlr.Xwayland else void,
new_xwayland_surface: if (build_options.xwayland) wl.Listener(*wlr.XwaylandSurface) else void,
xdg_activation: *wlr.XdgActivationV1,
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
decoration_manager: DecorationManager,
input_manager: InputManager,
@ -115,6 +117,8 @@ pub fn init(self: *Self) !void {
}
self.xdg_activation = try wlr.XdgActivationV1.create(self.wl_server);
self.xdg_activation.events.request_activate.add(&self.request_activate);
self.request_activate.setNotify(handleRequestActivate);
_ = try wlr.PrimarySelectionDeviceManagerV1.create(self.wl_server);
@ -144,7 +148,14 @@ pub fn deinit(self: *Self) void {
self.sigint_source.remove();
self.sigterm_source.remove();
if (build_options.xwayland) self.xwayland.destroy();
self.new_xdg_surface.link.remove();
self.new_layer_surface.link.remove();
self.request_activate.link.remove();
if (build_options.xwayland) {
self.new_xwayland_surface.link.remove();
self.xwayland.destroy();
}
self.wl_server.destroyClients();
@ -251,3 +262,23 @@ fn handleNewXwaylandSurface(_: *wl.Listener(*wlr.XwaylandSurface), xwayland_surf
};
}
}
fn handleRequestActivate(
listener: *wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
event: *wlr.XdgActivationV1.event.RequestActivate,
) void {
const server = @fieldParentPtr(Self, "request_activate", listener);
std.debug.print("made it here ig\n", .{});
const node_data = SceneNodeData.fromSurface(event.surface) orelse return;
switch (node_data.data) {
.view => |view| if (view.current.focus == 0) {
view.pending.urgent = true;
server.root.applyPending();
},
else => |tag| {
log.info("ignoring xdg-activation-v1 activate request of {s} surface", .{@tagName(tag)});
},
}
}

View File

@ -147,9 +147,6 @@ float_box: wlr.Box = undefined,
/// exiting fullscreen if there is no active layout.
post_fullscreen_box: wlr.Box = undefined,
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) =
wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate),
pub fn create(impl: Impl) error{OutOfMemory}!*Self {
const view = try util.gpa.create(Self);
errdefer util.gpa.destroy(view);
@ -383,21 +380,6 @@ pub fn applyConstraints(self: *Self, box: *wlr.Box) void {
box.height = math.clamp(box.height, self.constraints.min_height, self.constraints.max_height);
}
/// Find and return the view corresponding to a given surface, if any
pub fn fromWlrSurface(surface: *wlr.Surface) ?*Self {
if (surface.isXdgSurface()) {
const xdg_surface = wlr.XdgSurface.fromWlrSurface(surface) orelse return null;
if (xdg_surface.role == .toplevel) {
return @intToPtr(*Self, xdg_surface.data);
}
}
if (build_options.xwayland and surface.isXWaylandSurface()) {
const xwayland_surface = wlr.XwaylandSurface.fromWlrSurface(surface) orelse return null;
return @intToPtr(?*Self, xwayland_surface.data);
}
return null;
}
/// Called by the impl when the surface is ready to be displayed
pub fn map(view: *Self) !void {
log.debug("view '{?s}' mapped", .{view.getTitle()});
@ -407,8 +389,6 @@ pub fn map(view: *Self) !void {
view.pending.borders = !server.config.csdAllowed(view);
server.xdg_activation.events.request_activate.add(&view.request_activate);
if (server.input_manager.defaultSeat().focused_output) |output| {
// Center the initial pending box on the output
view.pending.box.x = @divTrunc(math.max(0, output.usable_box.width - view.pending.box.width), 2);
@ -444,8 +424,6 @@ pub fn unmap(view: *Self) void {
server.root.hidden.pending.wm_stack.prepend(view);
}
view.request_activate.link.remove();
assert(view.mapped and !view.destroying);
view.mapped = false;
@ -468,15 +446,3 @@ pub fn notifyTitle(self: *const Self) void {
pub fn notifyAppId(_: Self) void {
// TODO reimplement foreign-toplevel-management I guess.
}
fn handleRequestActivate(
_: *wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
event: *wlr.XdgActivationV1.event.RequestActivate,
) void {
if (fromWlrSurface(event.surface)) |view| {
if (view.current.focus == 0) {
view.pending.urgent = true;
server.root.applyPending();
}
}
}

View File

@ -86,7 +86,7 @@ fn handleNewPopup(listener: *wl.Listener(*wlr.XdgPopup), wlr_xdg_popup: *wlr.Xdg
fn handleReposition(listener: *wl.Listener(void)) void {
const xdg_popup = @fieldParentPtr(XdgPopup, "reposition", listener);
const output = switch (SceneNodeData.get(&xdg_popup.root.node).?.data) {
const output = switch (SceneNodeData.fromNode(&xdg_popup.root.node).?.data) {
.view => |view| view.current.output orelse return,
.layer_surface => |layer_surface| layer_surface.output,
else => unreachable,

View File

@ -79,6 +79,7 @@ pub fn create(xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
_ = try view.surface_tree.createSceneXdgSurface(xdg_toplevel.base);
xdg_toplevel.base.data = @ptrToInt(view);
xdg_toplevel.base.surface.data = @ptrToInt(&view.tree.node);
// Add listeners that are active over the view's entire lifetime
const self = &view.impl.xdg_toplevel;

View File

@ -91,11 +91,12 @@ pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
}
fn mapImpl(self: *Self) error{OutOfMemory}!void {
self.surface_tree = try server.root.layers.xwayland_override_redirect.createSceneSubsurfaceTree(
self.xwayland_surface.surface.?,
);
const surface = self.xwayland_surface.surface.?;
self.surface_tree = try server.root.layers.xwayland_override_redirect.createSceneSubsurfaceTree(surface);
try SceneNodeData.attach(&self.surface_tree.?.node, .{ .xwayland_override_redirect = self });
surface.data = @ptrToInt(&self.surface_tree.?.node);
self.surface_tree.?.node.setPosition(self.xwayland_surface.x, self.xwayland_surface.y);
self.xwayland_surface.events.set_geometry.add(&self.set_geometry);
@ -130,6 +131,7 @@ fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSur
self.set_geometry.link.remove();
self.xwayland_surface.surface.?.data = 0;
self.surface_tree.?.node.destroy();
self.surface_tree = null;

View File

@ -159,8 +159,10 @@ pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface:
const self = @fieldParentPtr(Self, "map", listener);
const view = self.view;
// Add listeners that are only active while mapped
const surface = xwayland_surface.surface.?;
surface.data = @ptrToInt(&view.tree.node);
// Add listeners that are only active while mapped
xwayland_surface.events.set_title.add(&self.set_title);
xwayland_surface.events.set_class.add(&self.set_class);
xwayland_surface.events.request_fullscreen.add(&self.request_fullscreen);
@ -206,6 +208,8 @@ pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface:
fn handleUnmap(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandSurface) void {
const self = @fieldParentPtr(Self, "unmap", listener);
self.xwayland_surface.surface.?.data = 0;
// Remove listeners that are only active while mapped
self.set_title.link.remove();
self.set_class.link.remove();