Handle exclusive zones of layer surfaces

This commit is contained in:
Isaac Freund 2020-04-11 20:34:51 +02:00
parent ff833a07d3
commit 03691722b2
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
3 changed files with 105 additions and 19 deletions

View File

@ -29,6 +29,7 @@ pub const LayerSurface = struct {
self.output = output; self.output = output;
self.wlr_layer_surface = wlr_layer_surface; self.wlr_layer_surface = wlr_layer_surface;
self.box = undefined;
self.layer = layer; self.layer = layer;
self.listen_map.notify = handleMap; self.listen_map.notify = handleMap;
@ -58,6 +59,7 @@ pub const LayerSurface = struct {
layer_surface.wlr_layer_surface.surface, layer_surface.wlr_layer_surface.surface,
layer_surface.wlr_layer_surface.output, layer_surface.wlr_layer_surface.output,
); );
layer_surface.output.arrangeLayers();
} }
fn handleUnmap(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void { 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 { fn handleCommit(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
const layer_surface = @fieldParentPtr(LayerSurface, "listen_commit", listener.?); 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) { if (layer_surface.wlr_layer_surface.output == null) {
Log.Error.log("Layer surface committed with null output", .{});
return; return;
} }
@ -92,6 +96,10 @@ pub const LayerSurface = struct {
const new_layer_idx = @intCast(usize, @enumToInt(layer_surface.layer)); const new_layer_idx = @intCast(usize, @enumToInt(layer_surface.layer));
layer_surface.output.layers[new_layer_idx].append(node); 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 { fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {

View File

@ -35,6 +35,7 @@ pub const Output = struct {
master_factor: f64, master_factor: f64,
listen_frame: c.wl_listener, listen_frame: c.wl_listener,
listen_mode: c.wl_listener,
pub fn init(self: *Self, root: *Root, wlr_output: *c.wlr_output) !void { 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 // 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(); layer.* = std.TailQueue(LayerSurface).init();
} }
self.usable_box = undefined; self.usable_box = .{
.x = 0,
.y = 0,
.width = 1920,
.height = 1080,
};
self.views.init(); self.views.init();
@ -72,10 +78,13 @@ pub const Output = struct {
self.master_factor = 0.6; self.master_factor = 0.6;
// Sets up a listener for the frame notify event. // Set up listeners
self.listen_frame.notify = handleFrame; self.listen_frame.notify = handleFrame;
c.wl_signal_add(&wlr_output.events.frame, &self.listen_frame); 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 // 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 // from left-to-right in the order they appear. A more sophisticated
// compositor would let the user configure the arrangement of outputs in the // 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 { pub fn arrange(self: *Self) void {
// TODO: properly handle output events instead of calling arrangeLayers() here
self.arrangeLayers();
self.arrangeViews(); self.arrangeViews();
} }
@ -187,8 +194,7 @@ pub const Output = struct {
/// Arrange all layer surfaces of this output and addjust the usable aread /// Arrange all layer surfaces of this output and addjust the usable aread
pub fn arrangeLayers(self: *Self) void { pub fn arrangeLayers(self: *Self) void {
// TODO: handle exclusive zones var bounds = blk: {
const bounds = blk: {
var width: c_int = undefined; var width: c_int = undefined;
var height: c_int = undefined; var height: c_int = undefined;
c.wlr_output_effective_resolution(self.wlr_output, &width, &height); c.wlr_output_effective_resolution(self.wlr_output, &width, &height);
@ -200,36 +206,52 @@ pub const Output = struct {
}; };
}; };
for (self.layers) |layer| { self.arrangeLayer(self.layers[@intCast(usize, c.ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY)], &bounds, true);
self.arrangeLayer(layer, bounds); 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 // TODO: handle seat focus
} }
/// Arrange the layer surfaces of a given layer /// 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; var it = layer.first;
while (it) |node| : (it = node.next) { while (it) |node| : (it = node.next) {
const layer_surface = &node.data; const layer_surface = &node.data;
const current_state = layer_surface.wlr_layer_surface.current; 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; var new_box: Box = undefined;
// Horizontal alignment // Horizontal alignment
if (current_state.anchor & (@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) | const anchor_left = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT);
@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) != 0 and 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) current_state.desired_width == 0)
{ {
new_box.x = bounds.x + @intCast(i32, current_state.margin.left); new_box.x = bounds.x + @intCast(i32, current_state.margin.left);
new_box.width = bounds.width - new_box.width = bounds.width -
(current_state.margin.left + current_state.margin.right); (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.x = bounds.x + @intCast(i32, current_state.margin.left);
new_box.width = current_state.desired_width; 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 - new_box.x = bounds.x + @intCast(i32, bounds.width - current_state.desired_width -
current_state.margin.right); current_state.margin.right);
new_box.width = current_state.desired_width; new_box.width = current_state.desired_width;
@ -239,17 +261,18 @@ pub const Output = struct {
} }
// Vertical alignment // Vertical alignment
if (current_state.anchor & (@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) | const anchor_top = @intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP);
@intCast(u32, c.ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) != 0 and 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) current_state.desired_height == 0)
{ {
new_box.y = bounds.y + @intCast(i32, current_state.margin.top); new_box.y = bounds.y + @intCast(i32, current_state.margin.top);
new_box.height = bounds.height - new_box.height = bounds.height -
(current_state.margin.top + current_state.margin.bottom); (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.y = bounds.y + @intCast(i32, current_state.margin.top);
new_box.height = current_state.desired_height; 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 - new_box.y = bounds.y + @intCast(i32, bounds.height - current_state.desired_height -
current_state.margin.bottom); current_state.margin.bottom);
new_box.height = current_state.desired_height; new_box.height = current_state.desired_height;
@ -259,6 +282,54 @@ pub const Output = struct {
} }
layer_surface.box = new_box; 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(); layer_surface.sendConfigure();
} }
} }
@ -269,4 +340,10 @@ pub const Output = struct {
const output = @fieldParentPtr(Output, "listen_frame", listener.?); const output = @fieldParentPtr(Output, "listen_frame", listener.?);
render.renderOutput(output); 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();
}
}; };

View File

@ -156,7 +156,7 @@ pub const Server = struct {
); );
Log.Debug.log( 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.namespace,
wlr_layer_surface.client_pending.layer, 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.right,
wlr_layer_surface.client_pending.margin.bottom, wlr_layer_surface.client_pending.margin.bottom,
wlr_layer_surface.client_pending.margin.left, wlr_layer_surface.client_pending.margin.left,
wlr_layer_surface.client_pending.exclusive_zone,
}, },
); );