fix: miss free switch toggle listener when switch VT

This commit is contained in:
DreamMaoMao 2025-09-06 09:37:40 +08:00
parent 7b591ccd4b
commit 30b41a59e7
2 changed files with 61 additions and 35 deletions

View file

@ -2649,9 +2649,14 @@ void reapply_keyboard(void) {
} }
void reapply_pointer(void) { void reapply_pointer(void) {
struct input_device *id; InputDevice *id;
struct libinput_device *device; struct libinput_device *device;
wl_list_for_each(id, &pointers, link) { wl_list_for_each(id, &inputdevices, link) {
if (id->wlr_device->type != WLR_INPUT_DEVICE_POINTER) {
continue;
}
device = id->libinput_device; device = id->libinput_device;
if (wlr_input_device_is_libinput(id->wlr_device) && device) { if (wlr_input_device_is_libinput(id->wlr_device) && device) {
configure_pointer(device); configure_pointer(device);

View file

@ -191,17 +191,19 @@ typedef struct {
const Arg arg; const Arg arg;
} Axis; } Axis;
struct input_device { typedef struct {
struct wl_list link; struct wl_list link;
struct wlr_input_device *wlr_device; struct wlr_input_device *wlr_device;
struct libinput_device *libinput_device; struct libinput_device *libinput_device;
struct wl_listener destroy_listener; // 用于监听设备销毁事件 struct wl_listener destroy_listener; // 用于监听设备销毁事件
}; void *device_data; // 新增:指向设备特定数据(如 Switch
} InputDevice;
typedef struct { typedef struct {
struct wl_list link; struct wl_list link;
struct wlr_switch *wlr_switch; struct wlr_switch *wlr_switch;
struct wl_listener toggle; struct wl_listener toggle;
InputDevice *input_dev;
} Switch; } Switch;
struct dwl_animation { struct dwl_animation {
@ -521,10 +523,9 @@ static void createmon(struct wl_listener *listener, void *data);
static void createnotify(struct wl_listener *listener, void *data); static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer); static void createpointer(struct wlr_pointer *pointer);
static void configure_pointer(struct libinput_device *device); static void configure_pointer(struct libinput_device *device);
static void destroypointer(struct wl_listener *listener, void *data); static void destroyinputdevice(struct wl_listener *listener, void *data);
static void createswitch(struct wlr_switch *switch_device); static void createswitch(struct wlr_switch *switch_device);
static void switch_toggle(struct wl_listener *listener, void *data); static void switch_toggle(struct wl_listener *listener, void *data);
static void cleanupswitches();
static void createpointerconstraint(struct wl_listener *listener, void *data); static void createpointerconstraint(struct wl_listener *listener, void *data);
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void commitpopup(struct wl_listener *listener, void *data); static void commitpopup(struct wl_listener *listener, void *data);
@ -751,8 +752,7 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
static struct wlr_seat *seat; static struct wlr_seat *seat;
static KeyboardGroup *kb_group; static KeyboardGroup *kb_group;
static struct wl_list keyboards; static struct wl_list keyboards;
static struct wl_list pointers; static struct wl_list inputdevices;
static struct wl_list switches;
static unsigned int cursor_mode; static unsigned int cursor_mode;
static Client *grabc; static Client *grabc;
static int grabcx, grabcy; /* client-relative */ static int grabcx, grabcy; /* client-relative */
@ -2009,8 +2009,6 @@ void cleanup(void) {
dwl_im_relay_finish(dwl_input_method_relay); dwl_im_relay_finish(dwl_input_method_relay);
cleanupswitches();
/* If it's not destroyed manually it will cause a use-after-free of /* If it's not destroyed manually it will cause a use-after-free of
* wlr_seat. Destroy it until it's fixed in the wlroots side */ * wlr_seat. Destroy it until it's fixed in the wlroots side */
wlr_backend_destroy(backend); wlr_backend_destroy(backend);
@ -2642,13 +2640,32 @@ createnotify(struct wl_listener *listener, void *data) {
LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle); LISTEN(&toplevel->events.set_title, &c->set_title, updatetitle);
} }
void destroypointer(struct wl_listener *listener, void *data) { void destroyinputdevice(struct wl_listener *listener, void *data) {
struct input_device *input_dev = InputDevice *input_dev =
wl_container_of(listener, input_dev, destroy_listener); wl_container_of(listener, input_dev, destroy_listener);
// 清理设备特定数据
if (input_dev->device_data) {
// 根据设备类型进行特定清理
switch (input_dev->wlr_device->type) {
case WLR_INPUT_DEVICE_SWITCH: {
Switch *sw = (Switch *)input_dev->device_data;
// 移除 toggle 监听器
wl_list_remove(&sw->toggle.link);
// 释放 Switch 内存
free(sw);
break;
}
// 可以添加其他设备类型的清理代码
default:
break;
}
input_dev->device_data = NULL;
}
// 从设备列表中移除 // 从设备列表中移除
wl_list_remove(&input_dev->link); wl_list_remove(&input_dev->link);
// 移除监听器 // 移除 destroy 监听器
wl_list_remove(&input_dev->destroy_listener.link); wl_list_remove(&input_dev->destroy_listener.link);
// 释放内存 // 释放内存
free(input_dev); free(input_dev);
@ -2704,14 +2721,14 @@ void createpointer(struct wlr_pointer *pointer) {
configure_pointer(device); configure_pointer(device);
} }
struct input_device *input_dev = calloc(1, sizeof(struct input_device)); InputDevice *input_dev = calloc(1, sizeof(InputDevice));
input_dev->wlr_device = &pointer->base; input_dev->wlr_device = &pointer->base;
input_dev->libinput_device = device; input_dev->libinput_device = device;
input_dev->destroy_listener.notify = destroypointer; input_dev->destroy_listener.notify = destroyinputdevice;
wl_signal_add(&pointer->base.events.destroy, &input_dev->destroy_listener); wl_signal_add(&pointer->base.events.destroy, &input_dev->destroy_listener);
wl_list_insert(&pointers, &input_dev->link); wl_list_insert(&inputdevices, &input_dev->link);
wlr_cursor_attach_input_device(cursor, &pointer->base); wlr_cursor_attach_input_device(cursor, &pointer->base);
} }
@ -2737,27 +2754,32 @@ void switch_toggle(struct wl_listener *listener, void *data) {
} }
void createswitch(struct wlr_switch *switch_device) { void createswitch(struct wlr_switch *switch_device) {
struct libinput_device *device =
wlr_libinput_get_device_handle(&switch_device->base);
InputDevice *input_dev = calloc(1, sizeof(InputDevice));
input_dev->wlr_device = &switch_device->base;
input_dev->libinput_device = device;
input_dev->device_data = NULL; // 初始化为 NULL
input_dev->destroy_listener.notify = destroyinputdevice;
wl_signal_add(&switch_device->base.events.destroy,
&input_dev->destroy_listener);
// 创建 Switch 特定数据
Switch *sw = calloc(1, sizeof(Switch)); Switch *sw = calloc(1, sizeof(Switch));
sw->wlr_switch = switch_device; sw->wlr_switch = switch_device;
sw->toggle.notify = switch_toggle; sw->toggle.notify = switch_toggle;
sw->input_dev = input_dev;
// 将 Switch 指针保存到 input_device 中
input_dev->device_data = sw;
// 添加 toggle 监听器
wl_signal_add(&switch_device->events.toggle, &sw->toggle); wl_signal_add(&switch_device->events.toggle, &sw->toggle);
// 添加到全局列表(可选,用于统一管理) // 添加到全局列表
wl_list_insert(&switches, &sw->link); wl_list_insert(&inputdevices, &input_dev->link);
}
void cleanupswitches() {
Switch *sw, *tmp;
wl_list_for_each_safe(sw, tmp, &switches, link) {
// 移除事件监听
wl_list_remove(&sw->toggle.link);
// 从列表中移除
wl_list_remove(&sw->link);
// 释放内存
free(sw);
}
} }
void createpointerconstraint(struct wl_listener *listener, void *data) { void createpointerconstraint(struct wl_listener *listener, void *data) {
@ -3572,7 +3594,7 @@ void motionabsolute(struct wl_listener *listener, void *data) {
return; return;
} }
if (!event->time_msec) /* this is 0 with virtual pointers */ if (!event->time_msec) /* this is 0 with virtual pointer */
wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x, wlr_cursor_warp_absolute(cursor, &event->pointer->base, event->x,
event->y); event->y);
@ -4703,8 +4725,7 @@ void setup(void) {
* to let us know when new input devices are available on the backend. * to let us know when new input devices are available on the backend.
*/ */
wl_list_init(&keyboards); wl_list_init(&keyboards);
wl_list_init(&pointers); wl_list_init(&inputdevices);
wl_list_init(&switches);
wl_signal_add(&backend->events.new_input, &new_input_device); wl_signal_add(&backend->events.new_input, &new_input_device);
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,