aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <mail@isaacfreund.com>2023-02-01 21:47:52 +0100
committerIsaac Freund <mail@isaacfreund.com>2023-02-28 14:55:58 +0100
commitf4a8d6dcc9850f6dc65c26108ab5b925f7a8c9ea (patch)
treea82f78a37d200ae2bba502e74141c20fb609cd1d
parentb38676f0784b59a0a5b858fd947e7aad6d5872d7 (diff)
downloadriver-f4a8d6dcc9850f6dc65c26108ab5b925f7a8c9ea.tar.gz
river-f4a8d6dcc9850f6dc65c26108ab5b925f7a8c9ea.tar.xz
Output: use separate scene trees for layers
-rw-r--r--river/LayerSurface.zig2
-rw-r--r--river/Output.zig76
-rw-r--r--river/Root.zig25
-rw-r--r--river/XdgToplevel.zig2
-rw-r--r--river/XwaylandView.zig2
-rw-r--r--river/command/config.zig5
6 files changed, 92 insertions, 20 deletions
diff --git a/river/LayerSurface.zig b/river/LayerSurface.zig
index 16e50df..1e84740 100644
--- a/river/LayerSurface.zig
+++ b/river/LayerSurface.zig
@@ -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;
diff --git a/river/Output.zig b/river/Output.zig
index 83b4831..f286fef 100644
--- a/river/Output.zig
+++ b/river/Output.zig
@@ -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();
diff --git a/river/Root.zig b/river/Root.zig
index 2eebd68..4ef1260 100644
--- a/river/Root.zig
+++ b/river/Root.zig
@@ -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();
}
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 564189a..4a78d1b 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -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 = .{
diff --git a/river/XwaylandView.zig b/river/XwaylandView.zig
index 0f77a26..211a8a8 100644
--- a/river/XwaylandView.zig
+++ b/river/XwaylandView.zig
@@ -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,
diff --git a/river/command/config.zig b/river/command/config.zig
index 145743f..88ad1f4 100644
--- a/river/command/config.zig
+++ b/river/command/config.zig
@@ -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(