xdg-decoration: clean up implementation
We now send some protocol errors that wlroots 0.16 is missing [1]. This also allows us to access the xdg decoration from a view, which will be necessary for some future changes. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4051
This commit is contained in:
parent
fcb184f0bd
commit
05eac54b07
@ -91,6 +91,7 @@ pub fn build(b: *zbs.Builder) !void {
|
|||||||
scanner.addSystemProtocol("staging/ext-session-lock/ext-session-lock-v1.xml");
|
scanner.addSystemProtocol("staging/ext-session-lock/ext-session-lock-v1.xml");
|
||||||
scanner.addSystemProtocol("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml");
|
scanner.addSystemProtocol("unstable/pointer-gestures/pointer-gestures-unstable-v1.xml");
|
||||||
scanner.addSystemProtocol("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml");
|
scanner.addSystemProtocol("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml");
|
||||||
|
scanner.addSystemProtocol("unstable/xdg-decoration/xdg-decoration-unstable-v1.xml");
|
||||||
scanner.addProtocolPath("protocol/river-control-unstable-v1.xml");
|
scanner.addProtocolPath("protocol/river-control-unstable-v1.xml");
|
||||||
scanner.addProtocolPath("protocol/river-status-unstable-v1.xml");
|
scanner.addProtocolPath("protocol/river-status-unstable-v1.xml");
|
||||||
scanner.addProtocolPath("protocol/river-layout-v3.xml");
|
scanner.addProtocolPath("protocol/river-layout-v3.xml");
|
||||||
@ -109,6 +110,7 @@ pub fn build(b: *zbs.Builder) !void {
|
|||||||
scanner.generate("xdg_wm_base", 2);
|
scanner.generate("xdg_wm_base", 2);
|
||||||
scanner.generate("zwp_pointer_gestures_v1", 3);
|
scanner.generate("zwp_pointer_gestures_v1", 3);
|
||||||
scanner.generate("zwp_pointer_constraints_v1", 1);
|
scanner.generate("zwp_pointer_constraints_v1", 1);
|
||||||
|
scanner.generate("zxdg_decoration_manager_v1", 1);
|
||||||
scanner.generate("ext_session_lock_manager_v1", 1);
|
scanner.generate("ext_session_lock_manager_v1", 1);
|
||||||
|
|
||||||
scanner.generate("zriver_control_v1", 1);
|
scanner.generate("zriver_control_v1", 1);
|
||||||
|
2
deps/zig-wlroots
vendored
2
deps/zig-wlroots
vendored
@ -1 +1 @@
|
|||||||
Subproject commit f804c6d2ab1a240f7659c82325dc21ddcc6392b7
|
Subproject commit c4cdb08505de19f6bfbf8e1825349b80c7696475
|
@ -1,70 +0,0 @@
|
|||||||
// This file is part of river, a dynamic tiling wayland compositor.
|
|
||||||
//
|
|
||||||
// Copyright 2020 The River Developers
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 3.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const wlr = @import("wlroots");
|
|
||||||
const wl = @import("wayland").server.wl;
|
|
||||||
|
|
||||||
const server = &@import("main.zig").server;
|
|
||||||
const util = @import("util.zig");
|
|
||||||
|
|
||||||
const Server = @import("Server.zig");
|
|
||||||
const View = @import("View.zig");
|
|
||||||
|
|
||||||
xdg_toplevel_decoration: *wlr.XdgToplevelDecorationV1,
|
|
||||||
|
|
||||||
destroy: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
|
||||||
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleDestroy),
|
|
||||||
request_mode: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
|
||||||
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleRequestMode),
|
|
||||||
|
|
||||||
pub fn init(self: *Self, xdg_toplevel_decoration: *wlr.XdgToplevelDecorationV1) void {
|
|
||||||
self.* = .{ .xdg_toplevel_decoration = xdg_toplevel_decoration };
|
|
||||||
|
|
||||||
xdg_toplevel_decoration.events.destroy.add(&self.destroy);
|
|
||||||
xdg_toplevel_decoration.events.request_mode.add(&self.request_mode);
|
|
||||||
|
|
||||||
handleRequestMode(&self.request_mode, self.xdg_toplevel_decoration);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handleDestroy(
|
|
||||||
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
|
||||||
_: *wlr.XdgToplevelDecorationV1,
|
|
||||||
) void {
|
|
||||||
const self = @fieldParentPtr(Self, "destroy", listener);
|
|
||||||
self.destroy.link.remove();
|
|
||||||
self.request_mode.link.remove();
|
|
||||||
|
|
||||||
const node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
|
|
||||||
server.decoration_manager.decorations.remove(node);
|
|
||||||
util.gpa.destroy(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handleRequestMode(
|
|
||||||
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
|
||||||
_: *wlr.XdgToplevelDecorationV1,
|
|
||||||
) void {
|
|
||||||
const self = @fieldParentPtr(Self, "request_mode", listener);
|
|
||||||
|
|
||||||
const view = @intToPtr(*View, self.xdg_toplevel_decoration.surface.data);
|
|
||||||
if (server.config.csdAllowed(view)) {
|
|
||||||
_ = self.xdg_toplevel_decoration.setMode(.client_side);
|
|
||||||
} else {
|
|
||||||
_ = self.xdg_toplevel_decoration.setMode(.server_side);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
// This file is part of river, a dynamic tiling wayland compositor.
|
|
||||||
//
|
|
||||||
// Copyright 2020 The River Developers
|
|
||||||
//
|
|
||||||
// This program is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, version 3.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
const std = @import("std");
|
|
||||||
const wlr = @import("wlroots");
|
|
||||||
const wl = @import("wayland").server.wl;
|
|
||||||
|
|
||||||
const server = &@import("main.zig").server;
|
|
||||||
const util = @import("util.zig");
|
|
||||||
|
|
||||||
const Decoration = @import("Decoration.zig");
|
|
||||||
const Server = @import("Server.zig");
|
|
||||||
|
|
||||||
/// List of all Decoration objects. This will clean itself up on exit through
|
|
||||||
/// the wlr.XdgToplevelDecorationV1.events.destroy event.
|
|
||||||
decorations: std.TailQueue(Decoration) = .{},
|
|
||||||
|
|
||||||
xdg_decoration_manager: *wlr.XdgDecorationManagerV1,
|
|
||||||
|
|
||||||
new_toplevel_decoration: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
|
||||||
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleNewToplevelDecoration),
|
|
||||||
|
|
||||||
pub fn init(self: *Self) !void {
|
|
||||||
self.* = .{
|
|
||||||
.xdg_decoration_manager = try wlr.XdgDecorationManagerV1.create(server.wl_server),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.xdg_decoration_manager.events.new_toplevel_decoration.add(&self.new_toplevel_decoration);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handleNewToplevelDecoration(
|
|
||||||
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
|
||||||
xdg_toplevel_decoration: *wlr.XdgToplevelDecorationV1,
|
|
||||||
) void {
|
|
||||||
const self = @fieldParentPtr(Self, "new_toplevel_decoration", listener);
|
|
||||||
const decoration_node = util.gpa.create(std.TailQueue(Decoration).Node) catch {
|
|
||||||
xdg_toplevel_decoration.resource.postNoMemory();
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
decoration_node.data.init(xdg_toplevel_decoration);
|
|
||||||
self.decorations.append(decoration_node);
|
|
||||||
}
|
|
@ -11,7 +11,7 @@ const IdleInhibitorManager = @import("IdleInhibitorManager.zig");
|
|||||||
|
|
||||||
inhibitor_manager: *IdleInhibitorManager,
|
inhibitor_manager: *IdleInhibitorManager,
|
||||||
inhibitor: *wlr.IdleInhibitorV1,
|
inhibitor: *wlr.IdleInhibitorV1,
|
||||||
destroy: wl.Listener(*wlr.IdleInhibitorV1) = wl.Listener(*wlr.IdleInhibitorV1).init(handleDestroy),
|
destroy: wl.Listener(*wlr.Surface) = wl.Listener(*wlr.Surface).init(handleDestroy),
|
||||||
|
|
||||||
pub fn init(self: *Self, inhibitor: *wlr.IdleInhibitorV1, inhibitor_manager: *IdleInhibitorManager) !void {
|
pub fn init(self: *Self, inhibitor: *wlr.IdleInhibitorV1, inhibitor_manager: *IdleInhibitorManager) !void {
|
||||||
self.inhibitor_manager = inhibitor_manager;
|
self.inhibitor_manager = inhibitor_manager;
|
||||||
@ -22,7 +22,7 @@ pub fn init(self: *Self, inhibitor: *wlr.IdleInhibitorV1, inhibitor_manager: *Id
|
|||||||
inhibitor_manager.idleInhibitCheckActive();
|
inhibitor_manager.idleInhibitCheckActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleDestroy(listener: *wl.Listener(*wlr.IdleInhibitorV1), _: *wlr.IdleInhibitorV1) void {
|
fn handleDestroy(listener: *wl.Listener(*wlr.Surface), _: *wlr.Surface) void {
|
||||||
const self = @fieldParentPtr(Self, "destroy", listener);
|
const self = @fieldParentPtr(Self, "destroy", listener);
|
||||||
self.destroy.link.remove();
|
self.destroy.link.remove();
|
||||||
|
|
||||||
|
@ -71,6 +71,8 @@ hidden: struct {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
views: wl.list.Head(View, .link),
|
||||||
|
|
||||||
new_output: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleNewOutput),
|
new_output: wl.Listener(*wlr.Output) = wl.Listener(*wlr.Output).init(handleNewOutput),
|
||||||
|
|
||||||
output_layout: *wlr.OutputLayout,
|
output_layout: *wlr.OutputLayout,
|
||||||
@ -146,6 +148,7 @@ pub fn init(self: *Self) !void {
|
|||||||
.wm_stack = undefined,
|
.wm_stack = undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.views = undefined,
|
||||||
.output_layout = output_layout,
|
.output_layout = output_layout,
|
||||||
.output_manager = try wlr.OutputManagerV1.create(server.wl_server),
|
.output_manager = try wlr.OutputManagerV1.create(server.wl_server),
|
||||||
.power_manager = try wlr.OutputPowerManagerV1.create(server.wl_server),
|
.power_manager = try wlr.OutputPowerManagerV1.create(server.wl_server),
|
||||||
@ -155,6 +158,7 @@ pub fn init(self: *Self) !void {
|
|||||||
self.hidden.pending.wm_stack.init();
|
self.hidden.pending.wm_stack.init();
|
||||||
self.hidden.inflight.focus_stack.init();
|
self.hidden.inflight.focus_stack.init();
|
||||||
self.hidden.inflight.wm_stack.init();
|
self.hidden.inflight.wm_stack.init();
|
||||||
|
self.views.init();
|
||||||
|
|
||||||
server.backend.events.new_output.add(&self.new_output);
|
server.backend.events.new_output.add(&self.new_output);
|
||||||
self.output_manager.events.apply.add(&self.manager_apply);
|
self.output_manager.events.apply.add(&self.manager_apply);
|
||||||
|
@ -26,7 +26,6 @@ const util = @import("util.zig");
|
|||||||
|
|
||||||
const Config = @import("Config.zig");
|
const Config = @import("Config.zig");
|
||||||
const Control = @import("Control.zig");
|
const Control = @import("Control.zig");
|
||||||
const DecorationManager = @import("DecorationManager.zig");
|
|
||||||
const IdleInhibitorManager = @import("IdleInhibitorManager.zig");
|
const IdleInhibitorManager = @import("IdleInhibitorManager.zig");
|
||||||
const InputManager = @import("InputManager.zig");
|
const InputManager = @import("InputManager.zig");
|
||||||
const LayerSurface = @import("LayerSurface.zig");
|
const LayerSurface = @import("LayerSurface.zig");
|
||||||
@ -36,6 +35,7 @@ const Output = @import("Output.zig");
|
|||||||
const Root = @import("Root.zig");
|
const Root = @import("Root.zig");
|
||||||
const SceneNodeData = @import("SceneNodeData.zig");
|
const SceneNodeData = @import("SceneNodeData.zig");
|
||||||
const StatusManager = @import("StatusManager.zig");
|
const StatusManager = @import("StatusManager.zig");
|
||||||
|
const XdgDecoration = @import("XdgDecoration.zig");
|
||||||
const XdgToplevel = @import("XdgToplevel.zig");
|
const XdgToplevel = @import("XdgToplevel.zig");
|
||||||
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
|
const XwaylandOverrideRedirect = @import("XwaylandOverrideRedirect.zig");
|
||||||
const XwaylandView = @import("XwaylandView.zig");
|
const XwaylandView = @import("XwaylandView.zig");
|
||||||
@ -55,6 +55,9 @@ allocator: *wlr.Allocator,
|
|||||||
xdg_shell: *wlr.XdgShell,
|
xdg_shell: *wlr.XdgShell,
|
||||||
new_xdg_surface: wl.Listener(*wlr.XdgSurface),
|
new_xdg_surface: wl.Listener(*wlr.XdgSurface),
|
||||||
|
|
||||||
|
xdg_decoration_manager: *wlr.XdgDecorationManagerV1,
|
||||||
|
new_toplevel_decoration: wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||||
|
|
||||||
layer_shell: *wlr.LayerShellV1,
|
layer_shell: *wlr.LayerShellV1,
|
||||||
new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1),
|
new_layer_surface: wl.Listener(*wlr.LayerSurfaceV1),
|
||||||
|
|
||||||
@ -66,7 +69,6 @@ foreign_toplevel_manager: *wlr.ForeignToplevelManagerV1,
|
|||||||
xdg_activation: *wlr.XdgActivationV1,
|
xdg_activation: *wlr.XdgActivationV1,
|
||||||
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
|
request_activate: wl.Listener(*wlr.XdgActivationV1.event.RequestActivate),
|
||||||
|
|
||||||
decoration_manager: DecorationManager,
|
|
||||||
input_manager: InputManager,
|
input_manager: InputManager,
|
||||||
root: Root,
|
root: Root,
|
||||||
config: Config,
|
config: Config,
|
||||||
@ -103,6 +105,10 @@ pub fn init(self: *Self) !void {
|
|||||||
self.new_xdg_surface.setNotify(handleNewXdgSurface);
|
self.new_xdg_surface.setNotify(handleNewXdgSurface);
|
||||||
self.xdg_shell.events.new_surface.add(&self.new_xdg_surface);
|
self.xdg_shell.events.new_surface.add(&self.new_xdg_surface);
|
||||||
|
|
||||||
|
self.xdg_decoration_manager = try wlr.XdgDecorationManagerV1.create(self.wl_server);
|
||||||
|
self.new_toplevel_decoration.setNotify(handleNewToplevelDecoration);
|
||||||
|
self.xdg_decoration_manager.events.new_toplevel_decoration.add(&self.new_toplevel_decoration);
|
||||||
|
|
||||||
self.layer_shell = try wlr.LayerShellV1.create(self.wl_server);
|
self.layer_shell = try wlr.LayerShellV1.create(self.wl_server);
|
||||||
self.new_layer_surface.setNotify(handleNewLayerSurface);
|
self.new_layer_surface.setNotify(handleNewLayerSurface);
|
||||||
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
self.layer_shell.events.new_surface.add(&self.new_layer_surface);
|
||||||
@ -122,7 +128,6 @@ pub fn init(self: *Self) !void {
|
|||||||
_ = try wlr.PrimarySelectionDeviceManagerV1.create(self.wl_server);
|
_ = try wlr.PrimarySelectionDeviceManagerV1.create(self.wl_server);
|
||||||
|
|
||||||
self.config = try Config.init();
|
self.config = try Config.init();
|
||||||
try self.decoration_manager.init();
|
|
||||||
try self.root.init();
|
try self.root.init();
|
||||||
// Must be called after root is initialized
|
// Must be called after root is initialized
|
||||||
try self.input_manager.init();
|
try self.input_manager.init();
|
||||||
@ -205,6 +210,24 @@ fn handleNewXdgSurface(_: *wl.Listener(*wlr.XdgSurface), xdg_surface: *wlr.XdgSu
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handleNewToplevelDecoration(
|
||||||
|
_: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||||
|
wlr_decoration: *wlr.XdgToplevelDecorationV1,
|
||||||
|
) void {
|
||||||
|
const xdg_toplevel = @intToPtr(*XdgToplevel, wlr_decoration.surface.data);
|
||||||
|
|
||||||
|
// TODO(wlroots): The next wlroots version will handle this for us
|
||||||
|
if (xdg_toplevel.decoration != null) {
|
||||||
|
wlr_decoration.resource.postError(
|
||||||
|
.already_constructed,
|
||||||
|
"xdg_toplevel already has a decoration object",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XdgDecoration.init(wlr_decoration);
|
||||||
|
}
|
||||||
|
|
||||||
fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
fn handleNewLayerSurface(listener: *wl.Listener(*wlr.LayerSurfaceV1), wlr_layer_surface: *wlr.LayerSurfaceV1) void {
|
||||||
const self = @fieldParentPtr(Self, "new_layer_surface", listener);
|
const self = @fieldParentPtr(Self, "new_layer_surface", listener);
|
||||||
|
|
||||||
|
@ -117,6 +117,9 @@ pub const State = struct {
|
|||||||
/// The implementation of this view
|
/// The implementation of this view
|
||||||
impl: Impl,
|
impl: Impl,
|
||||||
|
|
||||||
|
/// Link for Root.views
|
||||||
|
link: wl.list.Link,
|
||||||
|
|
||||||
tree: *wlr.SceneTree,
|
tree: *wlr.SceneTree,
|
||||||
surface_tree: *wlr.SceneTree,
|
surface_tree: *wlr.SceneTree,
|
||||||
saved_surface_tree: *wlr.SceneTree,
|
saved_surface_tree: *wlr.SceneTree,
|
||||||
@ -182,6 +185,7 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Self {
|
|||||||
|
|
||||||
view.* = .{
|
view.* = .{
|
||||||
.impl = impl,
|
.impl = impl,
|
||||||
|
.link = undefined,
|
||||||
.tree = tree,
|
.tree = tree,
|
||||||
.surface_tree = try tree.createSceneTree(),
|
.surface_tree = try tree.createSceneTree(),
|
||||||
.saved_surface_tree = try tree.createSceneTree(),
|
.saved_surface_tree = try tree.createSceneTree(),
|
||||||
@ -199,6 +203,7 @@ pub fn create(impl: Impl) error{OutOfMemory}!*Self {
|
|||||||
.inflight_focus_stack_link = undefined,
|
.inflight_focus_stack_link = undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
server.root.views.prepend(view);
|
||||||
server.root.hidden.pending.focus_stack.prepend(view);
|
server.root.hidden.pending.focus_stack.prepend(view);
|
||||||
server.root.hidden.pending.wm_stack.prepend(view);
|
server.root.hidden.pending.wm_stack.prepend(view);
|
||||||
server.root.hidden.inflight.focus_stack.prepend(view);
|
server.root.hidden.inflight.focus_stack.prepend(view);
|
||||||
@ -229,6 +234,7 @@ pub fn destroy(view: *Self) void {
|
|||||||
view.tree.node.destroy();
|
view.tree.node.destroy();
|
||||||
view.popup_tree.node.destroy();
|
view.popup_tree.node.destroy();
|
||||||
|
|
||||||
|
view.link.remove();
|
||||||
view.pending_focus_stack_link.remove();
|
view.pending_focus_stack_link.remove();
|
||||||
view.pending_wm_stack_link.remove();
|
view.pending_wm_stack_link.remove();
|
||||||
view.inflight_focus_stack_link.remove();
|
view.inflight_focus_stack_link.remove();
|
||||||
|
80
river/XdgDecoration.zig
Normal file
80
river/XdgDecoration.zig
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// This file is part of river, a dynamic tiling wayland compositor.
|
||||||
|
//
|
||||||
|
// Copyright 2023 The River Developers
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, version 3.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
const XdgDecoration = @This();
|
||||||
|
|
||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const wlr = @import("wlroots");
|
||||||
|
const wl = @import("wayland").server.wl;
|
||||||
|
|
||||||
|
const server = &@import("main.zig").server;
|
||||||
|
const util = @import("util.zig");
|
||||||
|
|
||||||
|
const XdgToplevel = @import("XdgToplevel.zig");
|
||||||
|
|
||||||
|
wlr_decoration: *wlr.XdgToplevelDecorationV1,
|
||||||
|
|
||||||
|
destroy: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
||||||
|
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleDestroy),
|
||||||
|
request_mode: wl.Listener(*wlr.XdgToplevelDecorationV1) =
|
||||||
|
wl.Listener(*wlr.XdgToplevelDecorationV1).init(handleRequestMode),
|
||||||
|
|
||||||
|
pub fn init(wlr_decoration: *wlr.XdgToplevelDecorationV1) void {
|
||||||
|
const xdg_toplevel = @intToPtr(*XdgToplevel, wlr_decoration.surface.data);
|
||||||
|
|
||||||
|
xdg_toplevel.decoration = .{ .wlr_decoration = wlr_decoration };
|
||||||
|
const decoration = &xdg_toplevel.decoration.?;
|
||||||
|
|
||||||
|
wlr_decoration.events.destroy.add(&decoration.destroy);
|
||||||
|
wlr_decoration.events.request_mode.add(&decoration.request_mode);
|
||||||
|
|
||||||
|
handleRequestMode(&decoration.request_mode, decoration.wlr_decoration);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(wlroots): remove this function when updating to 0.17.0
|
||||||
|
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4051
|
||||||
|
pub fn deinit(decoration: *XdgDecoration) void {
|
||||||
|
decoration.destroy.link.remove();
|
||||||
|
decoration.request_mode.link.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleDestroy(
|
||||||
|
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||||
|
_: *wlr.XdgToplevelDecorationV1,
|
||||||
|
) void {
|
||||||
|
const decoration = @fieldParentPtr(XdgDecoration, "destroy", listener);
|
||||||
|
const xdg_toplevel = @intToPtr(*XdgToplevel, decoration.wlr_decoration.surface.data);
|
||||||
|
|
||||||
|
decoration.deinit();
|
||||||
|
|
||||||
|
assert(xdg_toplevel.decoration != null);
|
||||||
|
xdg_toplevel.decoration = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handleRequestMode(
|
||||||
|
listener: *wl.Listener(*wlr.XdgToplevelDecorationV1),
|
||||||
|
_: *wlr.XdgToplevelDecorationV1,
|
||||||
|
) void {
|
||||||
|
const decoration = @fieldParentPtr(XdgDecoration, "request_mode", listener);
|
||||||
|
|
||||||
|
const xdg_toplevel = @intToPtr(*XdgToplevel, decoration.wlr_decoration.surface.data);
|
||||||
|
if (server.config.csdAllowed(xdg_toplevel.view)) {
|
||||||
|
_ = decoration.wlr_decoration.setMode(.client_side);
|
||||||
|
} else {
|
||||||
|
_ = decoration.wlr_decoration.setMode(.server_side);
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@ const Output = @import("Output.zig");
|
|||||||
const Seat = @import("Seat.zig");
|
const Seat = @import("Seat.zig");
|
||||||
const XdgPopup = @import("XdgPopup.zig");
|
const XdgPopup = @import("XdgPopup.zig");
|
||||||
const View = @import("View.zig");
|
const View = @import("View.zig");
|
||||||
|
const XdgDecoration = @import("XdgDecoration.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.xdg_shell);
|
const log = std.log.scoped(.xdg_shell);
|
||||||
|
|
||||||
@ -37,6 +38,8 @@ view: *View,
|
|||||||
|
|
||||||
xdg_toplevel: *wlr.XdgToplevel,
|
xdg_toplevel: *wlr.XdgToplevel,
|
||||||
|
|
||||||
|
decoration: ?XdgDecoration = null,
|
||||||
|
|
||||||
/// Initialized on map
|
/// Initialized on map
|
||||||
geometry: wlr.Box = undefined,
|
geometry: wlr.Box = undefined,
|
||||||
|
|
||||||
@ -74,15 +77,15 @@ pub fn create(xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory}!void {
|
|||||||
} });
|
} });
|
||||||
errdefer view.destroy();
|
errdefer view.destroy();
|
||||||
|
|
||||||
view.impl.xdg_toplevel.view = view;
|
|
||||||
|
|
||||||
_ = try view.surface_tree.createSceneXdgSurface(xdg_toplevel.base);
|
_ = 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;
|
const self = &view.impl.xdg_toplevel;
|
||||||
|
|
||||||
|
self.view = view;
|
||||||
|
|
||||||
|
xdg_toplevel.base.data = @ptrToInt(self);
|
||||||
|
|
||||||
|
// Add listeners that are active over the toplevel's entire lifetime
|
||||||
xdg_toplevel.base.events.destroy.add(&self.destroy);
|
xdg_toplevel.base.events.destroy.add(&self.destroy);
|
||||||
xdg_toplevel.base.events.map.add(&self.map);
|
xdg_toplevel.base.events.map.add(&self.map);
|
||||||
xdg_toplevel.base.events.unmap.add(&self.unmap);
|
xdg_toplevel.base.events.unmap.add(&self.unmap);
|
||||||
@ -170,6 +173,17 @@ pub fn destroyPopups(self: Self) void {
|
|||||||
fn handleDestroy(listener: *wl.Listener(void)) void {
|
fn handleDestroy(listener: *wl.Listener(void)) void {
|
||||||
const self = @fieldParentPtr(Self, "destroy", listener);
|
const self = @fieldParentPtr(Self, "destroy", listener);
|
||||||
|
|
||||||
|
// TODO(wlroots): Replace this with an assertion when updating to wlroots 0.17.0
|
||||||
|
// https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4051
|
||||||
|
if (self.decoration) |*decoration| {
|
||||||
|
decoration.wlr_decoration.resource.postError(
|
||||||
|
.orphaned,
|
||||||
|
"xdg_toplevel destroyed before xdg_toplevel_decoration",
|
||||||
|
);
|
||||||
|
decoration.deinit();
|
||||||
|
self.decoration = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove listeners that are active for the entire lifetime of the view
|
// Remove listeners that are active for the entire lifetime of the view
|
||||||
self.destroy.link.remove();
|
self.destroy.link.remove();
|
||||||
self.map.link.remove();
|
self.map.link.remove();
|
||||||
|
@ -116,24 +116,25 @@ pub fn csdFilterRemove(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn csdFilterUpdateViews(kind: FilterKind, pattern: []const u8, operation: enum { add, remove }) void {
|
fn csdFilterUpdateViews(kind: FilterKind, pattern: []const u8, operation: enum { add, remove }) void {
|
||||||
var decoration_it = server.decoration_manager.decorations.first;
|
var it = server.root.views.iterator(.forward);
|
||||||
while (decoration_it) |decoration_node| : (decoration_it = decoration_node.next) {
|
while (it.next()) |view| {
|
||||||
const xdg_toplevel_decoration = decoration_node.data.xdg_toplevel_decoration;
|
if (view.impl == .xdg_toplevel) {
|
||||||
|
if (view.impl.xdg_toplevel.decoration) |decoration| {
|
||||||
const view = @intToPtr(*View, xdg_toplevel_decoration.surface.data);
|
|
||||||
if (viewMatchesPattern(kind, pattern, view)) {
|
if (viewMatchesPattern(kind, pattern, view)) {
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
.add => {
|
.add => {
|
||||||
_ = xdg_toplevel_decoration.setMode(.client_side);
|
_ = decoration.wlr_decoration.setMode(.client_side);
|
||||||
view.pending.borders = false;
|
view.pending.borders = false;
|
||||||
},
|
},
|
||||||
.remove => {
|
.remove => {
|
||||||
_ = xdg_toplevel_decoration.setMode(.server_side);
|
_ = decoration.wlr_decoration.setMode(.server_side);
|
||||||
view.pending.borders = true;
|
view.pending.borders = true;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn viewMatchesPattern(kind: FilterKind, pattern: []const u8, view: *View) bool {
|
fn viewMatchesPattern(kind: FilterKind, pattern: []const u8, view: *View) bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user