Survive session loss by detaching listeners before wlroots tears down output and input devices
This commit is contained in:
parent
382809b126
commit
131950d6e0
1 changed files with 58 additions and 6 deletions
|
|
@ -132,6 +132,7 @@ struct tabbed_server {
|
|||
struct wl_listener new_toplevel;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener frame;
|
||||
struct wl_listener output_destroy;
|
||||
struct wl_event_source *ctl_source;
|
||||
|
||||
struct wlr_xdg_toplevel *active;
|
||||
|
|
@ -415,6 +416,7 @@ struct standalone_kbdev {
|
|||
struct wlr_keyboard *keyboard;
|
||||
struct wl_listener key;
|
||||
struct wl_listener modifiers;
|
||||
struct wl_listener destroy;
|
||||
struct wl_list link;
|
||||
};
|
||||
|
||||
|
|
@ -458,6 +460,7 @@ static void shutdown_cleanup(void) {
|
|||
wl_list_remove(&kd->link);
|
||||
wl_list_remove(&kd->key.link);
|
||||
wl_list_remove(&kd->modifiers.link);
|
||||
wl_list_remove(&kd->destroy.link);
|
||||
free(kd);
|
||||
}
|
||||
wl_list_init(&server.kbdevs);
|
||||
|
|
@ -1536,6 +1539,31 @@ static void handle_output_frame(struct wl_listener *listener, void *data) {
|
|||
frame_pending = true;
|
||||
}
|
||||
|
||||
/* How many standalone outputs have been seen since the last (re)connect.
|
||||
DRM destroys and re-creates the output when the session loses/regains its
|
||||
VT, so this is reset to keep accepting the re-added connector. */
|
||||
static int standalone_output_count;
|
||||
|
||||
/* DRM destroys the output when the session (VT) is lost. Clear our
|
||||
references so nothing touches freed memory, detach the frame listener
|
||||
(wlr_output_finish asserts it's empty), and let the connector re-added on
|
||||
resume be accepted again. */
|
||||
static void handle_output_destroy(struct wl_listener *listener, void *data) {
|
||||
(void)listener;
|
||||
(void)data;
|
||||
wl_list_remove(&server.output_destroy.link);
|
||||
wl_list_remove(&server.frame.link);
|
||||
server.output = NULL;
|
||||
server.scene_output = NULL; /* wlroots frees it via its output addon */
|
||||
if (server.swapchain) {
|
||||
wlr_swapchain_destroy(server.swapchain);
|
||||
server.swapchain = NULL;
|
||||
}
|
||||
standalone_output_count = 0;
|
||||
frame_pending = false;
|
||||
needs_redraw = false;
|
||||
}
|
||||
|
||||
static void handle_new_output(struct wl_listener *listener, void *data) {
|
||||
(void)listener;
|
||||
struct wlr_output *output = data;
|
||||
|
|
@ -1543,7 +1571,6 @@ static void handle_new_output(struct wl_listener *listener, void *data) {
|
|||
/* Standalone (multi-monitor allowed at the wlroots layer): drive only
|
||||
the first output with the tabbed canvas, like the headless nested
|
||||
single output. Later outputs are left disabled. */
|
||||
static int standalone_output_count;
|
||||
if (server.standalone && standalone_output_count++ > 0) {
|
||||
tabbed_log(TABBED_LOG_INFO,
|
||||
"standalone: extra output ignored (first output only)\n");
|
||||
|
|
@ -1565,6 +1592,8 @@ server.output = output;
|
|||
enter events even before any damage has accumulated. */
|
||||
server.frame.notify = handle_output_frame;
|
||||
wl_signal_add(&output->events.frame, &server.frame);
|
||||
server.output_destroy.notify = handle_output_destroy;
|
||||
wl_signal_add(&output->events.destroy, &server.output_destroy);
|
||||
|
||||
/* Enable the output up front so buffer commits succeed even before the
|
||||
host window has been configured. A native output drives at its
|
||||
|
|
@ -1599,11 +1628,17 @@ server.output = output;
|
|||
backdrop so the nested frame is never transparent. (Direct scanout is
|
||||
disabled separately above; a rect alone cannot prevent it because
|
||||
wlroots culls a rect that a covering client surface occludes, leaving
|
||||
a single render-list entry which is exactly what triggers scanout.) */
|
||||
server.bg_rect = wlr_scene_rect_create(&server.scene->tree, w, h,
|
||||
(float[]){ 0.0f, 0.0f, 0.0f, 1.0f });
|
||||
if (server.bg_rect)
|
||||
wlr_scene_node_lower_to_bottom(&server.bg_rect->node);
|
||||
a single render-list entry which is exactly what triggers scanout.)
|
||||
On a re-connected output (VT round-trip) the node already exists; just
|
||||
resize it. */
|
||||
if (server.bg_rect) {
|
||||
wlr_scene_rect_set_size(server.bg_rect, w, h);
|
||||
} else {
|
||||
server.bg_rect = wlr_scene_rect_create(&server.scene->tree, w, h,
|
||||
(float[]){ 0.0f, 0.0f, 0.0f, 1.0f });
|
||||
if (server.bg_rect)
|
||||
wlr_scene_node_lower_to_bottom(&server.bg_rect->node);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_toplevel_destroy(struct wl_listener *listener, void *data) {
|
||||
|
|
@ -3399,6 +3434,21 @@ static void standalone_kbd_modifiers(struct wl_listener *listener, void *data) {
|
|||
wlr_seat_keyboard_notify_modifiers(server.seat, &kb->modifiers);
|
||||
}
|
||||
|
||||
/* The device is going away (libinput suspends all devices when the session
|
||||
loses its VT). Drop our listeners so wlr_keyboard_finish's assert that
|
||||
every event list is empty holds, then free the struct. wlroots emits the
|
||||
input device's destroy signal from within wlr_keyboard_finish(), so this
|
||||
runs before the assert. */
|
||||
static void standalone_kbd_destroy(struct wl_listener *listener, void *data) {
|
||||
(void)data;
|
||||
struct standalone_kbdev *kd = wl_container_of(listener, kd, destroy);
|
||||
wl_list_remove(&kd->destroy.link);
|
||||
wl_list_remove(&kd->key.link);
|
||||
wl_list_remove(&kd->modifiers.link);
|
||||
wl_list_remove(&kd->link);
|
||||
free(kd);
|
||||
}
|
||||
|
||||
static struct wl_listener standalone_ptr_motion;
|
||||
static struct wl_listener standalone_ptr_abs;
|
||||
static struct wl_listener standalone_ptr_button;
|
||||
|
|
@ -3468,6 +3518,8 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
|
|||
wl_signal_add(&kb->events.key, &kd->key);
|
||||
kd->modifiers.notify = standalone_kbd_modifiers;
|
||||
wl_signal_add(&kb->events.modifiers, &kd->modifiers);
|
||||
kd->destroy.notify = standalone_kbd_destroy;
|
||||
wl_signal_add(&kb->base.events.destroy, &kd->destroy);
|
||||
wl_list_insert(server.kbdevs.prev, &kd->link);
|
||||
tabbed_log(TABBED_LOG_INFO, "standalone: keyboard '%s'\n", device->name);
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue