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(