diff --git a/src/Output.zig b/src/Output.zig index 4ce8ab6..c07e682 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -576,8 +576,11 @@ pub fn manage(output: *Output) void { } } - // Calculate layout before managing windows - output.calculateLayout(); + // Calculate layout before managing windows, but only if output dimensions are initialized + if (output.usable_geometry.width > 0 and output.usable_geometry.height > 0) { + output.calculateLayout(); + } + var it = output.windows.iterator(.forward); while (it.next()) |window| { window.manage(); @@ -612,6 +615,8 @@ pub fn render(output: *Output) void { /// - Single window: maximized /// - Multiple windows: stack (45% left, vertically tiled), primary (55% right) 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 var active_list: DoublyLinkedList = .{}; var active_count: u31 = 0; @@ -714,8 +719,14 @@ fn calculateLayout(output: *Output) void { } // Make space for borders - window.pending_manage.dimensions.?.height -= 2 * border_width; - window.pending_manage.dimensions.?.width -= 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.?.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.?.y += border_width; } diff --git a/src/WindowManager.zig b/src/WindowManager.zig index 13e6bfd..cb64fc5 100644 --- a/src/WindowManager.zig +++ b/src/WindowManager.zig @@ -72,7 +72,63 @@ pub fn prevOutput(wm: *WindowManager, current: *Output) ?*Output { 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 context = wm.context; @@ -82,54 +138,7 @@ fn manage_start(wm: *WindowManager) void { if (!context.initialized) { // This code runs during initial startup and after config reloads. @branchHint(.cold); - context.initialized = true; - - 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(); - } + wm.initialize(); } { @@ -147,7 +156,7 @@ fn manage_start(wm: *WindowManager) void { 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; { var it = wm.seats.iterator(.forward); @@ -171,8 +180,8 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv .unavailable => { fatal("Window manager unavailable (some other wm instance is running). Exiting", .{}); }, - .manage_start => wm.manage_start(), - .render_start => wm.render_start(), + .manage_start => wm.manage(), + .render_start => wm.render(), .output => |ev| { const output = Output.create(context, ev.id) catch @panic("Out of memory"); wm.outputs.append(output);