Properly clean up resources on exit
This commit is contained in:
		
							
								
								
									
										288
									
								
								src/cursor.zig
									
									
									
									
									
								
							
							
						
						
									
										288
									
								
								src/cursor.zig
									
									
									
									
									
								
							@ -17,14 +17,6 @@ pub const Cursor = struct {
 | 
			
		||||
    wlr_cursor: *c.wlr_cursor,
 | 
			
		||||
    wlr_xcursor_manager: *c.wlr_xcursor_manager,
 | 
			
		||||
 | 
			
		||||
    listen_motion: c.wl_listener,
 | 
			
		||||
    listen_motion_absolute: c.wl_listener,
 | 
			
		||||
    listen_button: c.wl_listener,
 | 
			
		||||
    listen_axis: c.wl_listener,
 | 
			
		||||
    listen_frame: c.wl_listener,
 | 
			
		||||
 | 
			
		||||
    listen_request_set_cursor: c.wl_listener,
 | 
			
		||||
 | 
			
		||||
    mode: CursorMode,
 | 
			
		||||
    grabbed_view: ?*View,
 | 
			
		||||
    grab_x: f64,
 | 
			
		||||
@ -33,6 +25,13 @@ pub const Cursor = struct {
 | 
			
		||||
    grab_height: c_int,
 | 
			
		||||
    resize_edges: u32,
 | 
			
		||||
 | 
			
		||||
    listen_axis: c.wl_listener,
 | 
			
		||||
    listen_button: c.wl_listener,
 | 
			
		||||
    listen_frame: c.wl_listener,
 | 
			
		||||
    listen_motion_absolute: c.wl_listener,
 | 
			
		||||
    listen_motion: c.wl_listener,
 | 
			
		||||
    listen_request_set_cursor: c.wl_listener,
 | 
			
		||||
 | 
			
		||||
    pub fn init(self: *Self, seat: *Seat) !void {
 | 
			
		||||
        self.seat = seat;
 | 
			
		||||
 | 
			
		||||
@ -68,31 +67,99 @@ pub const Cursor = struct {
 | 
			
		||||
        // can choose how we want to process them, forwarding them to clients and
 | 
			
		||||
        // moving the cursor around. See following post for more detail:
 | 
			
		||||
        // https://drewdevault.com/2018/07/17/Input-handling-in-wlroots.html
 | 
			
		||||
        self.listen_motion.notify = handleMotion;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.motion, &self.listen_motion);
 | 
			
		||||
 | 
			
		||||
        self.listen_motion_absolute.notify = handleMotionAbsolute;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.motion_absolute, &self.listen_motion_absolute);
 | 
			
		||||
        self.listen_axis.notify = handleAxis;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.axis, &self.listen_axis);
 | 
			
		||||
 | 
			
		||||
        self.listen_button.notify = handleButton;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.button, &self.listen_button);
 | 
			
		||||
 | 
			
		||||
        self.listen_axis.notify = handleAxis;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.axis, &self.listen_axis);
 | 
			
		||||
 | 
			
		||||
        self.listen_frame.notify = handleFrame;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.frame, &self.listen_frame);
 | 
			
		||||
 | 
			
		||||
        // This listens for clients requesting a specific cursor image
 | 
			
		||||
        self.listen_motion_absolute.notify = handleMotionAbsolute;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.motion_absolute, &self.listen_motion_absolute);
 | 
			
		||||
 | 
			
		||||
        self.listen_motion.notify = handleMotion;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_cursor.events.motion, &self.listen_motion);
 | 
			
		||||
 | 
			
		||||
        self.listen_request_set_cursor.notify = handleRequestSetCursor;
 | 
			
		||||
        c.wl_signal_add(&self.seat.wlr_seat.events.request_set_cursor, &self.listen_request_set_cursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn destroy(self: Self) void {
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        c.wlr_xcursor_manager_destroy(self.wlr_xcursor_manager);
 | 
			
		||||
        c.wlr_cursor_destroy(self.wlr_cursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleAxis(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an axis event,
 | 
			
		||||
        // for example when you move the scroll wheel.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_axis", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_axis,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_axis), data),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Notify the client with pointer focus of the axis event.
 | 
			
		||||
        c.wlr_seat_pointer_notify_axis(
 | 
			
		||||
            cursor.seat.wlr_seat,
 | 
			
		||||
            event.time_msec,
 | 
			
		||||
            event.orientation,
 | 
			
		||||
            event.delta,
 | 
			
		||||
            event.delta_discrete,
 | 
			
		||||
            event.source,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleButton(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits a button
 | 
			
		||||
        // event.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_button", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_button,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_button), data),
 | 
			
		||||
        );
 | 
			
		||||
        // Notify the client with pointer focus that a button press has occurred
 | 
			
		||||
        _ = c.wlr_seat_pointer_notify_button(
 | 
			
		||||
            cursor.seat.wlr_seat,
 | 
			
		||||
            event.time_msec,
 | 
			
		||||
            event.button,
 | 
			
		||||
            event.state,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        var sx: f64 = undefined;
 | 
			
		||||
        var sy: f64 = undefined;
 | 
			
		||||
 | 
			
		||||
        var surface: ?*c.wlr_surface = null;
 | 
			
		||||
        const view = cursor.seat.input_manager.server.root.viewAt(
 | 
			
		||||
            cursor.wlr_cursor.x,
 | 
			
		||||
            cursor.wlr_cursor.y,
 | 
			
		||||
            &surface,
 | 
			
		||||
            &sx,
 | 
			
		||||
            &sy,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (event.state == c.enum_wlr_button_state.WLR_BUTTON_RELEASED) {
 | 
			
		||||
            // If you released any buttons, we exit interactive move/resize mode.
 | 
			
		||||
            cursor.mode = CursorMode.Passthrough;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Focus that client if the button was _pressed_
 | 
			
		||||
            if (view) |v| {
 | 
			
		||||
                cursor.seat.focus(v);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleFrame(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an frame
 | 
			
		||||
        // event. Frame events are sent after regular pointer events to group
 | 
			
		||||
        // multiple events together. For instance, two axis events may happen at the
 | 
			
		||||
        // same time, in which case a frame event won't be sent in between.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_frame", listener.?);
 | 
			
		||||
        // Notify the client with pointer focus of the frame event.
 | 
			
		||||
        c.wlr_seat_pointer_notify_frame(cursor.seat.wlr_seat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn processMove(self: Self, time: u32) void {
 | 
			
		||||
        // Move the grabbed view to the new position.
 | 
			
		||||
        // TODO: log on null
 | 
			
		||||
@ -102,6 +169,64 @@ pub const Cursor = struct {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleMotionAbsolute(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an _absolute_
 | 
			
		||||
        // motion event, from 0..1 on each axis. This happens, for example, when
 | 
			
		||||
        // wlroots is running under a Wayland window rather than KMS+DRM, and you
 | 
			
		||||
        // move the mouse over the window. You could enter the window from any edge,
 | 
			
		||||
        // so we have to warp the mouse there. There is also some hardware which
 | 
			
		||||
        // emits these events.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_motion_absolute", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_motion_absolute,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_motion_absolute), data),
 | 
			
		||||
        );
 | 
			
		||||
        c.wlr_cursor_warp_absolute(cursor.wlr_cursor, event.device, event.x, event.y);
 | 
			
		||||
        cursor.processMotion(event.time_msec);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleMotion(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits a _relative_
 | 
			
		||||
        // pointer motion event (i.e. a delta)
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_motion", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_motion,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_motion), data),
 | 
			
		||||
        );
 | 
			
		||||
        // The cursor doesn't move unless we tell it to. The cursor automatically
 | 
			
		||||
        // handles constraining the motion to the output layout, as well as any
 | 
			
		||||
        // special configuration applied for the specific input device which
 | 
			
		||||
        // generated the event. You can pass NULL for the device if you want to move
 | 
			
		||||
        // the cursor around without any input.
 | 
			
		||||
        c.wlr_cursor_move(cursor.wlr_cursor, event.device, event.delta_x, event.delta_y);
 | 
			
		||||
        cursor.processMotion(event.time_msec);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleRequestSetCursor(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is rasied by the seat when a client provides a cursor image
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_request_set_cursor", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_seat_pointer_request_set_cursor_event,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_seat_pointer_request_set_cursor_event), data),
 | 
			
		||||
        );
 | 
			
		||||
        const focused_client = cursor.seat.wlr_seat.pointer_state.focused_client;
 | 
			
		||||
 | 
			
		||||
        // This can be sent by any client, so we check to make sure this one is
 | 
			
		||||
        // actually has pointer focus first.
 | 
			
		||||
        if (focused_client == event.seat_client) {
 | 
			
		||||
            // Once we've vetted the client, we can tell the cursor to use the
 | 
			
		||||
            // provided surface as the cursor image. It will set the hardware cursor
 | 
			
		||||
            // on the output that it's currently on and continue to do so as the
 | 
			
		||||
            // cursor moves between outputs.
 | 
			
		||||
            c.wlr_cursor_set_surface(
 | 
			
		||||
                cursor.wlr_cursor,
 | 
			
		||||
                event.surface,
 | 
			
		||||
                event.hotspot_x,
 | 
			
		||||
                event.hotspot_y,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn processsResize(self: Self, time: u32) void {
 | 
			
		||||
        // Resizing the grabbed view can be a little bit complicated, because we
 | 
			
		||||
        // could be resizing from any corner or edge. This not only resizes the view
 | 
			
		||||
@ -205,131 +330,4 @@ pub const Cursor = struct {
 | 
			
		||||
            c.wlr_seat_pointer_clear_focus(wlr_seat);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleMotion(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits a _relative_
 | 
			
		||||
        // pointer motion event (i.e. a delta)
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_motion", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_motion,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_motion), data),
 | 
			
		||||
        );
 | 
			
		||||
        // The cursor doesn't move unless we tell it to. The cursor automatically
 | 
			
		||||
        // handles constraining the motion to the output layout, as well as any
 | 
			
		||||
        // special configuration applied for the specific input device which
 | 
			
		||||
        // generated the event. You can pass NULL for the device if you want to move
 | 
			
		||||
        // the cursor around without any input.
 | 
			
		||||
        c.wlr_cursor_move(cursor.wlr_cursor, event.device, event.delta_x, event.delta_y);
 | 
			
		||||
        cursor.processMotion(event.time_msec);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleMotionAbsolute(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an _absolute_
 | 
			
		||||
        // motion event, from 0..1 on each axis. This happens, for example, when
 | 
			
		||||
        // wlroots is running under a Wayland window rather than KMS+DRM, and you
 | 
			
		||||
        // move the mouse over the window. You could enter the window from any edge,
 | 
			
		||||
        // so we have to warp the mouse there. There is also some hardware which
 | 
			
		||||
        // emits these events.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_motion_absolute", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_motion_absolute,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_motion_absolute), data),
 | 
			
		||||
        );
 | 
			
		||||
        c.wlr_cursor_warp_absolute(cursor.wlr_cursor, event.device, event.x, event.y);
 | 
			
		||||
        cursor.processMotion(event.time_msec);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleButton(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits a button
 | 
			
		||||
        // event.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_button", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_button,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_button), data),
 | 
			
		||||
        );
 | 
			
		||||
        // Notify the client with pointer focus that a button press has occurred
 | 
			
		||||
        _ = c.wlr_seat_pointer_notify_button(
 | 
			
		||||
            cursor.seat.wlr_seat,
 | 
			
		||||
            event.time_msec,
 | 
			
		||||
            event.button,
 | 
			
		||||
            event.state,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        var sx: f64 = undefined;
 | 
			
		||||
        var sy: f64 = undefined;
 | 
			
		||||
 | 
			
		||||
        var surface: ?*c.wlr_surface = null;
 | 
			
		||||
        const view = cursor.seat.input_manager.server.root.viewAt(
 | 
			
		||||
            cursor.wlr_cursor.x,
 | 
			
		||||
            cursor.wlr_cursor.y,
 | 
			
		||||
            &surface,
 | 
			
		||||
            &sx,
 | 
			
		||||
            &sy,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (event.state == c.enum_wlr_button_state.WLR_BUTTON_RELEASED) {
 | 
			
		||||
            // If you released any buttons, we exit interactive move/resize mode.
 | 
			
		||||
            cursor.mode = CursorMode.Passthrough;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Focus that client if the button was _pressed_
 | 
			
		||||
            if (view) |v| {
 | 
			
		||||
                cursor.seat.focus(v);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleAxis(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an axis event,
 | 
			
		||||
        // for example when you move the scroll wheel.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_axis", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_event_pointer_axis,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_event_pointer_axis), data),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Notify the client with pointer focus of the axis event.
 | 
			
		||||
        c.wlr_seat_pointer_notify_axis(
 | 
			
		||||
            cursor.seat.wlr_seat,
 | 
			
		||||
            event.time_msec,
 | 
			
		||||
            event.orientation,
 | 
			
		||||
            event.delta,
 | 
			
		||||
            event.delta_discrete,
 | 
			
		||||
            event.source,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleFrame(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is forwarded by the cursor when a pointer emits an frame
 | 
			
		||||
        // event. Frame events are sent after regular pointer events to group
 | 
			
		||||
        // multiple events together. For instance, two axis events may happen at the
 | 
			
		||||
        // same time, in which case a frame event won't be sent in between.
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_frame", listener.?);
 | 
			
		||||
        // Notify the client with pointer focus of the frame event.
 | 
			
		||||
        c.wlr_seat_pointer_notify_frame(cursor.seat.wlr_seat);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleRequestSetCursor(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is rasied by the seat when a client provides a cursor image
 | 
			
		||||
        const cursor = @fieldParentPtr(Cursor, "listen_request_set_cursor", listener.?);
 | 
			
		||||
        const event = @ptrCast(
 | 
			
		||||
            *c.wlr_seat_pointer_request_set_cursor_event,
 | 
			
		||||
            @alignCast(@alignOf(*c.wlr_seat_pointer_request_set_cursor_event), data),
 | 
			
		||||
        );
 | 
			
		||||
        const focused_client = cursor.seat.wlr_seat.pointer_state.focused_client;
 | 
			
		||||
 | 
			
		||||
        // This can be sent by any client, so we check to make sure this one is
 | 
			
		||||
        // actually has pointer focus first.
 | 
			
		||||
        if (focused_client == event.seat_client) {
 | 
			
		||||
            // Once we've vetted the client, we can tell the cursor to use the
 | 
			
		||||
            // provided surface as the cursor image. It will set the hardware cursor
 | 
			
		||||
            // on the output that it's currently on and continue to do so as the
 | 
			
		||||
            // cursor moves between outputs.
 | 
			
		||||
            c.wlr_cursor_set_surface(
 | 
			
		||||
                cursor.wlr_cursor,
 | 
			
		||||
                event.surface,
 | 
			
		||||
                event.hotspot_x,
 | 
			
		||||
                event.hotspot_y,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,13 @@ pub const InputManager = struct {
 | 
			
		||||
        c.wl_signal_add(&self.server.wlr_backend.events.new_input, &self.listen_new_input);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        while (self.seats.pop()) |seat_node| {
 | 
			
		||||
            seat_node.data.deinit();
 | 
			
		||||
            self.server.allocator.destroy(seat_node);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Must be called whenever a view is unmapped.
 | 
			
		||||
    pub fn handleViewUnmap(self: Self, view: *View) void {
 | 
			
		||||
        var it = self.seats.first;
 | 
			
		||||
 | 
			
		||||
@ -11,8 +11,8 @@ pub const Keyboard = struct {
 | 
			
		||||
    device: *c.wlr_input_device,
 | 
			
		||||
    wlr_keyboard: *c.wlr_keyboard,
 | 
			
		||||
 | 
			
		||||
    listen_modifiers: c.wl_listener,
 | 
			
		||||
    listen_key: c.wl_listener,
 | 
			
		||||
    listen_modifiers: c.wl_listener,
 | 
			
		||||
 | 
			
		||||
    pub fn init(self: *Self, seat: *Seat, device: *c.wlr_input_device) !void {
 | 
			
		||||
        self.seat = seat;
 | 
			
		||||
@ -45,29 +45,11 @@ pub const Keyboard = struct {
 | 
			
		||||
        c.wlr_keyboard_set_repeat_info(self.wlr_keyboard, 25, 600);
 | 
			
		||||
 | 
			
		||||
        // Setup listeners for keyboard events
 | 
			
		||||
        self.listen_modifiers.notify = handleModifiers;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_keyboard.events.modifiers, &self.listen_modifiers);
 | 
			
		||||
 | 
			
		||||
        self.listen_key.notify = handleKey;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_keyboard.events.key, &self.listen_key);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleModifiers(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is raised when a modifier key, such as shift or alt, is
 | 
			
		||||
        // pressed. We simply communicate this to the client. */
 | 
			
		||||
        const keyboard = @fieldParentPtr(Keyboard, "listen_modifiers", listener.?);
 | 
			
		||||
 | 
			
		||||
        // A seat can only have one keyboard, but this is a limitation of the
 | 
			
		||||
        // Wayland protocol - not wlroots. We assign all connected keyboards to the
 | 
			
		||||
        // same seat. You can swap out the underlying wlr_keyboard like this and
 | 
			
		||||
        // wlr_seat handles this transparently.
 | 
			
		||||
        c.wlr_seat_set_keyboard(keyboard.seat.wlr_seat, keyboard.device);
 | 
			
		||||
 | 
			
		||||
        // Send modifiers to the client.
 | 
			
		||||
        c.wlr_seat_keyboard_notify_modifiers(
 | 
			
		||||
            keyboard.seat.wlr_seat,
 | 
			
		||||
            &keyboard.wlr_keyboard.modifiers,
 | 
			
		||||
        );
 | 
			
		||||
        self.listen_modifiers.notify = handleModifiers;
 | 
			
		||||
        c.wl_signal_add(&self.wlr_keyboard.events.modifiers, &self.listen_modifiers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleKey(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
@ -144,6 +126,24 @@ pub const Keyboard = struct {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn handleModifiers(listener: ?*c.wl_listener, data: ?*c_void) callconv(.C) void {
 | 
			
		||||
        // This event is raised when a modifier key, such as shift or alt, is
 | 
			
		||||
        // pressed. We simply communicate this to the client. */
 | 
			
		||||
        const keyboard = @fieldParentPtr(Keyboard, "listen_modifiers", listener.?);
 | 
			
		||||
 | 
			
		||||
        // A seat can only have one keyboard, but this is a limitation of the
 | 
			
		||||
        // Wayland protocol - not wlroots. We assign all connected keyboards to the
 | 
			
		||||
        // same seat. You can swap out the underlying wlr_keyboard like this and
 | 
			
		||||
        // wlr_seat handles this transparently.
 | 
			
		||||
        c.wlr_seat_set_keyboard(keyboard.seat.wlr_seat, keyboard.device);
 | 
			
		||||
 | 
			
		||||
        // Send modifiers to the client.
 | 
			
		||||
        c.wlr_seat_keyboard_notify_modifiers(
 | 
			
		||||
            keyboard.seat.wlr_seat,
 | 
			
		||||
            &keyboard.wlr_keyboard.modifiers,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Handle any builtin, harcoded compsitor bindings such as VT switching.
 | 
			
		||||
    /// Returns true if the keysym was handled.
 | 
			
		||||
    fn handleBuiltinKeybind(self: Self, keysym: c.xkb_keysym_t) bool {
 | 
			
		||||
 | 
			
		||||
@ -12,11 +12,13 @@ pub fn main() !void {
 | 
			
		||||
 | 
			
		||||
    var server: Server = undefined;
 | 
			
		||||
    try server.init(std.heap.c_allocator);
 | 
			
		||||
    defer server.destroy();
 | 
			
		||||
    defer server.deinit();
 | 
			
		||||
 | 
			
		||||
    try server.start();
 | 
			
		||||
 | 
			
		||||
    Log.Info.log("Running server...", .{});
 | 
			
		||||
 | 
			
		||||
    server.run();
 | 
			
		||||
 | 
			
		||||
    Log.Info.log("Shutting down server", .{});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -101,6 +101,20 @@ pub const Output = struct {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        for (self.layers) |*layer| {
 | 
			
		||||
            while (layer.pop()) |layer_surface_node| {
 | 
			
		||||
                self.root.server.allocator.destroy(layer_surface_node);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (self.views.first) |node| {
 | 
			
		||||
            node.view.deinit();
 | 
			
		||||
            self.views.remove(node);
 | 
			
		||||
            self.root.server.allocator.destroy(node);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Add a new view to the output. arrangeViews() will be called by the view
 | 
			
		||||
    /// when it is mapped.
 | 
			
		||||
    pub fn addView(self: *Self, wlr_xdg_surface: *c.wlr_xdg_surface) void {
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,11 @@ pub const Root = struct {
 | 
			
		||||
        self.transaction_timer = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn destroy(self: Self) void {
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        while (self.outputs.pop()) |output_node| {
 | 
			
		||||
            output_node.data.deinit();
 | 
			
		||||
            self.server.allocator.destroy(output_node);
 | 
			
		||||
        }
 | 
			
		||||
        c.wlr_output_layout_destroy(self.wlr_output_layout);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								src/seat.zig
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/seat.zig
									
									
									
									
									
								
							@ -50,8 +50,17 @@ pub const Seat = struct {
 | 
			
		||||
        self.focus_stack.init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn destroy(self: Self) void {
 | 
			
		||||
        self.cursor.destroy();
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        self.cursor.deinit();
 | 
			
		||||
 | 
			
		||||
        while (self.keyboards.pop()) |node| {
 | 
			
		||||
            self.input_manager.server.allocator.destroy(node);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (self.focus_stack.first) |node| {
 | 
			
		||||
            self.focus_stack.remove(node);
 | 
			
		||||
            self.input_manager.server.allocator.destroy(node);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Set the current focus. If a visible view is passed it will be focused.
 | 
			
		||||
 | 
			
		||||
@ -99,10 +99,12 @@ pub const Server = struct {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Free allocated memory and clean up
 | 
			
		||||
    pub fn destroy(self: Self) void {
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        // Note: order is important here
 | 
			
		||||
        c.wl_display_destroy_clients(self.wl_display);
 | 
			
		||||
        c.wl_display_destroy(self.wl_display);
 | 
			
		||||
        self.root.destroy();
 | 
			
		||||
        self.input_manager.deinit();
 | 
			
		||||
        self.root.deinit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Create the socket, set WAYLAND_DISPLAY, and start the backend
 | 
			
		||||
 | 
			
		||||
@ -70,6 +70,12 @@ pub const View = struct {
 | 
			
		||||
        c.wl_signal_add(&self.wlr_xdg_surface.events.unmap, &self.listen_unmap);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn deinit(self: *Self) void {
 | 
			
		||||
        if (self.stashed_buffer) |buffer| {
 | 
			
		||||
            c.wlr_buffer_unref(buffer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn needsConfigure(self: Self) bool {
 | 
			
		||||
        if (self.pending_box) |pending_box| {
 | 
			
		||||
            return pending_box.width != self.current_box.width or
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user