Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
protocol: specify fullscreen/clip interaction
The compositor now ignores clip/content clip boxes and always clips to
output bounds while a window is fullscreen.
protocol/river-window-management-v1.xml | 13 +++++++-
river/Window.zig | 57 +++++++++++++++++----------------
2 files changed, 41 insertions(+), 29 deletions(-)
diff --git a/protocol/river-window-management-v1.xml b/protocol/river-window-management-v1.xml
index f433a48..cdb273e 100644
--- a/protocol/river-window-management-v1.xml
+++ b/protocol/river-window-management-v1.xml
@@ -601,6 +601,8 @@
the left edge will not extend vertically beyond the top edge of the
window.
+ Borders are not drawn while the window is fullscreen.
+
The color is defined by four 32-bit RGBA values. Unless specified in
another protocol extension, the RGBA values use pre-multiplied alpha.
@@ -909,6 +911,11 @@
shall not affect the current position and dimensions of a fullscreen
window.
+ The compositor will clip window content, decoration surfaces, and
+ borders to the given output's dimensions while the window is fullscreen.
+ The effects of set_clip_box and set_content_clip_box are ignored while
+ the window is fullscreen.
+
If the output on which a window is currently fullscreen is removed, the
windowing state is modified as if there were an exit_fullscreen request
made in the same manage sequence as the river_output_v1.removed event.
@@ -965,6 +972,8 @@
Setting a clip box with 0 width or height disables clipping.
+ The clip box is ignored while the window is fullscreen.
+
Both set_clip_box and set_content_clip_box may be enabled simultaneously.
This request modifies rendering state and may only be made as part of a
@@ -1005,7 +1014,9 @@
The width and height arguments must be greater than or equal to 0.
- Setting a clip box with 0 width or height disables content clipping.
+ Setting a box with 0 width or height disables content clipping.
+
+ The content clip box is ignored while the window is fullscreen.
Both set_clip_box and set_content_clip_box may be enabled simultaneously.
diff --git a/river/Window.zig b/river/Window.zig
index 8e7a5ec..789ac27 100644
--- a/river/Window.zig
+++ b/river/Window.zig
@@ -818,32 +818,42 @@ pub fn renderStart(window: *Window) void {
pub fn renderFinish(window: *Window) void {
const requested = &window.rendering_requested;
+ window.tree.node.setEnabled(!requested.hidden);
+ window.popup_tree.node.setEnabled(!requested.hidden);
- window.tree.node.setEnabled(!window.rendering_requested.hidden);
- window.popup_tree.node.setEnabled(!window.rendering_requested.hidden);
-
- window.box = .{
- .x = requested.x,
- .y = requested.y,
- .width = window.rendering_sent.width,
- .height = window.rendering_sent.height,
- };
+ window.box.width = window.rendering_sent.width;
+ window.box.height = window.rendering_sent.height;
+ var clip: wlr.Box = requested.clip;
+ var content_clip: wlr.Box = requested.content_clip;
if (window.wm_requested.fullscreen) |output| {
window.box.x = output.sent.x;
window.box.y = output.sent.y;
window.fullscreen_background.node.setEnabled(true);
const width, const height = output.sent.dimensions();
window.fullscreen_background.setSize(width, height);
+ clip = .{ .x = 0, .y = 0, .width = width, .height = height };
+ content_clip = .{ .x = 0, .y = 0, .width = 0, .height = 0 };
} else {
+ window.box.x = requested.x;
+ window.box.y = requested.y;
window.fullscreen_background.node.setEnabled(false);
+ window.drawBorders();
}
-
window.tree.node.setPosition(window.box.x, window.box.y);
window.popup_tree.node.setPosition(window.box.x, window.box.y);
- window.applySurfaceClip();
+ window.applySurfaceClip(&clip, &content_clip);
+ inline for (.{ &window.decorations_above, &window.decorations_below }) |decorations| {
+ var it = decorations.iterator(.forward);
+ while (it.next()) |decoration| {
+ decoration.renderFinish(&clip);
+ }
+ }
+}
+fn drawBorders(window: *Window) void {
+ const requested = &window.rendering_requested;
var content: wlr.Box = .{
.x = 0,
.y = 0,
@@ -862,7 +872,6 @@ pub fn renderFinish(window: *Window) void {
@floatCast(@as(f64, @floatFromInt(border.b)) / math.maxInt(u32)),
@floatCast(@as(f64, @floatFromInt(border.a)) / math.maxInt(u32)),
};
-
var left: wlr.Box = .{
.x = -@as(i32, border.width),
.y = 0,
@@ -887,7 +896,6 @@ pub fn renderFinish(window: *Window) void {
.width = content.width,
.height = border.width,
};
-
// Use left and right scene rects to draw the corners if needed
if (border.edges.top) {
left.y -= border.width;
@@ -899,7 +907,6 @@ pub fn renderFinish(window: *Window) void {
left.height += border.width;
right.height += border.width;
}
-
inline for (.{
.{ .name = "left", .box = &left },
.{ .name = "right", .box = &right },
@@ -920,27 +927,21 @@ pub fn renderFinish(window: *Window) void {
rect.setColor(&color);
}
}
-
- inline for (.{ &window.decorations_above, &window.decorations_below }) |decorations| {
- var it = decorations.iterator(.forward);
- while (it.next()) |decoration| {
- decoration.renderFinish(&requested.clip);
- }
- }
}
-fn applySurfaceClip(window: *Window) void {
- const requested = &window.rendering_requested;
- var surface_clip: wlr.Box = requested.clip;
- if (!requested.clip.empty() and !requested.content_clip.empty()) {
- if (!surface_clip.intersection(&requested.clip, &requested.content_clip)) {
+fn applySurfaceClip(window: *Window, a: *const wlr.Box, b: *const wlr.Box) void {
+ var surface_clip: wlr.Box = undefined;
+ if (!a.empty() and !b.empty()) {
+ if (!surface_clip.intersection(a, b)) {
// Clip boxes are both non-empty but don't intersect, all window
// content is clipped away.
window.surfaces.setEnabled(false);
return;
}
- } else if (!requested.content_clip.empty()) {
- surface_clip = requested.content_clip;
+ } else if (!a.empty()) {
+ surface_clip = a.*;
+ } else {
+ surface_clip = b.*;
}
window.surfaces.setEnabled(true);
switch (window.impl) {