aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <mail@isaacfreund.com>2022-05-29 15:16:48 +0200
committerIsaac Freund <mail@isaacfreund.com>2022-05-29 16:28:07 +0200
commit6ef97eea241ecc5bec32e0cf820c3644692f5554 (patch)
treedfc9c2b0c621749a2e6277fe2fa48ebb0f37cf6d
parent8a8dd9ff65fe04d9aad71e0ad8e5e69b6d275ae5 (diff)
downloadriver-6ef97eea241ecc5bec32e0cf820c3644692f5554.tar.gz
river-6ef97eea241ecc5bec32e0cf820c3644692f5554.tar.xz
Xwayland: handle override redirect state changes
-rw-r--r--river/Server.zig9
-rw-r--r--river/View.zig11
-rw-r--r--river/XwaylandUnmanaged.zig39
-rw-r--r--river/XwaylandView.zig38
4 files changed, 84 insertions, 13 deletions
diff --git a/river/Server.zig b/river/Server.zig
index 0a7bd94..e730b5e 100644
--- a/river/Server.zig
+++ b/river/Server.zig
@@ -193,7 +193,7 @@ fn handleNewXdgSurface(listener: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wl
xdg_surface.resource.postNoMemory();
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.
@@ -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
const output = self.input_manager.defaultSeat().focused_output;
const node = util.gpa.create(ViewStack(View).Node) catch return;
- node.view.init(output, getNewViewTags(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;
+ node.view.init(output, wlr_xwayland_surface);
}
diff --git a/river/View.zig b/river/View.zig
index 1a6c0ae..0435e62 100644
--- a/river/View.zig
+++ b/river/View.zig
@@ -126,11 +126,16 @@ foreign_close: wl.Listener(*wlr.ForeignToplevelHandleV1) =
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate) =
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.* = .{
.output = output,
- .current = .{ .tags = tags },
- .pending = .{ .tags = tags },
+ .current = .{ .tags = initial_tags },
+ .pending = .{ .tags = initial_tags },
.saved_buffers = std.ArrayList(SavedBuffer).init(util.gpa),
};
diff --git a/river/XwaylandUnmanaged.zig b/river/XwaylandUnmanaged.zig
index 96f6f3f..4eb6a88 100644
--- a/river/XwaylandUnmanaged.zig
+++ b/river/XwaylandUnmanaged.zig
@@ -17,6 +17,8 @@
const Self = @This();
const std = @import("std");
+const assert = std.debug.assert;
+
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
@@ -24,6 +26,11 @@ const server = &@import("main.zig").server;
const util = @import("util.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
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),
map: wl.Listener(*wlr.XwaylandSurface) = wl.Listener(*wlr.XwaylandSurface).init(handleMap),
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),
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.
-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);
// 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;
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);
+ }
+}
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index 0fbc25a..153ccee 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -17,16 +17,22 @@
const Self = @This();
const std = @import("std");
+const assert = std.debug.assert;
const math = std.math;
+
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const server = &@import("main.zig").server;
+const util = @import("util.zig");
const Box = @import("Box.zig");
const View = @import("View.zig");
const ViewStack = @import("view_stack.zig").ViewStack;
const XdgPopup = @import("XdgPopup.zig");
+const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
+
+const log = std.log.scoped(.xwayland);
/// The view this xwayland view implements
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),
request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
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
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.
-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 view = self.view;
@@ -223,7 +231,7 @@ fn handleMap(listener: *wl.Listener(*wlr.XwaylandSurface), xwayland_surface: *wl
}
view.map() catch {
- std.log.err("out of memory", .{});
+ log.err("out of memory", .{});
surface.resource.getClient().postNoMemory();
};
}
@@ -262,6 +270,32 @@ fn handleRequestConfigure(
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 {
const self = @fieldParentPtr(Self, "commit", listener);