Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
Window: add update sequence machinery
river/Cursor.zig | 3 +-
river/Window.zig | 176 ++++++++++++++++++++++++++++++++++++++++-------
river/WindowManager.zig | 17 ++++-
river/XdgDecoration.zig | 12 ++--
river/XdgToplevel.zig | 44 +++++-------
river/XwaylandWindow.zig | 59 +++++-----------
6 files changed, 207 insertions(+), 104 deletions(-)
diff --git a/river/Cursor.zig b/river/Cursor.zig
index 26cd3a2..e1abbce 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -331,8 +331,7 @@ fn handleButton(listener: *wl.Listener(*wlr.Pointer.event.Button), event: *wlr.P
// If we were in down mode, we need pass along the release event
_ = cursor.seat.wlr_seat.pointerNotifyButton(event.time_msec, event.button, event.state);
},
- .move => {},
- .resize => |data| data.window.pending.resizing = false,
+ .move, .resize => {},
}
cursor.mode = .passthrough;
diff --git a/river/Window.zig b/river/Window.zig
index 5f806b5..d936118 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -69,17 +69,17 @@ pub const State = struct {
};
/// The window management protocol object for this window
-/// If the window is unmapped the "closed" event is sent to the current object.
-/// If the window is remapped a new object is created and sent to the window manager.
-object: ?*river.WindowV1,
+/// Created after the window is ready to be configured.
+/// Lifetime is managed through pending.state
+object: ?*river.WindowV1 = null,
/// The implementation of this window
impl: Impl,
/// Link for WindowManager.windows
link: wl.list.Link,
-/// Link for WindowManager.pending_to_wm.new_windows
-link_new: wl.list.Link,
+/// Link for WindowManager.pending.dirty_windows
+link_dirty: wl.list.Link,
tree: *wlr.SceneTree,
surface_tree: *wlr.SceneTree,
@@ -98,14 +98,35 @@ inflight_transaction: bool = false,
/// transaction completes. See Window.destroy()
destroying: bool = false,
+/// State to be sent to the window manager client in the next update sequence.
pending: struct {
+ state: enum {
+ /// Indicates that there is currently no associated river_window_v1
+ /// object.
+ init,
+ /// Indicates that the window is ready to be configured.
+ /// Create a river_window_v1 object if needed an send events.
+ ready,
+ /// Indicates that the closed event will be sent in the next update sequence.
+ closing,
+ } = .init,
box: wlr.Box = .{ .x = 0, .y = 0, .width = 0, .height = 0 },
-
decoration_hint: river.WindowV1.DecorationHint = .only_supports_csd,
- /// TODO output hint
- fullscreen_requested: bool = false,
+ /// Set back to no_request at the end of each update sequence
+ fullscreen_requested: enum {
+ no_request,
+ /// TODO output hint
+ fullscreen,
+ exit,
+ } = .no_request,
+} = .{},
- resizing: bool = false,
+/// State sent to the window manager client in the latest update sequence.
+/// This state is only kept around in order to avoid sending redundant events
+/// to the window manager client.
+sent: struct {
+ box: wlr.Box = .{ .x = 0, .y = 0, .width = 0, .height = 0 },
+ decoration_hint: river.WindowV1.DecorationHint = .only_supports_csd,
} = .{},
uncommitted: struct {} = .{},
@@ -128,13 +149,6 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
const window = try util.gpa.create(Window);
errdefer util.gpa.destroy(window);
- const object = blk: {
- const wm_v1 = server.wm.object orelse break :blk null;
- break :blk river.WindowV1.create(wm_v1.getClient(), wm_v1.getVersion(), 0) catch
- return error.OutOfMemory;
- };
- errdefer if (object) |o| o.destroy();
-
const tree = try server.root.hidden_tree.createSceneTree();
errdefer tree.node.destroy();
@@ -142,10 +156,9 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
errdefer popup_tree.node.destroy();
window.* = .{
- .object = object,
.impl = impl,
.link = undefined,
- .link_new = undefined,
+ .link_dirty = undefined,
.tree = tree,
.surface_tree = try tree.createSceneTree(),
.saved_surface_tree = try tree.createSceneTree(),
@@ -163,7 +176,7 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
};
server.wm.windows.prepend(window);
- server.wm.pending.new_windows.prepend(window);
+ window.link_dirty.init();
window.uncommitted_render_list_link.init();
window.committed_render_list_link.init();
@@ -185,6 +198,7 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Window {
pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
assert(window.impl == .none);
assert(!window.mapped);
+ assert(window.object == null);
window.destroying = true;
@@ -196,7 +210,7 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
window.popup_tree.node.destroy();
window.link.remove();
- window.link_new.remove();
+ window.link_dirty.remove();
window.uncommitted_render_list_link.remove();
window.committed_render_list_link.remove();
window.inflight_render_list_link.remove();
@@ -212,6 +226,121 @@ pub fn destroy(window: *Window, when: enum { lazy, assert }) void {
}
}
+fn dirtyPending(window: *Window) void {
+ switch (window.pending.state) {
+ .init => {},
+ .ready, .closing => {
+ window.link_dirty.remove();
+ server.wm.pending.dirty_windows.prepend(window);
+ server.wm.dirtyPending();
+ },
+ }
+}
+
+pub fn ready(window: *Window) void {
+ if (window.pending.state != .ready) {
+ window.pending.state = .ready;
+ window.dirtyPending();
+ }
+}
+
+pub fn closing(window: *Window) void {
+ if (window.pending.state != .closing) {
+ window.pending.state = .closing;
+ window.dirtyPending();
+ }
+}
+
+pub fn setDecorationHint(window: *Window, hint: river.WindowV1.DecorationHint) void {
+ window.pending.decoration_hint = hint;
+ if (hint != window.sent.decoration_hint) {
+ window.dirtyPending();
+ }
+}
+
+pub fn setFullscreenRequested(window: *Window, fullscreen_requested: bool) void {
+ if (fullscreen_requested) {
+ window.pending.fullscreen_requested = .fullscreen;
+ } else {
+ window.pending.fullscreen_requested = .exit;
+ }
+ window.dirtyPending();
+}
+
+/// Send dirty pending state as part of an in progress update sequence.
+pub fn sendDirty(window: *Window) !void {
+ assert(window.pending.state != .init);
+
+ switch (window.pending.state) {
+ .init => unreachable,
+ .closing => {
+ window.pending.state = .init;
+ if (window.object) |window_v1| {
+ window.object = null;
+ window_v1.sendClosed();
+ window_v1.setHandler(?*anyopaque, handleRequestInert, null, null);
+ }
+ },
+ .ready => {
+ const wm_v1 = server.wm.object.?;
+ const new = window.object == null;
+ const window_v1 = window.object orelse blk: {
+ const window_v1 = try river.WindowV1.create(wm_v1.getClient(), wm_v1.getVersion(), 0);
+ window.object = window_v1;
+
+ window_v1.setHandler(*Window, handleRequest, null, window);
+
+ wm_v1.sendWindow(window_v1);
+ break :blk window_v1;
+ };
+ errdefer comptime unreachable;
+
+ const pending = &window.pending;
+ const sent = &window.sent;
+
+ // XXX send all dirty pending state
+ if ((pending.box.width != sent.box.width or
+ pending.box.height != sent.box.height) and !pending.box.empty())
+ {
+ window_v1.sendDimensions(window.pending.box.width, window.pending.box.height);
+ sent.box.width = pending.box.width;
+ sent.box.height = pending.box.height;
+ }
+ if (new or pending.decoration_hint != sent.decoration_hint) {
+ window_v1.sendDecorationHint(window.pending.decoration_hint);
+ sent.decoration_hint = pending.decoration_hint;
+ }
+ switch (pending.fullscreen_requested) {
+ .no_request => {},
+ .fullscreen => window_v1.sendFullscreenRequested(null),
+ .exit => window_v1.sendExitFullscreenRequested(),
+ }
+ pending.fullscreen_requested = .no_request;
+ },
+ }
+
+ window.link_dirty.remove();
+ window.link_dirty.init();
+}
+
+fn handleRequestInert(
+ window_v1: *river.WindowV1,
+ request: river.WindowV1.Request,
+ _: ?*anyopaque,
+) void {
+ if (request == .destroy) window_v1.destroy();
+}
+
+fn handleRequest(
+ window_v1: *river.WindowV1,
+ _: river.WindowV1.Request,
+ window: *Window,
+) void {
+ assert(window.object == window_v1);
+ // XXX handle requests
+ //switch (request) {}
+}
+
/// The change in x/y position of the window during resize cannot be determined
/// until the size of the buffer actually committed is known. Clients are permitted
/// by the protocol to take a size smaller than that requested by the compositor in
@@ -484,7 +613,7 @@ pub fn map(window: *Window) !void {
window.foreign_toplevel_handle.map();
- server.wm.dirtyPending();
+ window.ready();
}
/// Called by the impl when the surface will no longer be displayed
@@ -493,15 +622,12 @@ pub fn unmap(window: *Window) void {
if (!window.saved_surface_tree.node.enabled) window.saveSurfaceTree();
- //window.pending_render_list_link.remove();
- //server.root.hidden.pending.render_list.prepend(window);
-
assert(window.mapped and !window.destroying);
window.mapped = false;
window.foreign_toplevel_handle.unmap();
- server.wm.dirtyPending();
+ window.closing();
}
pub fn notifyTitle(window: *const Window) void {
diff --git a/river/WindowManager.zig b/river/WindowManager.zig
index d8d1d21..bc0aeef 100644
--- a/river/WindowManager.zig
+++ b/river/WindowManager.zig
@@ -51,7 +51,7 @@ state: union(enum) {
pending: struct {
/// Pending state has been modified since the last update event sent to the wm.
dirty: bool = false,
- new_windows: wl.list.Head(Window, .link_new),
+ dirty_windows: wl.list.Head(Window, .link_dirty),
},
/// State sent by the wm but not yet committed with a commit request.
@@ -86,7 +86,7 @@ pub fn init(wm: *WindowManager) !void {
.global = try wl.Global.create(server.wl_server, river.WindowManagerV1, 1, *WindowManager, wm, bind),
.windows = undefined,
.pending = .{
- .new_windows = undefined,
+ .dirty_windows = undefined,
},
.uncommitted = .{
.render_list = undefined,
@@ -100,7 +100,7 @@ pub fn init(wm: *WindowManager) !void {
.transaction_timeout = transaction_timeout,
};
wm.windows.init();
- wm.pending.new_windows.init();
+ wm.pending.dirty_windows.init();
wm.uncommitted.render_list.init();
wm.committed.render_list.init();
wm.inflight.render_list.init();
@@ -130,6 +130,7 @@ fn bind(client: *wl.Client, wm: *WindowManager, version: u32, id: u32) void {
wm.object = object;
object.setHandler(*WindowManager, handleRequest, null, wm);
+ // XXX send existing windows?
}
fn handleRequestInert(
@@ -194,6 +195,16 @@ fn sendUpdate(wm: *WindowManager) void {
// XXX send all dirty pending state
+ {
+ var it = wm.pending.dirty_windows.safeIterator(.forward);
+ while (it.next()) |window| {
+ window.sendDirty() catch {
+ log.err("out of memory", .{});
+ continue; // Try again next update
+ };
+ }
+ }
+
wm.pending.dirty = false;
const serial = server.wl_server.nextSerial();
diff --git a/river/XdgDecoration.zig b/river/XdgDecoration.zig
index 0cd57c2..558bd10 100644
--- a/river/XdgDecoration.zig
+++ b/river/XdgDecoration.zig
@@ -75,11 +75,9 @@ fn handleRequestMode(
const toplevel: *XdgToplevel = @ptrFromInt(decoration.wlr_decoration.toplevel.base.data);
const window = toplevel.window;
- switch (decoration.wlr_decoration.requested_mode) {
- .none => window.pending.decoration_hint = .no_preference,
- .client_side => window.pending.decoration_hint = .prefers_csd,
- .server_side => window.pending.decoration_hint = .prefers_ssd,
- }
-
- server.wm.dirtyPending();
+ window.setDecorationHint(switch (decoration.wlr_decoration.requested_mode) {
+ .none => .no_preference,
+ .client_side => .prefers_csd,
+ .server_side => .prefers_ssd,
+ });
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 0ca4a56..3b6eacc 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -64,10 +64,6 @@ map: wl.Listener(void) = wl.Listener(void).init(handleMap),
unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
commit: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleCommit),
new_popup: wl.Listener(*wlr.XdgPopup) = wl.Listener(*wlr.XdgPopup).init(handleNewPopup),
-
-// Listeners that are only active while the window is mapped
-ack_configure: wl.Listener(*wlr.XdgSurface.Configure) =
- wl.Listener(*wlr.XdgSurface.Configure).init(handleAckConfigure),
request_fullscreen: wl.Listener(void) = wl.Listener(void).init(handleRequestFullscreen),
request_move: wl.Listener(*wlr.XdgToplevel.event.Move) =
wl.Listener(*wlr.XdgToplevel.event.Move).init(handleRequestMove),
@@ -76,6 +72,10 @@ request_resize: wl.Listener(*wlr.XdgToplevel.event.Resize) =
set_title: wl.Listener(void) = wl.Listener(void).init(handleSetTitle),
set_app_id: wl.Listener(void) = wl.Listener(void).init(handleSetAppId),
+// Listeners that are only active while the window is mapped
+ack_configure: wl.Listener(*wlr.XdgSurface.Configure) =
+ wl.Listener(*wlr.XdgSurface.Configure).init(handleAckConfigure),
+
pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
const window = try Window.create(.{ .toplevel = .{
.window = undefined,
@@ -108,6 +108,11 @@ pub fn create(wlr_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
wlr_toplevel.base.surface.events.map.add(&toplevel.map);
wlr_toplevel.base.surface.events.commit.add(&toplevel.commit);
wlr_toplevel.base.events.new_popup.add(&toplevel.new_popup);
+ wlr_toplevel.events.request_fullscreen.add(&toplevel.request_fullscreen);
+ wlr_toplevel.events.request_move.add(&toplevel.request_move);
+ wlr_toplevel.events.request_resize.add(&toplevel.request_resize);
+ wlr_toplevel.events.set_title.add(&toplevel.set_title);
+ wlr_toplevel.events.set_app_id.add(&toplevel.set_app_id);
}
/// Send a configure event, applying the inflight state of the window.
@@ -205,12 +210,17 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
}
assert(toplevel.decoration == null);
- // Remove listeners that are active for the entire lifetime of the window
+ // Remove listeners that are active for the entire lifetime of the toplevel
toplevel.destroy.link.remove();
toplevel.map.link.remove();
toplevel.unmap.link.remove();
toplevel.commit.link.remove();
toplevel.new_popup.link.remove();
+ toplevel.request_fullscreen.link.remove();
+ toplevel.request_move.link.remove();
+ toplevel.request_resize.link.remove();
+ toplevel.set_title.link.remove();
+ toplevel.set_app_id.link.remove();
// The wlr_surface may outlive the wlr_xdg_toplevel so we must clean up the user data.
toplevel.wlr_toplevel.base.surface.data = 0;
@@ -226,14 +236,10 @@ fn handleMap(listener: *wl.Listener(void)) void {
// Add listeners that are only active while mapped
toplevel.wlr_toplevel.base.events.ack_configure.add(&toplevel.ack_configure);
- toplevel.wlr_toplevel.events.request_fullscreen.add(&toplevel.request_fullscreen);
- toplevel.wlr_toplevel.events.request_move.add(&toplevel.request_move);
- toplevel.wlr_toplevel.events.request_resize.add(&toplevel.request_resize);
- toplevel.wlr_toplevel.events.set_title.add(&toplevel.set_title);
- toplevel.wlr_toplevel.events.set_app_id.add(&toplevel.set_app_id);
toplevel.wlr_toplevel.base.getGeometry(&toplevel.geometry);
+ // XXX this seems like it should be deleted/moved to handleCommit()
window.pending.box = .{
.x = 0,
.y = 0,
@@ -243,8 +249,6 @@ fn handleMap(listener: *wl.Listener(void)) void {
window.inflight.box = window.pending.box;
window.current.box = window.pending.box;
- toplevel.window.pending.fullscreen_requested = toplevel.wlr_toplevel.requested.fullscreen;
-
window.map() catch {
log.err("out of memory", .{});
toplevel.wlr_toplevel.resource.getClient().postNoMemory();
@@ -257,11 +261,6 @@ fn handleUnmap(listener: *wl.Listener(void)) void {
// Remove listeners that are only active while mapped
toplevel.ack_configure.link.remove();
- toplevel.request_fullscreen.link.remove();
- toplevel.request_move.link.remove();
- toplevel.request_resize.link.remove();
- toplevel.set_title.link.remove();
- toplevel.set_app_id.link.remove();
toplevel.window.unmap();
}
@@ -296,9 +295,7 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
const window = toplevel.window;
if (toplevel.wlr_toplevel.base.initial_commit) {
- _ = toplevel.wlr_toplevel.setWmCapabilities(.{ .fullscreen = true });
-
- // XXX I think this is where we actually want to send the new window event.
+ window.ready();
return;
}
@@ -389,14 +386,9 @@ fn handleCommit(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
}
}
-/// Called when the client asks to be fullscreened. We always honor the request
-/// for now, perhaps it should be denied in some cases in the future.
fn handleRequestFullscreen(listener: *wl.Listener(void)) void {
const toplevel: *XdgToplevel = @fieldParentPtr("request_fullscreen", listener);
- if (toplevel.window.pending.fullscreen_requested != toplevel.wlr_toplevel.requested.fullscreen) {
- toplevel.window.pending.fullscreen_requested = toplevel.wlr_toplevel.requested.fullscreen;
- server.wm.dirtyPending();
- }
+ toplevel.window.setFullscreenRequested(toplevel.wlr_toplevel.requested.fullscreen);
}
fn handleRequestMove(
diff --git a/river/XwaylandWindow.zig b/river/XwaylandWindow.zig
index e51f3f6..97a28b0 100644
--- a/river/XwaylandWindow.zig
+++ b/river/XwaylandWindow.zig
@@ -46,12 +46,6 @@ request_configure: wl.Listener(*wlr.XwaylandSurface.event.Configure) =
set_override_redirect: wl.Listener(void) = wl.Listener(void).init(handleSetOverrideRedirect),
associate: wl.Listener(void) = wl.Listener(void).init(handleAssociate),
dissociate: wl.Listener(void) = wl.Listener(void).init(handleDissociate),
-
-// Active while the xwayland_surface is associated with a wlr_surface
-map: wl.Listener(void) = wl.Listener(void).init(handleMap),
-unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
-
-// Active while mapped
set_title: wl.Listener(void) = wl.Listener(void).init(handleSetTitle),
set_class: wl.Listener(void) = wl.Listener(void).init(handleSetClass),
set_decorations: wl.Listener(void) = wl.Listener(void).init(handleSetDecorations),
@@ -59,6 +53,10 @@ request_fullscreen: wl.Listener(void) = wl.Listener(void).init(handleRequestFull
request_minimize: wl.Listener(*wlr.XwaylandSurface.event.Minimize) =
wl.Listener(*wlr.XwaylandSurface.event.Minimize).init(handleRequestMinimize),
+// Active while the xwayland_surface is associated with a wlr_surface
+map: wl.Listener(void) = wl.Listener(void).init(handleMap),
+unmap: wl.Listener(void) = wl.Listener(void).init(handleUnmap),
+
pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
const window = try Window.create(.{ .xwayland_window = .{
.window = undefined,
@@ -75,6 +73,11 @@ pub fn create(xwayland_surface: *wlr.XwaylandSurface) error{OutOfMemory}!void {
xwayland_surface.events.dissociate.add(&xwayland_window.dissociate);
xwayland_surface.events.request_configure.add(&xwayland_window.request_configure);
xwayland_surface.events.set_override_redirect.add(&xwayland_window.set_override_redirect);
+ xwayland_surface.events.set_title.add(&xwayland_window.set_title);
+ xwayland_surface.events.set_class.add(&xwayland_window.set_class);
+ xwayland_surface.events.set_decorations.add(&xwayland_window.set_decorations);
+ xwayland_surface.events.request_fullscreen.add(&xwayland_window.request_fullscreen);
+ xwayland_surface.events.request_minimize.add(&xwayland_window.request_minimize);
if (xwayland_surface.surface) |surface| {
handleAssociate(&xwayland_window.associate);
@@ -133,6 +136,11 @@ fn handleDestroy(listener: *wl.Listener(void)) void {
xwayland_window.dissociate.link.remove();
xwayland_window.request_configure.link.remove();
xwayland_window.set_override_redirect.link.remove();
+ xwayland_window.set_title.link.remove();
+ xwayland_window.set_class.link.remove();
+ xwayland_window.set_decorations.link.remove();
+ xwayland_window.request_fullscreen.link.remove();
+ xwayland_window.request_minimize.link.remove();
const window = xwayland_window.window;
window.impl = .none;
@@ -160,19 +168,13 @@ pub fn handleMap(listener: *wl.Listener(void)) void {
const surface = xwayland_surface.surface.?;
surface.data = @intFromPtr(&window.tree.node);
- // Add listeners that are only active while mapped
- xwayland_surface.events.set_title.add(&xwayland_window.set_title);
- xwayland_surface.events.set_class.add(&xwayland_window.set_class);
- xwayland_surface.events.set_decorations.add(&xwayland_window.set_decorations);
- xwayland_surface.events.request_fullscreen.add(&xwayland_window.request_fullscreen);
- xwayland_surface.events.request_minimize.add(&xwayland_window.request_minimize);
-
xwayland_window.surface_tree = window.surface_tree.createSceneSubsurfaceTree(surface) catch {
log.err("out of memory", .{});
surface.resource.getClient().postNoMemory();
return;
};
+ // XXX this seems like it should be deleted/moved to handleCommit()
window.pending.box = .{
.x = 0,
.y = 0,
@@ -182,16 +184,6 @@ pub fn handleMap(listener: *wl.Listener(void)) void {
window.inflight.box = window.pending.box;
window.current.box = window.pending.box;
- if (xwayland_surface.decorations.no_border or
- xwayland_surface.decorations.no_title)
- {
- window.pending.decoration_hint = .prefers_csd;
- } else {
- window.pending.decoration_hint = .prefers_ssd;
- }
-
- window.pending.fullscreen_requested = xwayland_surface.fullscreen;
-
window.map() catch {
log.err("out of memory", .{});
surface.resource.getClient().postNoMemory();
@@ -203,12 +195,6 @@ fn handleUnmap(listener: *wl.Listener(void)) void {
xwayland_window.xwayland_surface.surface.?.data = 0;
- // Remove listeners that are only active while mapped
- xwayland_window.set_title.link.remove();
- xwayland_window.set_class.link.remove();
- xwayland_window.request_fullscreen.link.remove();
- xwayland_window.request_minimize.link.remove();
-
xwayland_window.window.unmap();
// Don't destroy the surface tree until after Window.unmap() has a chance
@@ -271,28 +257,19 @@ fn handleSetClass(listener: *wl.Listener(void)) void {
fn handleSetDecorations(listener: *wl.Listener(void)) void {
const xwayland_window: *XwaylandWindow = @fieldParentPtr("set_decorations", listener);
- const window = xwayland_window.window;
if (xwayland_window.xwayland_surface.decorations.no_border or
xwayland_window.xwayland_surface.decorations.no_title)
{
- window.pending.decoration_hint = .prefers_csd;
+ xwayland_window.window.setDecorationHint(.prefers_csd);
} else {
- window.pending.decoration_hint = .prefers_ssd;
+ xwayland_window.window.setDecorationHint(.prefers_ssd);
}
-
- server.wm.dirtyPending();
}
fn handleRequestFullscreen(listener: *wl.Listener(void)) void {
const xwayland_window: *XwaylandWindow = @fieldParentPtr("request_fullscreen", listener);
- const window = xwayland_window.window;
- const xwayland_surface = xwayland_window.xwayland_surface;
-
- if (window.pending.fullscreen_requested != xwayland_surface.fullscreen) {
- window.pending.fullscreen_requested = xwayland_surface.fullscreen;
- server.wm.dirtyPending();
- }
+ xwayland_window.window.setFullscreenRequested(xwayland_window.xwayland_surface.fullscreen);
}
/// Some X11 clients will minimize themselves regardless of how we respond.