diff --git a/src/Output.zig b/src/Output.zig index c508ca8..d5e3b04 100644 --- a/src/Output.zig +++ b/src/Output.zig @@ -6,40 +6,50 @@ const Output = @This(); context: *Context, -output_v1: *river.OutputV1, +river_output_v1: *river.OutputV1, width: i32 = 0, height: i32 = 0, x: i32 = 0, y: i32 = 0, +tags: u32 = 0x0001, + link: wl.list.Link, -pub fn init(output: *Output, context: *Context, river_output_v1: *river.OutputV1) void { +pub fn create(context: *Context, river_output_v1: *river.OutputV1) !*Output { + var output = try utils.allocator.create(Output); + errdefer output.destroy(); + output.* = .{ .context = context, - .output_v1 = river_output_v1, + .river_output_v1 = river_output_v1, .link = undefined, // Handled by the wl.list }; - output.output_v1.setListener(*Output, outputListener, output); + output.river_output_v1.setListener(*Output, outputListener, output); + + return output; +} + +pub fn destroy(output: *Output) void { + output.river_output_v1.destroy(); + utils.allocator.destroy(output); } fn outputListener(river_output_v1: *river.OutputV1, event: river.OutputV1.Event, output: *Output) void { - assert(output.output_v1 == river_output_v1); + assert(output.river_output_v1 == river_output_v1); switch (event) { - .removed => { - river_output_v1.destroy(); - utils.allocator.destroy(output); - }, - .wl_output => { - // log.debug("initializing new river_output_v1 corresponding to wl_output: {d}", .{ev.name}); + .removed => output.destroy(), + .wl_output => |ev| { + log.debug("initializing new river_output_v1 corresponding to wl_output: {d}", .{ev.name}); }, .dimensions => |ev| { output.width = ev.width; output.height = ev.height; }, .position => |ev| { + // TODO - CONFIG: Allow setting output position (do I even need to do this?) output.x = ev.x; output.y = ev.y; }, diff --git a/src/Seat.zig b/src/Seat.zig index 5abd1c6..fbe6839 100644 --- a/src/Seat.zig +++ b/src/Seat.zig @@ -6,7 +6,7 @@ const Seat = @This(); context: *Context, -seat_v1: *river.SeatV1, +river_seat_v1: *river.SeatV1, focused: ?*Window, @@ -25,26 +25,33 @@ pub const PendingManage = struct { }; }; -pub fn init(seat: *Seat, context: *Context, river_seat_v1: *river.SeatV1) void { +pub fn create(context: *Context, river_seat_v1: *river.SeatV1) !*Seat { + var seat = try utils.allocator.create(Seat); + errdefer seat.destroy(); + seat.* = .{ .context = context, - .seat_v1 = river_seat_v1, + .river_seat_v1 = river_seat_v1, .focused = null, .link = undefined, // Handled by the wl.list }; - seat.seat_v1.setListener(*Seat, seatListener, seat); + seat.river_seat_v1.setListener(*Seat, seatListener, seat); + + return seat; +} + +pub fn destroy(seat: *Seat) void { + seat.river_seat_v1.destroy(); + utils.allocator.destroy(seat); } fn seatListener(river_seat_v1: *river.SeatV1, event: river.SeatV1.Event, seat: *Seat) void { - assert(seat.seat_v1 == river_seat_v1); + assert(seat.river_seat_v1 == river_seat_v1); switch (event) { - .removed => { - river_seat_v1.destroy(); - utils.allocator.destroy(seat); - }, - .wl_seat => { - // log.debug("initializing new river_seat_v1 corresponding to wl_seat: {d}", .{ev.name}); + .removed => seat.destroy(), + .wl_seat => |ev| { + log.debug("initializing new river_seat_v1 corresponding to wl_seat: {d}", .{ev.name}); }, .pointer_enter => |ev| seat.setWindowFocus(ev.window), .window_interaction => |ev| seat.setWindowFocus(ev.window), @@ -54,8 +61,9 @@ fn seatListener(river_seat_v1: *river.SeatV1, event: river.SeatV1.Event, seat: * } } -fn setWindowFocus(seat: *Seat, window_v1: ?*river.WindowV1) void { - const wv1 = window_v1 orelse return; +// river_window_v1 needs to be optional because ev.window is optional +fn setWindowFocus(seat: *Seat, river_window_v1: ?*river.WindowV1) void { + const wv1 = river_window_v1 orelse return; const window: *Window = @ptrCast(@alignCast(wv1.getUserData())); seat.pending_manage.pending_focus = .{ .window = window }; } @@ -73,7 +81,7 @@ pub fn manage(seat: *Seat) void { } } seat.focused = window; - seat.seat_v1.focusWindow(window.window_v1); + seat.river_seat_v1.focusWindow(window.river_window_v1); window.pending_render.focused = true; }, .clear_focus => { @@ -82,23 +90,23 @@ pub fn manage(seat: *Seat) void { focused.pending_render.focused = false; } seat.focused = null; - seat.seat_v1.clearFocus(); + seat.river_seat_v1.clearFocus(); }, } } if (seat.pending_manage.should_warp_pointer) { const window = seat.focused orelse { - log.err("Trying to warp pointer without focused window.", .{}); + log.err("Trying to warp-on-focus-change without a focused window.", .{}); return; }; // TODO - CONFIG: Allow disabling this behaviour // Warp pointer to center of focused window; - // because the x and y coords are set later, we need to check them here. + // because the x and y coords are set during render, we need to check if + // there are new coordinates in window.pending_render. const pointer_x: i32 = (window.pending_render.x orelse window.x) + @divTrunc(window.width, 2); const pointer_y: i32 = (window.pending_render.y orelse window.y) + @divTrunc(window.height, 2); - seat.seat_v1.pointerWarp(pointer_x, pointer_y); - log.debug("warped pointer to {}, {}", .{ pointer_x, pointer_y }); + seat.river_seat_v1.pointerWarp(pointer_x, pointer_y); } } diff --git a/src/Window.zig b/src/Window.zig index 058a5a0..f3b2137 100644 --- a/src/Window.zig +++ b/src/Window.zig @@ -6,8 +6,8 @@ const Window = @This(); context: *Context, -window_v1: *river.WindowV1, -node_v1: *river.NodeV1, +river_window_v1: *river.WindowV1, +river_node_v1: *river.NodeV1, width: u31 = 0, height: u31 = 0, @@ -17,6 +17,9 @@ y: i32 = 0, fullscreen: bool = false, maximized: bool = false, +tags: u32 = 0x0001, +output: ?*Output, + initialized: bool = false, /// State consumed in manage() phase, reset at end of manage(). @@ -42,23 +45,40 @@ pub const PendingRender = struct { focused: ?bool = null, }; -pub fn init(window: *Window, context: *Context, river_window_v1: *river.WindowV1) void { +pub fn create(context: *Context, river_window_v1: *river.WindowV1, output: ?*Output) !*Window { + var window = try utils.allocator.create(Window); + errdefer window.destroy(); + window.* = .{ .context = context, - .window_v1 = river_window_v1, - .node_v1 = river_window_v1.getNode() catch @panic("Failed to get node"), + .river_window_v1 = river_window_v1, + .river_node_v1 = river_window_v1.getNode() catch @panic("Failed to get node"), + .output = output, .link = undefined, // Handled by the wl.list }; - window.window_v1.setListener(*Window, windowListener, window); + if (output) |out| { + window.tags = if (out.tags != 0) out.tags else 0x0001; + } else { + window.tags = 0x0001; + } + + window.river_window_v1.setListener(*Window, windowListener, window); + + return window; +} + +pub fn destroy(window: *Window) void { + window.river_window_v1.destroy(); + window.river_node_v1.destroy(); + + utils.allocator.destroy(window); } fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event, window: *Window) void { - assert(window.window_v1 == river_window_v1); + assert(window.river_window_v1 == river_window_v1); switch (event) { .closed => { - river_window_v1.destroy(); - window.node_v1.destroy(); window.context.wm.window_count -= 1; { var it = window.context.wm.seats.iterator(.forward); @@ -80,7 +100,7 @@ fn windowListener(river_window_v1: *river.WindowV1, event: river.WindowV1.Event, } } window.link.remove(); - utils.allocator.destroy(window); + window.destroy(); }, .dimensions => |ev| { // The protocol requires these are strictly greather than zero. @@ -104,10 +124,10 @@ pub fn manage(window: *Window) void { // TODO: We might want to think about paying attention to the decoration_hint event // If we do, this would need to move, I think? - window.window_v1.useSsd(); + window.river_window_v1.useSsd(); - window.window_v1.setCapabilities(.{ .fullscreen = true, .maximize = true }); - window.window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); + window.river_window_v1.setCapabilities(.{ .fullscreen = true, .maximize = true }); + window.river_window_v1.setTiled(.{ .top = true, .bottom = true, .left = true, .right = true }); } // Any new state since the last manage event @@ -118,7 +138,7 @@ pub fn manage(window: *Window) void { if (pending_manage.height) |new_height| { window.width = new_width; window.height = new_height; - window.window_v1.proposeDimensions(new_width, new_height); + window.river_window_v1.proposeDimensions(new_width, new_height); } } @@ -127,19 +147,19 @@ pub fn manage(window: *Window) void { window.fullscreen = fullscreen; if (fullscreen) { const output = window.context.wm.outputs.first() orelse @panic("Failed to get output"); - window.window_v1.fullscreen(output.output_v1); - window.window_v1.informFullscreen(); + window.river_window_v1.fullscreen(output.river_output_v1); + window.river_window_v1.informFullscreen(); } else { - window.window_v1.exitFullscreen(); - window.window_v1.informNotFullscreen(); + window.river_window_v1.exitFullscreen(); + window.river_window_v1.informNotFullscreen(); } } if (pending_manage.maximized) |maximized| { window.maximized = maximized; if (maximized) { - window.window_v1.informMaximized(); + window.river_window_v1.informMaximized(); } else { - window.window_v1.informUnmaximized(); + window.river_window_v1.informUnmaximized(); } } } @@ -154,7 +174,7 @@ pub fn render(window: *Window) void { window.x = new_x; window.y = new_y; - window.node_v1.setPosition(window.x, window.y); + window.river_node_v1.setPosition(window.x, window.y); } else { log.err("Window.pending_render with only x set", .{}); } @@ -177,7 +197,7 @@ pub fn render(window: *Window) void { fn applyBorders(window: *Window, color: utils.RiverColor) void { const border_width = window.context.config.border_width; const all_sides = river.WindowV1.Edges{ .top = true, .bottom = true, .left = true, .right = true }; - window.window_v1.setBorders(all_sides, border_width, color.red, color.green, color.blue, color.alpha); + window.river_window_v1.setBorders(all_sides, border_width, color.red, color.green, color.blue, color.alpha); } const std = @import("std"); @@ -189,5 +209,6 @@ const river = wayland.client.river; const utils = @import("utils.zig"); const Context = @import("Context.zig"); +const Output = @import("Output.zig"); const log = std.log.scoped(.Window); diff --git a/src/WindowManager.zig b/src/WindowManager.zig index 0c8cc0e..78d86af 100644 --- a/src/WindowManager.zig +++ b/src/WindowManager.zig @@ -42,24 +42,20 @@ pub fn create(context: *Context, window_manager_v1: *river.WindowManagerV1) !*Wi pub fn destroy(wm: *WindowManager) void { var window_it = wm.windows.iterator(.forward); while (window_it.next()) |window| { - window.window_v1.destroy(); - window.node_v1.destroy(); window.link.remove(); - utils.allocator.destroy(window); + window.destroy(); } var output_it = wm.outputs.iterator(.forward); while (output_it.next()) |output| { - output.output_v1.destroy(); output.link.remove(); - utils.allocator.destroy(output); + output.destroy(); } var seat_it = wm.seats.iterator(.forward); while (seat_it.next()) |seat| { - seat.seat_v1.destroy(); seat.link.remove(); - utils.allocator.destroy(seat); + seat.destroy(); } utils.allocator.destroy(wm); @@ -164,7 +160,6 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv std.posix.exit(1); }, .manage_start => { - log.debug("manage start", .{}); if (!context.initialized) { // This code (should) only be run once while initializing the WM, so let's // mark it as cold. @@ -172,7 +167,7 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv context.initialized = true; const seat = wm.seats.first() orelse @panic("Failed to get seat"); - const river_seat_v1 = seat.seat_v1; + const river_seat_v1 = seat.river_seat_v1; context.xkb_bindings.addBinding(river_seat_v1, xkbcommon.Keysym.t, .{ .mod4 = true }, .{ .spawn = &.{"foot"} }); context.xkb_bindings.addBinding(river_seat_v1, xkbcommon.Keysym.j, .{ .mod4 = true }, .focus_next); context.xkb_bindings.addBinding(river_seat_v1, xkbcommon.Keysym.k, .{ .mod4 = true }, .focus_prev); @@ -202,10 +197,8 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv } } window_manager_v1.manageFinish(); - log.debug("manage end===================", .{}); }, .render_start => { - log.debug("render start", .{}); { var it = wm.seats.iterator(.forward); while (it.next()) |seat| { @@ -225,12 +218,11 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv } } window_manager_v1.renderFinish(); - log.debug("render end==================", .{}); }, .output => |ev| { + log.debug("initializing new wl_output: {d}", .{ev.id.getId()}); // TODO: Support multi-output - var output = utils.allocator.create(Output) catch @panic("Out of memory"); - output.init(context, ev.id); + const output = Output.create(context, ev.id) catch @panic("Out of memory"); wm.outputs.append(output); }, .seat => |ev| { @@ -242,17 +234,17 @@ fn windowManagerV1Listener(window_manager_v1: *river.WindowManagerV1, event: riv utils.versionNotSupported(river.SeatV1, river_seat_v1_version, MIN_RIVER_SEAT_V1_VERSION); } - var seat = utils.allocator.create(Seat) catch @panic("Out of memory"); - seat.init(context, river_seat_v1); + const seat = Seat.create(context, river_seat_v1) catch @panic("Out of memory"); wm.seats.append(seat); }, .window => |ev| { - var window = utils.allocator.create(Window) catch @panic("Out of memory"); - window.init(context, ev.id); + const seat = wm.seats.first() orelse @panic("Failed to get seat"); + // TODO: Support multiple outputs + const output = wm.outputs.first() orelse @panic("Failed to get output"); + const window = Window.create(context, ev.id, output) catch @panic("Out of memory"); // TODO - CONFIG: Allow appending window instead of prepending wm.windows.prepend(window); - const seat = wm.seats.first() orelse @panic("Failed to get seat"); seat.pending_manage.pending_focus = .{ .window = window }; seat.pending_manage.should_warp_pointer = true; diff --git a/src/XkbBindings.zig b/src/XkbBindings.zig index e31bdfb..59f38fc 100644 --- a/src/XkbBindings.zig +++ b/src/XkbBindings.zig @@ -19,7 +19,10 @@ const XkbBinding = struct { context: *Context, link: wl.list.Link, - fn init(xkb_binding: *XkbBinding, xkb_binding_v1: *river.XkbBindingV1, command: Command, context: *Context) void { + fn create(xkb_binding_v1: *river.XkbBindingV1, command: Command, context: *Context) !*XkbBinding { + var xkb_binding = try utils.allocator.create(XkbBinding); + errdefer xkb_binding.destroy(); + xkb_binding.* = .{ .xkb_binding_v1 = xkb_binding_v1, .command = command, @@ -28,6 +31,13 @@ const XkbBinding = struct { }; xkb_binding.xkb_binding_v1.setListener(*XkbBinding, xkbBindingListener, xkb_binding); + + return xkb_binding; + } + + fn destroy(xkb_binding: *XkbBinding) void { + xkb_binding.xkb_binding_v1.destroy(); + utils.allocator.destroy(xkb_binding); } fn xkbBindingListener(xkb_binding_v1: *river.XkbBindingV1, event: river.XkbBindingV1.Event, xkb_binding: *XkbBinding) void { @@ -93,7 +103,7 @@ const XkbBinding = struct { .close_window => { const seat = context.wm.seats.first() orelse return; if (seat.focused) |window| { - window.window_v1.close(); + window.river_window_v1.close(); } }, .exit => { @@ -141,8 +151,7 @@ pub fn addBinding(xkb_bindings: *XkbBindings, river_seat_v1: *river.SeatV1, keys return; }; - const xkb_binding = utils.allocator.create(XkbBinding) catch @panic("Out of memory"); - xkb_binding.init(xkb_binding_v1, command, xkb_bindings.context); + const xkb_binding = XkbBinding.create(xkb_binding_v1, command, xkb_bindings.context) catch @panic("Out of memory"); xkb_bindings.bindings.append(xkb_binding); xkb_binding_v1.enable();