Fix two crashes
One was where WM was assuming that a seat existed during first manage, but that's not always true, so we have to check that before running the initialization code. I also split that off into its own function like in Window. The other crash was when trying to calculate the layout with the output's width and/or height equal to zero, it would crash subtracting the border width. I discovered both of these when try to restart beansprout without restarting River.
This commit is contained in:
parent
6f68850a70
commit
08be768d99
2 changed files with 76 additions and 56 deletions
|
|
@ -576,8 +576,11 @@ pub fn manage(output: *Output) void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate layout before managing windows
|
// Calculate layout before managing windows, but only if output dimensions are initialized
|
||||||
output.calculateLayout();
|
if (output.usable_geometry.width > 0 and output.usable_geometry.height > 0) {
|
||||||
|
output.calculateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
var it = output.windows.iterator(.forward);
|
var it = output.windows.iterator(.forward);
|
||||||
while (it.next()) |window| {
|
while (it.next()) |window| {
|
||||||
window.manage();
|
window.manage();
|
||||||
|
|
@ -612,6 +615,8 @@ pub fn render(output: *Output) void {
|
||||||
/// - Single window: maximized
|
/// - Single window: maximized
|
||||||
/// - Multiple windows: stack (45% left, vertically tiled), primary (55% right)
|
/// - Multiple windows: stack (45% left, vertically tiled), primary (55% right)
|
||||||
fn calculateLayout(output: *Output) void {
|
fn calculateLayout(output: *Output) void {
|
||||||
|
// Shouldn't be called if height/width are not positive
|
||||||
|
assert(output.geometry.width > 0 and output.geometry.height > 0);
|
||||||
// Get a list of active windows
|
// Get a list of active windows
|
||||||
var active_list: DoublyLinkedList = .{};
|
var active_list: DoublyLinkedList = .{};
|
||||||
var active_count: u31 = 0;
|
var active_count: u31 = 0;
|
||||||
|
|
@ -714,8 +719,14 @@ fn calculateLayout(output: *Output) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make space for borders
|
// Make space for borders
|
||||||
window.pending_manage.dimensions.?.height -= 2 * border_width;
|
if (window.pending_manage.dimensions.?.height > 2 * border_width and
|
||||||
window.pending_manage.dimensions.?.width -= 2 * border_width;
|
window.pending_manage.dimensions.?.width > 2 * border_width)
|
||||||
|
{
|
||||||
|
window.pending_manage.dimensions.?.height -= 2 * border_width;
|
||||||
|
window.pending_manage.dimensions.?.width -= 2 * border_width;
|
||||||
|
} else {
|
||||||
|
log.warn("Can't add borders to some window; {s}'s dimensions are too small.", .{output.name orelse "some output"});
|
||||||
|
}
|
||||||
window.pending_render.position.?.x += border_width;
|
window.pending_render.position.?.x += border_width;
|
||||||
window.pending_render.position.?.y += border_width;
|
window.pending_render.position.?.y += border_width;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,63 @@ pub fn prevOutput(wm: *WindowManager, current: *Output) ?*Output {
|
||||||
return @fieldParentPtr("link", prev_link);
|
return @fieldParentPtr("link", prev_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn manage_start(wm: *WindowManager) void {
|
fn initialize(wm: *WindowManager) void {
|
||||||
|
if (wm.context.initialized) return;
|
||||||
|
|
||||||
|
// We need a seat to intitialize this stuff, so let's just not do it right now.
|
||||||
|
// The WM can run fine without it, though, it won't be fully usuable.
|
||||||
|
const seat = wm.seats.first() orelse return;
|
||||||
|
const river_seat_v1 = seat.river_seat_v1;
|
||||||
|
|
||||||
|
const context = wm.context;
|
||||||
|
context.initialized = true;
|
||||||
|
|
||||||
|
// Tag bindings
|
||||||
|
for (context.config.tag_binds.items) |tag_bind| {
|
||||||
|
comptime var i: u8 = 1;
|
||||||
|
comptime var buffer: [1]u8 = undefined;
|
||||||
|
inline while (i <= 9) : (i += 1) {
|
||||||
|
const tags: u32 = 1 << (i - 1);
|
||||||
|
buffer[0] = i + '0';
|
||||||
|
const command: XkbBindings.Command = switch (tag_bind.command) {
|
||||||
|
.set_output_tags => .{ .set_output_tags = tags },
|
||||||
|
.set_window_tags => .{ .set_window_tags = tags },
|
||||||
|
.toggle_output_tags => .{ .toggle_output_tags = tags },
|
||||||
|
.toggle_window_tags => .{ .toggle_window_tags = tags },
|
||||||
|
else => unreachable,
|
||||||
|
};
|
||||||
|
context.xkb_bindings.addBinding(river_seat_v1, @field(xkbcommon.Keysym, &buffer), tag_bind.modifiers, command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Rest of the keybinds
|
||||||
|
for (context.config.keybinds.keys(), context.config.keybinds.values()) |key, command| {
|
||||||
|
context.xkb_bindings.addBinding(river_seat_v1, key.keysym, key.modifiers, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer bindings
|
||||||
|
for (context.config.pointer_binds.items) |pointer_bind| {
|
||||||
|
const binding = river_seat_v1.getPointerBinding(pointer_bind.button, pointer_bind.modifiers) catch {
|
||||||
|
log.err("Failed to create pointer binding", .{});
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (pointer_bind.action) {
|
||||||
|
.move_window => {
|
||||||
|
if (seat.move_pointer_binding) |old| old.destroy();
|
||||||
|
binding.setListener(*Seat, Seat.movePointerBindingListener, seat);
|
||||||
|
seat.move_pointer_binding = binding;
|
||||||
|
},
|
||||||
|
.resize_window => {
|
||||||
|
if (seat.resize_pointer_binding) |old| old.destroy();
|
||||||
|
binding.setListener(*Seat, Seat.resizePointerBindingListener, seat);
|
||||||
|
seat.resize_pointer_binding = binding;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
binding.enable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manage(wm: *WindowManager) void {
|
||||||
const river_window_manager_v1 = wm.river_window_manager_v1;
|
const river_window_manager_v1 = wm.river_window_manager_v1;
|
||||||
const context = wm.context;
|
const context = wm.context;
|
||||||
|
|
||||||
|
|
@ -82,54 +138,7 @@ fn manage_start(wm: *WindowManager) void {
|
||||||
if (!context.initialized) {
|
if (!context.initialized) {
|
||||||
// This code runs during initial startup and after config reloads.
|
// This code runs during initial startup and after config reloads.
|
||||||
@branchHint(.cold);
|
@branchHint(.cold);
|
||||||
context.initialized = true;
|
wm.initialize();
|
||||||
|
|
||||||
const seat = wm.seats.first() orelse @panic("Failed to get seat");
|
|
||||||
const river_seat_v1 = seat.river_seat_v1;
|
|
||||||
|
|
||||||
// Tag bindings
|
|
||||||
for (context.config.tag_binds.items) |tag_bind| {
|
|
||||||
comptime var i: u8 = 1;
|
|
||||||
comptime var buffer: [1]u8 = undefined;
|
|
||||||
inline while (i <= 9) : (i += 1) {
|
|
||||||
const tags: u32 = 1 << (i - 1);
|
|
||||||
buffer[0] = i + '0';
|
|
||||||
const command: XkbBindings.Command = switch (tag_bind.command) {
|
|
||||||
.set_output_tags => .{ .set_output_tags = tags },
|
|
||||||
.set_window_tags => .{ .set_window_tags = tags },
|
|
||||||
.toggle_output_tags => .{ .toggle_output_tags = tags },
|
|
||||||
.toggle_window_tags => .{ .toggle_window_tags = tags },
|
|
||||||
else => unreachable,
|
|
||||||
};
|
|
||||||
context.xkb_bindings.addBinding(river_seat_v1, @field(xkbcommon.Keysym, &buffer), tag_bind.modifiers, command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Rest of the keybinds
|
|
||||||
for (context.config.keybinds.keys(), context.config.keybinds.values()) |key, command| {
|
|
||||||
context.xkb_bindings.addBinding(river_seat_v1, key.keysym, key.modifiers, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pointer bindings
|
|
||||||
for (context.config.pointer_binds.items) |pointer_bind| {
|
|
||||||
const binding = river_seat_v1.getPointerBinding(pointer_bind.button, pointer_bind.modifiers) catch {
|
|
||||||
log.err("Failed to create pointer binding", .{});
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (pointer_bind.action) {
|
|
||||||
.move_window => {
|
|
||||||
if (seat.move_pointer_binding) |old| old.destroy();
|
|
||||||
binding.setListener(*Seat, Seat.movePointerBindingListener, seat);
|
|
||||||
seat.move_pointer_binding = binding;
|
|
||||||
},
|
|
||||||
.resize_window => {
|
|
||||||
if (seat.resize_pointer_binding) |old| old.destroy();
|
|
||||||
binding.setListener(*Seat, Seat.resizePointerBindingListener, seat);
|
|
||||||
seat.resize_pointer_binding = binding;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
binding.enable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -147,7 +156,7 @@ fn manage_start(wm: *WindowManager) void {
|
||||||
river_window_manager_v1.manageFinish();
|
river_window_manager_v1.manageFinish();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_start(wm: *WindowManager) void {
|
fn render(wm: *WindowManager) void {
|
||||||
const river_window_manager_v1 = wm.river_window_manager_v1;
|
const river_window_manager_v1 = wm.river_window_manager_v1;
|
||||||
{
|
{
|
||||||
var it = wm.seats.iterator(.forward);
|
var it = wm.seats.iterator(.forward);
|
||||||
|
|
@ -171,8 +180,8 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv
|
||||||
.unavailable => {
|
.unavailable => {
|
||||||
fatal("Window manager unavailable (some other wm instance is running). Exiting", .{});
|
fatal("Window manager unavailable (some other wm instance is running). Exiting", .{});
|
||||||
},
|
},
|
||||||
.manage_start => wm.manage_start(),
|
.manage_start => wm.manage(),
|
||||||
.render_start => wm.render_start(),
|
.render_start => wm.render(),
|
||||||
.output => |ev| {
|
.output => |ev| {
|
||||||
const output = Output.create(context, ev.id) catch @panic("Out of memory");
|
const output = Output.create(context, ev.id) catch @panic("Out of memory");
|
||||||
wm.outputs.append(output);
|
wm.outputs.append(output);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue