code: handle out of memory as well as possible
This commit is contained in:
		@ -130,7 +130,7 @@ const ScanProtocolsStep = struct {
 | 
				
			|||||||
    step: std.build.Step,
 | 
					    step: std.build.Step,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn create(builder: *std.build.Builder) *ScanProtocolsStep {
 | 
					    fn create(builder: *std.build.Builder) *ScanProtocolsStep {
 | 
				
			||||||
        const self = builder.allocator.create(ScanProtocolsStep) catch unreachable;
 | 
					        const self = builder.allocator.create(ScanProtocolsStep) catch @panic("out of memory");
 | 
				
			||||||
        self.* = init(builder);
 | 
					        self.* = init(builder);
 | 
				
			||||||
        return self;
 | 
					        return self;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -225,7 +225,7 @@ const ScdocStep = struct {
 | 
				
			|||||||
    step: std.build.Step,
 | 
					    step: std.build.Step,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn create(builder: *std.build.Builder) *ScdocStep {
 | 
					    fn create(builder: *std.build.Builder) *ScdocStep {
 | 
				
			||||||
        const self = builder.allocator.create(ScdocStep) catch unreachable;
 | 
					        const self = builder.allocator.create(ScdocStep) catch @panic("out of memory");
 | 
				
			||||||
        self.* = init(builder);
 | 
					        self.* = init(builder);
 | 
				
			||||||
        return self;
 | 
					        return self;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -22,10 +22,6 @@ const std = @import("std");
 | 
				
			|||||||
const c = @import("c.zig");
 | 
					const c = @import("c.zig");
 | 
				
			||||||
const util = @import("util.zig");
 | 
					const util = @import("util.zig");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DecorationManager = @import("DecorationManager.zig");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: this needs to listen for destroy and free nodes from the deco list
 | 
					 | 
				
			||||||
decoration_manager: *DecorationManager,
 | 
					 | 
				
			||||||
wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1,
 | 
					wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
listen_destroy: c.wl_listener,
 | 
					listen_destroy: c.wl_listener,
 | 
				
			||||||
@ -33,10 +29,8 @@ listen_request_mode: c.wl_listener,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub fn init(
 | 
					pub fn init(
 | 
				
			||||||
    self: *Self,
 | 
					    self: *Self,
 | 
				
			||||||
    decoration_manager: *DecorationManager,
 | 
					 | 
				
			||||||
    wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1,
 | 
					    wlr_xdg_toplevel_decoration: *c.wlr_xdg_toplevel_decoration_v1,
 | 
				
			||||||
) void {
 | 
					) void {
 | 
				
			||||||
    self.decoration_manager = decoration_manager;
 | 
					 | 
				
			||||||
    self.wlr_xdg_toplevel_decoration = wlr_xdg_toplevel_decoration;
 | 
					    self.wlr_xdg_toplevel_decoration = wlr_xdg_toplevel_decoration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self.listen_destroy.notify = handleDestroy;
 | 
					    self.listen_destroy.notify = handleDestroy;
 | 
				
			||||||
@ -50,17 +44,13 @@ pub fn init(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
					fn handleDestroy(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			||||||
    const self = @fieldParentPtr(Self, "listen_destroy", listener.?);
 | 
					    const self = @fieldParentPtr(Self, "listen_destroy", listener.?);
 | 
				
			||||||
    const node = @fieldParentPtr(std.SinglyLinkedList(Self).Node, "data", self);
 | 
					    util.gpa.destroy(self);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    self.decoration_manager.decorations.remove(node);
 | 
					 | 
				
			||||||
    util.gpa.destroy(node);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn handleRequestMode(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
					fn handleRequestMode(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			||||||
    const self = @fieldParentPtr(Self, "listen_request_mode", listener.?);
 | 
					    const self = @fieldParentPtr(Self, "listen_request_mode", listener.?);
 | 
				
			||||||
    // TODO: we might need to take this configure serial and do a transaction
 | 
					 | 
				
			||||||
    _ = c.wlr_xdg_toplevel_decoration_v1_set_mode(
 | 
					    _ = c.wlr_xdg_toplevel_decoration_v1_set_mode(
 | 
				
			||||||
        self.wlr_xdg_toplevel_decoration,
 | 
					        self.wlr_xdg_toplevel_decoration,
 | 
				
			||||||
        c.wlr_xdg_toplevel_decoration_v1_mode.WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE,
 | 
					        .WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -46,7 +46,9 @@ fn handleNewToplevelDecoration(listener: ?*c.wl_listener, data: ?*c_void) callco
 | 
				
			|||||||
    const self = @fieldParentPtr(Self, "listen_new_toplevel_decoration", listener.?);
 | 
					    const self = @fieldParentPtr(Self, "listen_new_toplevel_decoration", listener.?);
 | 
				
			||||||
    const wlr_xdg_toplevel_decoration = util.voidCast(c.wlr_xdg_toplevel_decoration_v1, data.?);
 | 
					    const wlr_xdg_toplevel_decoration = util.voidCast(c.wlr_xdg_toplevel_decoration_v1, data.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const node = self.decorations.allocateNode(util.gpa) catch unreachable;
 | 
					    const decoration = util.gpa.create(Decoration) catch {
 | 
				
			||||||
    node.data.init(self, wlr_xdg_toplevel_decoration);
 | 
					        c.wl_resource_post_no_memory(wlr_xdg_toplevel_decoration.resource);
 | 
				
			||||||
    self.decorations.prepend(node);
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    decoration.init(wlr_xdg_toplevel_decoration);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -140,7 +140,5 @@ fn handleNewInput(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			|||||||
    const device = util.voidCast(c.wlr_input_device, data.?);
 | 
					    const device = util.voidCast(c.wlr_input_device, data.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: suport multiple seats
 | 
					    // TODO: suport multiple seats
 | 
				
			||||||
    if (self.seats.first) |seat_node| {
 | 
					    self.default_seat.addDevice(device);
 | 
				
			||||||
        seat_node.data.addDevice(device) catch unreachable;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -191,6 +191,9 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			|||||||
    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
					    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This will free itself on destroy
 | 
					    // This will free itself on destroy
 | 
				
			||||||
    var xdg_popup = util.gpa.create(XdgPopup) catch unreachable;
 | 
					    var xdg_popup = util.gpa.create(XdgPopup) catch {
 | 
				
			||||||
 | 
					        c.wl_resource_post_no_memory(wlr_xdg_popup.resource);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    xdg_popup.init(self.output, &self.box, wlr_xdg_popup);
 | 
					    xdg_popup.init(self.output, &self.box, wlr_xdg_popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -86,13 +86,19 @@ pub fn deinit(self: *Self) void {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    c.wlr_output_layout_destroy(self.wlr_output_layout);
 | 
					    c.wlr_output_layout_destroy(self.wlr_output_layout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // This literally cannot fail, but for some reason returns 0
 | 
				
			||||||
    if (c.wl_event_source_remove(self.transaction_timer) < 0) unreachable;
 | 
					    if (c.wl_event_source_remove(self.transaction_timer) < 0) unreachable;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn addOutput(self: *Self, wlr_output: *c.wlr_output) void {
 | 
					pub fn addOutput(self: *Self, wlr_output: *c.wlr_output) void {
 | 
				
			||||||
    // TODO: Handle failure
 | 
					    const node = self.outputs.allocateNode(util.gpa) catch {
 | 
				
			||||||
    const node = self.outputs.allocateNode(util.gpa) catch unreachable;
 | 
					        c.wlr_output_destroy(wlr_output);
 | 
				
			||||||
    node.data.init(self, wlr_output) catch unreachable;
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    node.data.init(self, wlr_output) catch {
 | 
				
			||||||
 | 
					        c.wlr_output_destroy(wlr_output);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    self.outputs.append(node);
 | 
					    self.outputs.append(node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // if we previously had no real outputs, move focus from the noop output
 | 
					    // if we previously had no real outputs, move focus from the noop output
 | 
				
			||||||
 | 
				
			|||||||
@ -157,9 +157,7 @@ pub fn focus(self: *Self, _view: ?*View) void {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            // The view is not in the stack, so allocate a new node and prepend it
 | 
					            // The view is not in the stack, so allocate a new node and prepend it
 | 
				
			||||||
            const new_focus_node = util.gpa.create(
 | 
					            const new_focus_node = util.gpa.create(ViewStack(*View).Node) catch return;
 | 
				
			||||||
                ViewStack(*View).Node,
 | 
					 | 
				
			||||||
            ) catch unreachable;
 | 
					 | 
				
			||||||
            new_focus_node.view = view_to_focus;
 | 
					            new_focus_node.view = view_to_focus;
 | 
				
			||||||
            self.focus_stack.push(new_focus_node);
 | 
					            self.focus_stack.push(new_focus_node);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -305,30 +303,32 @@ pub fn handleMapping(self: *Self, keysym: c.xkb_keysym_t, modifiers: u32) bool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// Add a newly created input device to the seat and update the reported
 | 
					/// Add a newly created input device to the seat and update the reported
 | 
				
			||||||
/// capabilities.
 | 
					/// capabilities.
 | 
				
			||||||
pub fn addDevice(self: *Self, device: *c.wlr_input_device) !void {
 | 
					pub fn addDevice(self: *Self, device: *c.wlr_input_device) void {
 | 
				
			||||||
    switch (device.type) {
 | 
					    switch (device.type) {
 | 
				
			||||||
        .WLR_INPUT_DEVICE_KEYBOARD => self.addKeyboard(device) catch unreachable,
 | 
					        .WLR_INPUT_DEVICE_KEYBOARD => self.addKeyboard(device) catch return,
 | 
				
			||||||
        .WLR_INPUT_DEVICE_POINTER => self.addPointer(device),
 | 
					        .WLR_INPUT_DEVICE_POINTER => self.addPointer(device),
 | 
				
			||||||
        else => {},
 | 
					        else => return,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // We need to let the wlr_seat know what our capabilities are, which is
 | 
					    // We need to let the wlr_seat know what our capabilities are, which is
 | 
				
			||||||
    // communiciated to the client. We always have a cursor, even if
 | 
					    // communiciated to the client. We always have a cursor, even if
 | 
				
			||||||
    // there are no pointer devices, so we always include that capability.
 | 
					    // there are no pointer devices, so we always include that capability.
 | 
				
			||||||
    var caps = @intCast(u32, c.WL_SEAT_CAPABILITY_POINTER);
 | 
					    var caps = @intCast(u32, c.WL_SEAT_CAPABILITY_POINTER);
 | 
				
			||||||
    // if list not empty
 | 
					    if (self.keyboards.len > 0) caps |= @intCast(u32, c.WL_SEAT_CAPABILITY_KEYBOARD);
 | 
				
			||||||
    if (self.keyboards.len > 0) {
 | 
					 | 
				
			||||||
        caps |= @intCast(u32, c.WL_SEAT_CAPABILITY_KEYBOARD);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    c.wlr_seat_set_capabilities(self.wlr_seat, caps);
 | 
					    c.wlr_seat_set_capabilities(self.wlr_seat, caps);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn addKeyboard(self: *Self, device: *c.wlr_input_device) !void {
 | 
					fn addKeyboard(self: *Self, device: *c.wlr_input_device) !void {
 | 
				
			||||||
    c.wlr_seat_set_keyboard(self.wlr_seat, device);
 | 
					    const node = try self.keyboards.allocateNode(util.gpa);
 | 
				
			||||||
 | 
					    node.data.init(self, device) catch |err| {
 | 
				
			||||||
    const node = try util.gpa.create(std.TailQueue(Keyboard).Node);
 | 
					        switch (err) {
 | 
				
			||||||
    try node.data.init(self, device);
 | 
					            error.CreateXkbContextError => log.err(.keyboard, "Failed to create XKB context", .{}),
 | 
				
			||||||
 | 
					            error.CreateXkbKeymapError => log.err(.keyboard, "Failed to create XKB keymap", .{}),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    self.keyboards.append(node);
 | 
					    self.keyboards.append(node);
 | 
				
			||||||
 | 
					    c.wlr_seat_set_keyboard(self.wlr_seat, device);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn addPointer(self: Self, device: *c.struct_wlr_input_device) void {
 | 
					fn addPointer(self: Self, device: *c.struct_wlr_input_device) void {
 | 
				
			||||||
 | 
				
			|||||||
@ -180,7 +180,10 @@ fn handleNewXdgSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) v
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // The View will add itself to the output's view stack on map
 | 
					    // The View will add itself to the output's view stack on map
 | 
				
			||||||
    const output = self.input_manager.default_seat.focused_output;
 | 
					    const output = self.input_manager.default_seat.focused_output;
 | 
				
			||||||
    const node = util.gpa.create(ViewStack(View).Node) catch unreachable;
 | 
					    const node = util.gpa.create(ViewStack(View).Node) catch {
 | 
				
			||||||
 | 
					        c.wl_resource_post_no_memory(wlr_xdg_surface.resource);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    node.view.init(output, output.current.tags, wlr_xdg_surface);
 | 
					    node.view.init(output, output.current.tags, wlr_xdg_surface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -230,7 +233,10 @@ fn handleNewLayerSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // The layer surface will add itself to the proper list of the output on map
 | 
					    // The layer surface will add itself to the proper list of the output on map
 | 
				
			||||||
    const output = util.voidCast(Output, wlr_layer_surface.output.*.data.?);
 | 
					    const output = util.voidCast(Output, wlr_layer_surface.output.*.data.?);
 | 
				
			||||||
    const node = util.gpa.create(std.TailQueue(LayerSurface).Node) catch unreachable;
 | 
					    const node = util.gpa.create(std.TailQueue(LayerSurface).Node) catch {
 | 
				
			||||||
 | 
					        c.wl_resource_post_no_memory(wlr_layer_surface.resource);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    node.data.init(output, wlr_layer_surface);
 | 
					    node.data.init(output, wlr_layer_surface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -242,7 +248,7 @@ fn handleNewXwaylandSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(
 | 
				
			|||||||
        log.debug(.server, "new unmanaged xwayland surface", .{});
 | 
					        log.debug(.server, "new unmanaged xwayland surface", .{});
 | 
				
			||||||
        // The unmanged surface will add itself to the list of unmanaged views
 | 
					        // The unmanged surface will add itself to the list of unmanaged views
 | 
				
			||||||
        // in Root when it is mapped.
 | 
					        // in Root when it is mapped.
 | 
				
			||||||
        const node = util.gpa.create(std.TailQueue(XwaylandUnmanaged).Node) catch unreachable;
 | 
					        const node = util.gpa.create(std.TailQueue(XwaylandUnmanaged).Node) catch return;
 | 
				
			||||||
        node.data.init(&self.root, wlr_xwayland_surface);
 | 
					        node.data.init(&self.root, wlr_xwayland_surface);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -255,6 +261,6 @@ fn handleNewXwaylandSurface(listener: ?*c.wl_listener, data: ?*c_void) callconv(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // The View will add itself to the output's view stack on map
 | 
					    // The View will add itself to the output's view stack on map
 | 
				
			||||||
    const output = self.input_manager.default_seat.focused_output;
 | 
					    const output = self.input_manager.default_seat.focused_output;
 | 
				
			||||||
    const node = util.gpa.create(ViewStack(View).Node) catch unreachable;
 | 
					    const node = util.gpa.create(ViewStack(View).Node) catch return;
 | 
				
			||||||
    node.view.init(output, output.current.tags, wlr_xwayland_surface);
 | 
					    node.view.init(output, output.current.tags, wlr_xwayland_surface);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -76,6 +76,9 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			|||||||
    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
					    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This will free itself on destroy
 | 
					    // This will free itself on destroy
 | 
				
			||||||
    var xdg_popup = util.gpa.create(Self) catch unreachable;
 | 
					    var xdg_popup = util.gpa.create(Self) catch {
 | 
				
			||||||
 | 
					        c.wl_resource_post_no_memory(wlr_xdg_popup.resource);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    xdg_popup.init(self.output, self.parent_box, wlr_xdg_popup);
 | 
					    xdg_popup.init(self.output, self.parent_box, wlr_xdg_popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -253,7 +253,10 @@ fn handleNewPopup(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
				
			|||||||
    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
					    const wlr_xdg_popup = util.voidCast(c.wlr_xdg_popup, data.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // This will free itself on destroy
 | 
					    // This will free itself on destroy
 | 
				
			||||||
    var xdg_popup = util.gpa.create(XdgPopup) catch unreachable;
 | 
					    var xdg_popup = util.gpa.create(XdgPopup) catch {
 | 
				
			||||||
 | 
					        c.wl_resource_post_no_memory(wlr_xdg_popup.resource);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
    xdg_popup.init(self.view.output, &self.view.current.box, wlr_xdg_popup);
 | 
					    xdg_popup.init(self.view.output, &self.view.current.box, wlr_xdg_popup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user