Output: use separate scene trees for layers

This commit is contained in:
Isaac Freund 2023-02-01 21:47:52 +01:00
parent b38676f078
commit f4a8d6dcc9
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
6 changed files with 92 additions and 20 deletions

View File

@ -95,7 +95,7 @@ fn handleUnmap(listener: *wl.Listener(*wlr.LayerSurfaceV1), _: *wlr.LayerSurface
// Remove from the output's list of layer surfaces
const self_node = @fieldParentPtr(std.TailQueue(Self).Node, "data", self);
self.output.layers[@intCast(usize, @enumToInt(self.layer))].remove(self_node);
self.output.layer_surfaces[@intCast(usize, @enumToInt(self.layer))].remove(self_node);
// If the unmapped surface is focused, clear focus
var it = server.input_manager.seats.first;

View File

@ -57,7 +57,7 @@ const State = struct {
wlr_output: *wlr.Output,
/// All layer surfaces on the output, indexed by the layer enum.
layers: [4]std.TailQueue(LayerSurface) = [1]std.TailQueue(LayerSurface){.{}} ** 4,
layer_surfaces: [4]std.TailQueue(LayerSurface) = [1]std.TailQueue(LayerSurface){.{}} ** 4,
/// The area left for views and other layer surfaces after applying the
/// exclusive zones of exclusive layer surfaces.
@ -70,6 +70,24 @@ tree: *wlr.SceneTree,
normal_content: *wlr.SceneTree,
locked_content: *wlr.SceneTree,
layers: struct {
background_color_rect: *wlr.SceneRect,
/// Background layer shell layer
background: *wlr.SceneTree,
/// Bottom layer shell layer
bottom: *wlr.SceneTree,
/// Tiled and floating views
views: *wlr.SceneTree,
/// Top layer shell layer
top: *wlr.SceneTree,
/// Fullscreen views
fullscreen: *wlr.SceneTree,
/// Overlay layer shell layer
overlay: *wlr.SceneTree,
/// Xdg popups, Xwayland override redirect windows
popups: *wlr.SceneTree,
},
/// The top of the stack is the "most important" view.
views: ViewStack(View) = .{},
@ -146,16 +164,44 @@ pub fn create(wlr_output: *wlr.Output) !void {
};
}
var width: c_int = undefined;
var height: c_int = undefined;
wlr_output.effectiveResolution(&width, &height);
const tree = try server.root.scene.tree.createSceneTree();
const normal_content = try tree.createSceneTree();
self.* = .{
.wlr_output = wlr_output,
.tree = tree,
.normal_content = try tree.createSceneTree(),
.normal_content = normal_content,
.locked_content = try tree.createSceneTree(),
.usable_box = undefined,
.layers = .{
.background_color_rect = try normal_content.createSceneRect(
width,
height,
&server.config.background_color,
),
.background = try normal_content.createSceneTree(),
.bottom = try normal_content.createSceneTree(),
.views = try normal_content.createSceneTree(),
.top = try normal_content.createSceneTree(),
.fullscreen = try normal_content.createSceneTree(),
.overlay = try normal_content.createSceneTree(),
.popups = try normal_content.createSceneTree(),
},
.usable_box = .{
.x = 0,
.y = 0,
.width = width,
.height = height,
},
};
wlr_output.data = @ptrToInt(self);
_ = try self.layers.fullscreen.createSceneRect(width, height, &[_]f32{ 0, 0, 0, 1.0 });
self.layers.fullscreen.node.setEnabled(false);
wlr_output.events.destroy.add(&self.destroy);
wlr_output.events.enable.add(&self.enable);
wlr_output.events.mode.add(&self.mode);
@ -171,14 +217,6 @@ pub fn create(wlr_output: *wlr.Output) !void {
std.log.scoped(.cursor).err("failed to load xcursor theme at scale {}", .{wlr_output.scale});
}
self.usable_box = .{
.x = 0,
.y = 0,
.width = undefined,
.height = undefined,
};
self.wlr_output.effectiveResolution(&self.usable_box.width, &self.usable_box.height);
self.setTitle();
const ptr_node = try util.gpa.create(std.TailQueue(*Self).Node);
@ -189,7 +227,7 @@ pub fn create(wlr_output: *wlr.Output) !void {
}
pub fn getLayer(self: *Self, layer: zwlr.LayerShellV1.Layer) *std.TailQueue(LayerSurface) {
return &self.layers[@intCast(usize, @enumToInt(layer))];
return &self.layer_surfaces[@intCast(usize, @enumToInt(layer))];
}
pub fn sendViewTags(self: Self) void {
@ -475,7 +513,7 @@ fn handleDestroy(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
// Remove the destroyed output from root if it wasn't already removed
server.root.removeOutput(self);
assert(self.views.first == null and self.views.last == null);
for (self.layers) |layer| assert(layer.len == 0);
for (self.layer_surfaces) |layer| assert(layer.len == 0);
assert(self.layouts.len == 0);
var it = server.root.all_outputs.first;
@ -538,6 +576,18 @@ fn handleFrame(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
fn handleMode(listener: *wl.Listener(*wlr.Output), _: *wlr.Output) void {
const self = @fieldParentPtr(Self, "mode", listener);
{
var width: c_int = undefined;
var height: c_int = undefined;
self.wlr_output.effectiveResolution(&width, &height);
self.layers.background_color_rect.setSize(width, height);
var it = self.layers.fullscreen.children.iterator(.forward);
const background_color_rect = @fieldParentPtr(wlr.SceneRect, "node", it.next().?);
background_color_rect.setSize(width, height);
}
self.arrangeLayers(.mapped);
self.arrangeViews();
server.root.startTransaction();

View File

@ -93,7 +93,10 @@ pub fn init(self: *Self) !void {
const transaction_timer = try event_loop.addTimer(*Self, handleTransactionTimeout, self);
errdefer transaction_timer.remove();
// TODO get rid of this hack somehow
const noop_wlr_output = try server.headless_backend.headlessAddOutput(1920, 1080);
const noop_tree = try scene.tree.createSceneTree();
noop_tree.node.setEnabled(false);
self.* = .{
.scene = scene,
.output_layout = output_layout,
@ -102,9 +105,23 @@ pub fn init(self: *Self) !void {
.transaction_timer = transaction_timer,
.noop_output = .{
.wlr_output = noop_wlr_output,
.tree = try scene.tree.createSceneTree(),
.normal_content = try scene.tree.createSceneTree(),
.locked_content = try scene.tree.createSceneTree(),
.tree = noop_tree,
.normal_content = try noop_tree.createSceneTree(),
.locked_content = try noop_tree.createSceneTree(),
.layers = .{
.background_color_rect = try noop_tree.createSceneRect(
0,
0,
&server.config.background_color,
),
.background = try noop_tree.createSceneTree(),
.bottom = try noop_tree.createSceneTree(),
.views = try noop_tree.createSceneTree(),
.top = try noop_tree.createSceneTree(),
.fullscreen = try noop_tree.createSceneTree(),
.overlay = try noop_tree.createSceneTree(),
.popups = try noop_tree.createSceneTree(),
},
.usable_box = .{ .x = 0, .y = 0, .width = 0, .height = 0 },
},
};
@ -218,7 +235,7 @@ pub fn removeOutput(self: *Self, output: *Output) void {
}
// Close all layer surfaces on the removed output
for (output.layers) |*layer| {
for (output.layer_surfaces) |*layer| {
// Destroying the layer surface will cause it to be removed from this list.
while (layer.first) |layer_node| layer_node.data.wlr_layer_surface.destroy();
}

View File

@ -63,7 +63,7 @@ pub fn create(output: *Output, xdg_toplevel: *wlr.XdgToplevel) error{OutOfMemory
errdefer util.gpa.destroy(node);
const view = &node.view;
const tree = try output.normal_content.createSceneXdgSurface(xdg_toplevel.base);
const tree = try output.layers.views.createSceneXdgSurface(xdg_toplevel.base);
errdefer tree.node.destroy();
try view.init(output, tree, .{ .xdg_toplevel = .{

View File

@ -68,7 +68,7 @@ pub fn create(output: *Output, xwayland_surface: *wlr.XwaylandSurface) error{Out
const view = &node.view;
// TODO actually render xwayland windows, not just an empty tree.
const tree = try output.tree.createSceneTree();
const tree = try output.layers.views.createSceneTree();
view.init(output, tree, .{ .xwayland_view = .{
.view = view,

View File

@ -46,6 +46,11 @@ pub fn backgroundColor(
if (args.len > 2) return Error.TooManyArguments;
server.config.background_color = try parseRgba(args[1]);
var it = server.root.all_outputs.first;
while (it) |node| : (it = node.next) {
const output = node.data;
output.layers.background_color_rect.setColor(&server.config.background_color);
}
}
pub fn borderColorFocused(