Xwayland: handle override redirect state changes

This commit is contained in:
Isaac Freund 2022-05-29 15:16:48 +02:00
parent 8a8dd9ff65
commit 6ef97eea24
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
4 changed files with 84 additions and 13 deletions

View File

@ -193,7 +193,7 @@ fn handleNewXdgSurface(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wl
xdg_surface.resource.postNoMemory(); xdg_surface.resource.postNoMemory();
return; return;
}; };
node.view.init(output, getNewViewTags(output), xdg_surface); node.view.init(output, xdg_surface);
} }
/// This event is raised when the layer_shell recieves a new surface from a client. /// This event is raised when the layer_shell recieves a new surface from a client.
@ -259,10 +259,5 @@ fn handleNewXwaylandSurface(listener: *wl.Listener(*wlr.XwaylandSurface), wlr_xw
// The View will add itself to the output's view stack on map // The View will add itself to the output's view stack on map
const output = self.input_manager.defaultSeat().focused_output; const output = self.input_manager.defaultSeat().focused_output;
const node = util.gpa.create(ViewStack(View).Node) catch return; const node = util.gpa.create(ViewStack(View).Node) catch return;
node.view.init(output, getNewViewTags(output), wlr_xwayland_surface); node.view.init(output, wlr_xwayland_surface);
}
fn getNewViewTags(output: *Output) u32 {
const tags = output.current.tags & output.spawn_tagmask;
return if (tags != 0) tags else output.current.tags;
} }

View File

@ -126,11 +126,16 @@ foreign_close: wl.Listener(*wlr.ForeignToplevelHandleV1) =
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) = request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) =
wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate), wl.Listener(*wlr.XdgActivationV1.event.RequestActivate).init(handleRequestActivate),
pub fn init(self: *Self, output: *Output, tags: u32, surface: anytype) void { pub fn init(self: *Self, output: *Output, surface: anytype) void {
const initial_tags = blk: {
const tags = output.current.tags & output.spawn_tagmask;
break :blk if (tags != 0) tags else output.current.tags;
};
self.* = .{ self.* = .{
.output = output, .output = output,
.current = .{ .tags = tags }, .current = .{ .tags = initial_tags },
.pending = .{ .tags = tags }, .pending = .{ .tags = initial_tags },
.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa), .saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa),
}; };

View File

