Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
View: always check if current.output is null
This field being nullable at all is code smell. I think what needs to
happen here long term is for a proper separation of "window management
output" and "physical output" as concepts and integration outputs into
the transaction system.
That's a much larger change and I don't want to cause that amount of
code churn just before a release though.
river/Cursor.zig | 47 ++++++++++++++++++++++++++++++++++-------------
river/XdgToplevel.zig | 20 ++++++++++++++------
2 files changed, 48 insertions(+), 19 deletions(-)
diff --git a/river/Cursor.zig b/river/Cursor.zig
index 13d312f..b214b95 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -785,6 +785,9 @@ fn handleHideCursorTimeout(cursor: *Cursor) c_int {
}
pub fn startMove(cursor: *Cursor, view: *View) void {
+ // Guard against assertion in enterMode()
+ if (view.current.output == null) return;
+
if (cursor.constraint) |constraint| {
if (constraint.state == .active) constraint.deactivate();
}
@@ -798,6 +801,9 @@ pub fn startMove(cursor: *Cursor, view: *View) void {
}
pub fn startResize(cursor: *Cursor, view: *View, proposed_edges: ?wlr.Edges) void {
+ // Guard against assertions in computeEdges() and enterMode()
+ if (view.current.output == null) return;
+
if (cursor.constraint) |constraint| {
if (constraint.state == .active) constraint.deactivate();
}
@@ -961,9 +967,19 @@ fn processMotion(cursor: *Cursor, device: *wlr.InputDevice, time: u32, delta_x:
// based on the dimensions actually committed by the client.
const border_width = if (data.view.pending.ssd) server.config.border_width else 0;
+ const output = data.view.current.output orelse {
+ data.view.pending.resizing = false;
+
+ cursor.mode = .passthrough;
+ cursor.passthrough(time);
+
+ server.root.applyPending();
+ return;
+ };
+
var output_width: i32 = undefined;
var output_height: i32 = undefined;
- data.view.current.output.?.wlr_output.effectiveResolution(&output_width, &output_height);
+ output.wlr_output.effectiveResolution(&output_width, &output_height);
const constraints = &data.view.constraints;
const box = &data.view.pending.box;
@@ -1016,9 +1032,11 @@ pub fn checkFocusFollowsCursor(cursor: *Cursor) void {
if (server.config.focus_follows_cursor == .normal and
last_target == view) return;
if (cursor.seat.focused != .view or cursor.seat.focused.view != view) {
- cursor.seat.focusOutput(view.current.output.?);
- cursor.seat.focus(view);
- server.root.applyPending();
+ if (view.current.output) |output| {
+ cursor.seat.focusOutput(output);
+ cursor.seat.focus(view);
+ server.root.applyPending();
+ }
}
} else {
// The output doesn't contain any views, just focus the output.
@@ -1034,13 +1052,15 @@ fn updateFocusFollowsCursorTarget(cursor: *Cursor) void {
// geometry, we only want to update this when the cursor
// properly enters the window (the box that we draw borders around)
// in order to avoid clashes with cursor warping on focus change.
- var output_layout_box: wlr.Box = undefined;
- server.root.output_layout.getBox(view.current.output.?.wlr_output, &output_layout_box);
-
- const cursor_ox = cursor.wlr_cursor.x - @as(f64, @floatFromInt(output_layout_box.x));
- const cursor_oy = cursor.wlr_cursor.y - @as(f64, @floatFromInt(output_layout_box.y));
- if (view.current.box.containsPoint(cursor_ox, cursor_oy)) {
- cursor.focus_follows_cursor_target = view;
+ if (view.current.output) |output| {
+ var output_layout_box: wlr.Box = undefined;
+ server.root.output_layout.getBox(output.wlr_output, &output_layout_box);
+
+ const cursor_ox = cursor.wlr_cursor.x - @as(f64, @floatFromInt(output_layout_box.x));
+ const cursor_oy = cursor.wlr_cursor.y - @as(f64, @floatFromInt(output_layout_box.y));
+ if (view.current.box.containsPoint(cursor_ox, cursor_oy)) {
+ cursor.focus_follows_cursor_target = view;
+ }
}
},
.layer_surface, .lock_surface => {
@@ -1104,8 +1124,9 @@ pub fn updateState(cursor: *Cursor) void {
assert(!cursor.hidden);
// These conditions are checked in Root.applyPending()
- assert(data.view.current.tags & data.view.current.output.?.current.tags != 0);
- assert(data.view.current.float or data.view.current.output.?.layout == null);
+ const output = data.view.current.output orelse return;
+ assert(data.view.current.tags & output.current.tags != 0);
+ assert(data.view.current.float or output.layout == null);
assert(!data.view.current.fullscreen);
// Keep the cursor locked to the original offset from the edges of the view.
diff --git a/river/XdgToplevel.zig b/river/XdgToplevel.zig
index 1e99a3c..3e28933 100644
--- a/river/XdgToplevel.zig
+++ b/river/XdgToplevel.zig
@@ -422,10 +422,14 @@ fn handleRequestMove(
const seat: *Seat = @ptrFromInt(event.seat.seat.data);
const view = toplevel.view;
- if (view.current.output == null or view.pending.output == null) return;
- if (view.current.tags & view.current.output.?.current.tags == 0) return;
if (view.pending.fullscreen) return;
- if (!(view.pending.float or view.pending.output.?.layout == null)) return;
+
+ if (view.current.output) |current_output| {
+ if (view.current.tags & current_output.current.tags == 0) return;
+ }
+ if (view.pending.output) |pending_output| {
+ if (!(view.pending.float or pending_output.layout == null)) return;
+ }
// Moving windows with touch or tablet tool is not yet supported.
if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) {
@@ -441,10 +445,14 @@ fn handleRequestResize(listener: *wl.Listener(*wlr.XdgToplevel.event.Resize), ev
const seat: *Seat = @ptrFromInt(event.seat.seat.data);
const view = toplevel.view;
- if (view.current.output == null or view.pending.output == null) return;
- if (view.current.tags & view.current.output.?.current.tags == 0) return;
if (view.pending.fullscreen) return;
- if (!(view.pending.float or view.pending.output.?.layout == null)) return;
+
+ if (view.current.output) |current_output| {
+ if (view.current.tags & current_output.current.tags == 0) return;
+ }
+ if (view.pending.output) |pending_output| {
+ if (!(view.pending.float or pending_output.layout == null)) return;
+ }
// Resizing windows with touch or tablet tool is not yet supported.
if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) {