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.
This commit is contained in:
Isaac Freund 2024-04-03 17:14:55 +02:00
parent 8b8ac27c45
commit 36d8e90a54
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
2 changed files with 47 additions and 18 deletions

View File

@ -785,6 +785,9 @@ fn handleHideCursorTimeout(cursor: *Cursor) c_int {
} }
pub fn startMove(cursor: *Cursor, view: *View) void { pub fn startMove(cursor: *Cursor, view: *View) void {
// Guard against assertion in enterMode()
if (view.current.output == null) return;
if (cursor.constraint) |constraint| { if (cursor.constraint) |constraint| {
if (constraint.state == .active) constraint.deactivate(); 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 { 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 (cursor.constraint) |constraint| {
if (constraint.state == .active) constraint.deactivate(); 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. // based on the dimensions actually committed by the client.
const border_width = if (data.view.pending.ssd) server.config.border_width else 0; 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_width: i32 = undefined;
var output_height: 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 constraints = &data.view.constraints;
const box = &data.view.pending.box; const box = &data.view.pending.box;
@ -1016,9 +1032,11 @@ pub fn checkFocusFollowsCursor(cursor: *Cursor) void {
if (server.config.focus_follows_cursor == .normal and if (server.config.focus_follows_cursor == .normal and
last_target == view) return; last_target == view) return;
if (cursor.seat.focused != .view or cursor.seat.focused.view != view) { if (cursor.seat.focused != .view or cursor.seat.focused.view != view) {
cursor.seat.focusOutput(view.current.output.?); if (view.current.output) |output| {
cursor.seat.focus(view); cursor.seat.focusOutput(output);
server.root.applyPending(); cursor.seat.focus(view);
server.root.applyPending();
}
} }
} else { } else {
// The output doesn't contain any views, just focus the output. // 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 // geometry, we only want to update this when the cursor
// properly enters the window (the box that we draw borders around) // properly enters the window (the box that we draw borders around)
// in order to avoid clashes with cursor warping on focus change. // in order to avoid clashes with cursor warping on focus change.
var output_layout_box: wlr.Box = undefined; if (view.current.output) |output| {
server.root.output_layout.getBox(view.current.output.?.wlr_output, &output_layout_box); 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_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)); const cursor_oy = cursor.wlr_cursor.y - @as(f64, @floatFromInt(output_layout_box.y));
if (view.current.box.containsPoint(cursor_ox, cursor_oy)) { if (view.current.box.containsPoint(cursor_ox, cursor_oy)) {
cursor.focus_follows_cursor_target = view; cursor.focus_follows_cursor_target = view;
}
} }
}, },
.layer_surface, .lock_surface => { .layer_surface, .lock_surface => {
@ -1104,8 +1124,9 @@ pub fn updateState(cursor: *Cursor) void {
assert(!cursor.hidden); assert(!cursor.hidden);
// These conditions are checked in Root.applyPending() // These conditions are checked in Root.applyPending()
assert(data.view.current.tags & data.view.current.output.?.current.tags != 0); const output = data.view.current.output orelse return;
assert(data.view.current.float or data.view.current.output.?.layout == null); assert(data.view.current.tags & output.current.tags != 0);
assert(data.view.current.float or output.layout == null);
assert(!data.view.current.fullscreen); assert(!data.view.current.fullscreen);
// Keep the cursor locked to the original offset from the edges of the view. // Keep the cursor locked to the original offset from the edges of the view.

View File

@ -422,10 +422,14 @@ fn handleRequestMove(
const seat: *Seat = @ptrFromInt(event.seat.seat.data); const seat: *Seat = @ptrFromInt(event.seat.seat.data);
const view = toplevel.view; 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.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. // Moving windows with touch or tablet tool is not yet supported.
if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) { 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 seat: *Seat = @ptrFromInt(event.seat.seat.data);
const view = toplevel.view; 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.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. // Resizing windows with touch or tablet tool is not yet supported.
if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) { if (seat.wlr_seat.validatePointerGrabSerial(null, event.serial)) {