@ -17,6 +17,8 @@
const Self = @This(); const Self = @This();
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert;
const wlr = @import("wlroots"); const wlr = @import("wlroots");
const wl = @import("wayland").server.wl; const wl = @import("wayland").server.wl;
@ -24,6 +26,11 @@ const server = &@import("main.zig").server;
const util = @import("util.zig"); const util = @import("util.zig");
const Box = @import("Box.zig"); const Box = @import("Box.zig");
const View = @import("View.zig");
const XwaylandView = @import("XwaylandView.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const log = std.log.scoped(.xwayland);
/// The corresponding wlroots object /// The corresponding wlroots object
xwayland_surface: *wlr.XwaylandSurface, xwayland_surface: *wlr.XwaylandSurface,
@ -34,6 +41,10 @@ request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
destroy: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleDestroy), destroy: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleDestroy),
map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap), map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap),
unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap), unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap),
set_override_redirect: wl.Listener(*wlr.XwaylandSurface) =
wl.Listener(*wlr.XwaylandSurface).init(handleSetOverrideRedirect),
// Listeners that are only active while mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit), commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
pub fn init(self: *Self, xwayland_surface: *wlr.XwaylandSurface) void { pub fn init(self: *Self, xwayland_surface: *wlr.XwaylandSurface) void {
@ -69,7 +80,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
} }
/// Called when the xwayland surface is mapped, or ready to display on-screen. /// Called when the xwayland surface is mapped, or ready to display on-screen.
fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void { pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void {
const self = @fieldParentPtr(Self, "map", listener); const self = @fieldParentPtr(Self, "map", listener);
// Add self to the list of unmanaged views in the root // Add self to the list of unmanaged views in the root
@ -110,3 +121,29 @@ fn handleCommit(_: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
var it = server.root.outputs.first; var it = server.root.outputs.first;
while (it) |node| : (it = node.next) node.data.damage.addWhole(); while (it) |node| : (it = node.next) node.data.damage.addWhole();
} }
fn handleSetOverrideRedirect(
listener: *wl.Listener(*wlr.XwaylandSurface),
xwayland_surface: *wlr.XwaylandSurface,
) void {
const self = @fieldParentPtr(Self, "set_override_redirect", listener);
log.debug("xwayland surface unset override redirect, switching to managed", .{});
assert(!xwayland_surface.override_redirect);
if (xwayland_surface.mapped) handleUnmap(&self.unmap, xwayland_surface);
handleDestroy(&self.destroy, xwayland_surface);
// The View will add itself to the output's view stack on map
const output = server.input_manager.defaultSeat().focused_output;
const node = util.gpa.create(ViewStack(View).Node) catch {
log.err("out of memory", .{});
return;
};
node.view.init(output, xwayland_surface);
if (xwayland_surface.mapped) {
XwaylandView.handleMap(&node.view.impl.xwayland_view.map, xwayland_surface);
}
}

View File

@ -17,16 +17,22 @@
const Self = @This(); const Self = @This();
const std = @import("std"); const std = @import("std");
const assert = std.debug.assert;
const math = std.math; const math = std.math;
const wlr = @import("wlroots"); const wlr = @import("wlroots");
const wl = @import("wayland").server.wl; const wl = @import("wayland").server.wl;
const server = &@import("main.zig").server; const server = &@import("main.zig").server;
const util = @import("util.zig");
const Box = @import("Box.zig"); const Box = @import("Box.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 XdgPopup = @import("XdgPopup.zig"); const XdgPopup = @import("XdgPopup.zig");
const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
const log = std.log.scoped(.xwayland);
/// The view this xwayland view implements /// The view this xwayland view implements
view: *View, view: *View,
@ -45,6 +51,8 @@ map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(
unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap), unmap: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleUnmap),
request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) = request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
wl.Listener(*wlr.XwaylandSurface.event.Configure).init(handleRequestConfigure), wl.Listener(*wlr.XwaylandSurface.event.Configure).init(handleRequestConfigure),
set_override_redirect: wl.Listener(*wlr.XwaylandSurface) =
wl.Listener(*wlr.XwaylandSurface).init(handleSetOverrideRedirect),
// Listeners that are only active while the view is mapped // Listeners that are only active while the view is mapped
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit), commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
@ -176,7 +184,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.XwaylandSurface), _: *wlr.XwaylandS
} }
/// Called when the xwayland surface is mapped, or ready to display on-screen. /// Called when the xwayland surface is mapped, or ready to display on-screen.
fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void { pub fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wlr.XwaylandSurface) void {
const self = @fieldParentPtr(Self, "map", listener); const self = @fieldParentPtr(Self, "map", listener);
const view = self.view; const view = self.view;
@ -223,7 +231,7 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
} }
view.map() catch { view.map() catch {
std.log.err("out of memory", .{}); log.err("out of memory", .{});
surface.resource.getClient().postNoMemory(); surface.resource.getClient().postNoMemory();
}; };
} }
@ -262,6 +270,32 @@ fn handleRequestConfigure(
self.configure(); self.configure();
} }
fn handleSetOverrideRedirect(
listener: *wl.Listener(*wlr.XwaylandSurface),
xwayland_surface: *wlr.XwaylandSurface,
) void {
const self = @fieldParentPtr(Self, "set_override_redirect", listener);
log.debug("xwayland surface set override redirect, switching to unmanaged", .{});
assert(xwayland_surface.override_redirect);
if (xwayland_surface.mapped) handleUnmap(&self.unmap, xwayland_surface);
handleDestroy(&self.destroy, xwayland_surface);
// The unmanged surface will add itself to the list of unmanaged views
// in Root when it is mapped.
const node = util.gpa.create(std.TailQueue(XwaylandUnmanaged).Node) catch {
log.err("out of memory", .{});
return;
};
node.data.init(xwayland_surface);
if (xwayland_surface.mapped) {
XwaylandUnmanaged.handleMap(&node.data.map, xwayland_surface);
}
}
fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void { fn handleCommit(listener: *wl.Listener(*wlr.Surface), surface: *wlr.Surface) void {
const self = @fieldParentPtr(Self, "commit", listener); const self = @fieldParentPtr(Self, "commit", listener);