Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Window: send river_window_v1.parent
river/Window.zig | 22 ++++++++++++++++++++++
river/XdgToplevel.zig | 7 +++++++
2 files changed, 29 insertions(+)
diff --git a/river/Window.zig b/river/Window.zig
index ed71001..50c5e52 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -172,6 +172,7 @@ wm_scheduled: struct {
wm_sent: struct {
dimensions_hint: DimensionsHint = .{},
decoration_hint: river.WindowV1.DecorationHint = .only_supports_csd,
+ parent: ?Window.Ref = null,
} = .{},
/// Windowing state requested by the wm.
@@ -419,6 +420,16 @@ pub fn manageStart(window: *Window) void {
}
scheduled.minimize_requested = false;
+ if (window.getParent()) |parent| {
+ if (sent.parent == null or sent.parent.?.get() != parent) {
+ window_v1.sendParent(parent.object);
+ sent.parent = parent.ref;
+ }
+ } else if (sent.parent != null) {
+ window_v1.sendParent(null);
+ sent.parent = null;
+ }
+
if (new or scheduled.dirty_app_id) {
window_v1.sendAppId(window.getAppId());
scheduled.dirty_app_id = false;
@@ -872,6 +883,17 @@ pub fn destroyPopups(window: Window) void {
}
}
+pub fn getParent(window: *Window) ?*Window {
+ switch (window.impl) {
+ .toplevel => |toplevel| {
+ const wlr_parent = toplevel.wlr_toplevel.parent orelse return null;
+ const parent: *XdgToplevel = @alignCast(@ptrCast(wlr_parent.base.data));
+ return parent.window;
+ },
+ .xwayland, .destroying => return null,
+ }
+}
+
/// Return the current title of the window if any.
pub fn getTitle(window: Window) ?[*:0]const u8 {
return switch (window.impl) {
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 6ff71c0..a90d3ab 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -70,6 +70,7 @@ request_maximize: wl.Listener(void) = .init(handleRequestMaximize),
request_minimize: wl.Listener(void) = .init(handleRequestMinimize),
request_move: wl.Listener(*wlr.XdgToplevel.event.Move) = .init(handleRequestMove),
request_resize: wl.Listener(*wlr.XdgToplevel.event.Resize) = .init(handleRequestResize),
+set_parent: wl.Listener(void) = .init(handleSetParent),
set_title: wl.Listener(void) = .init(handleSetTitle),
set_app_id: wl.Listener(void) = .init(handleSetAppId),
@@ -112,6 +113,7 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
wlr_toplevel.events.request_minimize.add(&toplevel.request_minimize);
wlr_toplevel.events.request_move.add(&toplevel.request_move);
wlr_toplevel.events.request_resize.add(&toplevel.request_resize);
+ wlr_toplevel.events.set_parent.add(&toplevel.set_parent);
wlr_toplevel.events.set_title.add(&toplevel.set_title);
wlr_toplevel.events.set_app_id.add(&toplevel.set_app_id);
}
@@ -237,6 +239,7 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
toplevel.request_minimize.link.remove();
toplevel.request_move.link.remove();
toplevel.request_resize.link.remove();
+ toplevel.set_parent.link.remove();
toplevel.set_title.link.remove();
toplevel.set_app_id.link.remove();
@@ -428,6 +431,10 @@ fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), ev
}
}
+fn handleSetParent(_: *wl.Listener(void)) void {
+ server.wm.dirtyWindowing();
+}
+
/// Called when the client sets / updates its title
fn handleSetTitle(listener: *wl.Listener(void)) void {
const toplevel: *XdgToplevel = @fieldParentPtr("set_title", listener);