From 03691722b2d608f173ec7adb872ffafef174f76c Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 11 Apr 2020 20:34:51 +0200 Subject: [PATCH] Handle exclusive zones of layer surfaces --- src/layer_surface.zig | 8 +++ src/output.zig | 113 +++++++++++++++++++++++++++++++++++------- src/server.zig | 3 +- 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/layer_surface.zig b/src/layer_surface.zig index 89381d8..e628e71 100644 --- a/src/layer_surface.zig +++ b/src/layer_surface.zig @@ -29,6 +29,7 @@ pub const LayerSurface = struct { self.output = output; self.wlr_layer_surface = wlr_layer_surface; + self.box = undefined; self.layer = layer; self.listen_map.notify = handleMap; @@ -58,6 +59,7 @@ pub const LayerSurface = struct { layer_surface.wlr_layer_surface.surface, layer_surface.wlr_layer_surface.output, ); + layer_surface.output.arrangeLayers(); } fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { @@ -75,8 +77,10 @@ pub const LayerSurface = struct { fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { const layer_surface = @fieldParentPtr(LayerSurface, "listen_commit", listener.?); + const wlr_layer_surface = layer_surface.wlr_layer_surface; if (layer_surface.wlr_layer_surface.output == null) { + Log.Error.log("Layer surface committed with null output", .{}); return; } @@ -92,6 +96,10 @@ pub const LayerSurface = struct { const new_layer_idx = @intCast(usize, @enumToInt(layer_surface.layer)); layer_surface.output.layers[new_layer_idx].append(node); } + + // TODO: only reconfigure if things haven't changed + // https://github.com/swaywm/wlroots/issues/1079 + layer_surface.output.arrangeLayers(); } fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { diff --git a/src/output.zig b/src/output.zig index 634a062..10a9709 100644 --- a/src/output.zig +++ b/src/output.zig @@ -35,6 +35,7 @@ pub const Output = struct { master_factor: f64, listen_frame: c.wl_listener, + listen_mode: c.wl_listener, pub fn init(self: *Self, root: *Root, wlr_output: *c.wlr_output) !void { // Some backends don't have modes. DRM+KMS does, and we need to set a mode @@ -61,7 +62,12 @@ pub const Output = struct { layer.* = std.TailQueue(LayerSurface).init(); } - self.usable_box = undefined; + self.usable_box = .{ + .x = 0, + .y = 0, + .width = 1920, + .height = 1080, + }; self.views.init(); @@ -72,10 +78,13 @@ pub const Output = struct { self.master_factor = 0.6; - // Sets up a listener for the frame notify event. + // Set up listeners self.listen_frame.notify = handleFrame; c.wl_signal_add(&wlr_output.events.frame, &self.listen_frame); + self.listen_mode.notify = handleMode; + c.wl_signal_add(&wlr_output.events.mode, &self.listen_mode); + // Add the new output to the layout. The add_auto function arranges outputs // from left-to-right in the order they appear. A more sophisticated // compositor would let the user configure the arrangement of outputs in the @@ -106,8 +115,6 @@ pub const Output = struct { } pub fn arrange(self: *Self) void { - // TODO: properly handle output events instead of calling arrangeLayers() here - self.arrangeLayers(); self.arrangeViews(); } @@ -187,8 +194,7 @@ pub const Output = struct { /// Arrange all layer surfaces of this output and addjust the usable aread pub fn arrangeLayers(self: *Self) void { - // TODO: handle exclusive zones - const bounds = blk: { + var bounds = blk: { var width: c_int = undefined; var height: c_int = undefined; c.wlr_output_effective_resolution(self.wlr_output, &width, &height); @@ -200,36 +206,52 @@ pub const Output = struct { }; }; - for (self.layers) |layer| { - self.arrangeLayer(layer, bounds); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)], &bounds, true); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_TOP)], &bounds, true); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)], &bounds, true); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)], &bounds, true); + + if (self.usable_box.width != bounds.width or self.usable_box.height != bounds.height) { + self.usable_box = bounds; + self.root.arrange(); } - self.usable_box = bounds; + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)], &bounds, false); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_TOP)], &bounds, false); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)], &bounds, false); + self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)], &bounds, false); // TODO: handle seat focus } /// Arrange the layer surfaces of a given layer - fn arrangeLayer(self: *Self, layer: std.TailQueue(LayerSurface), bounds: Box) void { + fn arrangeLayer(self: *Self, layer: std.TailQueue(LayerSurface), bounds: *Box, exclusive: bool) void { var it = layer.first; while (it) |node| : (it = node.next) { const layer_surface = &node.data; const current_state = layer_surface.wlr_layer_surface.current; + // If the value of exclusive_zone is greater than zero, then it exclusivly + // occupies some area of the screen. + if (exclusive != (current_state.exclusive_zone > 0)) { + continue; + } + var new_box: Box = undefined; // Horizontal alignment - if (current_state.anchor & (@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) | - @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) != 0 and + const anchor_left = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT); + const anchor_right = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); + if (current_state.anchor & (anchor_left | anchor_right) != 0 and current_state.desired_width == 0) { new_box.x = bounds.x + @intCast(i32, current_state.margin.left); new_box.width = bounds.width - (current_state.margin.left + current_state.margin.right); - } else if (current_state.anchor & @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) != 0) { + } else if (current_state.anchor & anchor_left != 0) { new_box.x = bounds.x + @intCast(i32, current_state.margin.left); new_box.width = current_state.desired_width; - } else if (current_state.anchor & @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) != 0) { + } else if (current_state.anchor & anchor_right != 0) { new_box.x = bounds.x + @intCast(i32, bounds.width - current_state.desired_width - current_state.margin.right); new_box.width = current_state.desired_width; @@ -239,17 +261,18 @@ pub const Output = struct { } // Vertical alignment - if (current_state.anchor & (@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) | - @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) != 0 and + const anchor_top = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP); + const anchor_bottom = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); + if (current_state.anchor & (anchor_top | anchor_bottom) != 0 and current_state.desired_height == 0) { new_box.y = bounds.y + @intCast(i32, current_state.margin.top); new_box.height = bounds.height - (current_state.margin.top + current_state.margin.bottom); - } else if (current_state.anchor & @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) != 0) { + } else if (current_state.anchor & anchor_top != 0) { new_box.y = bounds.y + @intCast(i32, current_state.margin.top); new_box.height = current_state.desired_height; - } else if (current_state.anchor & @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) != 0) { + } else if (current_state.anchor & anchor_bottom != 0) { new_box.y = bounds.y + @intCast(i32, bounds.height - current_state.desired_height - current_state.margin.bottom); new_box.height = current_state.desired_height; @@ -259,6 +282,54 @@ pub const Output = struct { } layer_surface.box = new_box; + + // Apply the exclusive zone to the current bounds + const edges = [4]struct { + anchors: u32, + to_increase: ?*i32, + to_decrease: ?*u32, + margin: u32, + }{ + .{ + .anchors = anchor_left | anchor_right | anchor_top, + .to_increase = &bounds.y, + .to_decrease = &bounds.height, + .margin = current_state.margin.top, + }, + .{ + .anchors = anchor_left | anchor_right | anchor_bottom, + .to_increase = null, + .to_decrease = &bounds.height, + .margin = current_state.margin.bottom, + }, + .{ + .anchors = anchor_left | anchor_top | anchor_bottom, + .to_increase = &bounds.x, + .to_decrease = &bounds.width, + .margin = current_state.margin.left, + }, + .{ + .anchors = anchor_right | anchor_top | anchor_bottom, + .to_increase = null, + .to_decrease = &bounds.width, + .margin = current_state.margin.right, + }, + }; + + for (edges) |edge| { + if (current_state.anchor & edge.anchors == edge.anchors and + current_state.exclusive_zone + @intCast(i32, edge.margin) > 0) + { + const delta = current_state.exclusive_zone + @intCast(i32, edge.margin); + if (edge.to_increase) |value| { + value.* += delta; + } + if (edge.to_decrease) |value| { + value.* -= @intCast(u32, delta); + } + } + } + layer_surface.sendConfigure(); } } @@ -269,4 +340,10 @@ pub const Output = struct { const output = @fieldParentPtr(Output, "listen_frame", listener.?); render.renderOutput(output); } + + fn handleMode(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { + const output = @fieldParentPtr(Output, "listen_mode", listener.?); + output.arrangeLayers(); + output.root.arrange(); + } }; diff --git a/src/server.zig b/src/server.zig index 8a1db8b..902eb54 100644 --- a/src/server.zig +++ b/src/server.zig @@ -156,7 +156,7 @@ pub const Server = struct { ); Log.Debug.log( - "New layer surface: namespace {}, layer {}, anchor {}, size {}x{}, margin ({},{},{},{})", + "New layer surface: namespace {}, layer {}, anchor {}, size {}x{}, margin ({},{},{},{}), exclusive_zone {}", .{ wlr_layer_surface.namespace, wlr_layer_surface.client_pending.layer, @@ -167,6 +167,7 @@ pub const Server = struct { wlr_layer_surface.client_pending.margin.right, wlr_layer_surface.client_pending.margin.bottom, wlr_layer_surface.client_pending.margin.left, + wlr_layer_surface.client_pending.exclusive_zone, }, );