aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/backend.c66
-rw-r--r--include/wlr/backend.h3
2 files changed, 67 insertions, 2 deletions
diff --git a/backend/backend.c b/backend/backend.c
index dcc68b3f..05a40c04 100644
--- a/backend/backend.c
+++ b/backend/backend.c
@@ -146,6 +146,53 @@ static size_t parse_outputs_env(const char *name) {
return outputs;
}
+/**
+ * Helper to destroy the multi backend when one of its nested backends is
+ * destroyed.
+ */
+struct wlr_auto_backend_monitor {
+ struct wlr_backend *multi;
+ struct wlr_backend *primary;
+
+ struct wl_listener multi_destroy;
+ struct wl_listener primary_destroy;
+};
+
+static void auto_backend_monitor_destroy(struct wlr_auto_backend_monitor *monitor) {
+ wl_list_remove(&monitor->multi_destroy.link);
+ wl_list_remove(&monitor->primary_destroy.link);
+ free(monitor);
+}
+
+static void monitor_handle_multi_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_auto_backend_monitor *monitor = wl_container_of(listener, monitor, multi_destroy);
+ auto_backend_monitor_destroy(monitor);
+}
+
+static void monitor_handle_primary_destroy(struct wl_listener *listener, void *data) {
+ struct wlr_auto_backend_monitor *monitor = wl_container_of(listener, monitor, primary_destroy);
+ wlr_backend_destroy(monitor->multi);
+}
+
+static struct wlr_auto_backend_monitor *auto_backend_monitor_create(
+ struct wlr_backend *multi, struct wlr_backend *primary) {
+ struct wlr_auto_backend_monitor *monitor = calloc(1, sizeof(*monitor));
+ if (monitor == NULL) {
+ return NULL;
+ }
+
+ monitor->multi = multi;
+ monitor->primary = primary;
+
+ monitor->multi_destroy.notify = monitor_handle_multi_destroy;
+ wl_signal_add(&multi->events.destroy, &monitor->multi_destroy);
+
+ monitor->primary_destroy.notify = monitor_handle_primary_destroy;
+ wl_signal_add(&primary->events.destroy, &monitor->primary_destroy);
+
+ return monitor;
+}
+
static struct wlr_backend *attempt_wl_backend(struct wl_display *display) {
struct wlr_backend *backend = wlr_wl_backend_create(display, NULL);
if (backend == NULL) {
@@ -335,8 +382,12 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
if (!wl_backend) {
goto error;
}
-
wlr_multi_backend_add(multi, wl_backend);
+
+ if (!auto_backend_monitor_create(multi, wl_backend)) {
+ goto error;
+ }
+
goto success;
}
@@ -347,8 +398,12 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
if (!x11_backend) {
goto error;
}
-
wlr_multi_backend_add(multi, x11_backend);
+
+ if (!auto_backend_monitor_create(multi, x11_backend)) {
+ goto error;
+ }
+
goto success;
}
@@ -362,6 +417,9 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
struct wlr_backend *libinput = attempt_libinput_backend(display, session);
if (libinput) {
wlr_multi_backend_add(multi, libinput);
+ if (!auto_backend_monitor_create(multi, libinput)) {
+ goto error;
+ }
} else if (env_parse_bool("WLR_LIBINPUT_NO_DEVICES")) {
wlr_log(WLR_INFO, "WLR_LIBINPUT_NO_DEVICES is set, "
"starting without libinput backend");
@@ -377,6 +435,10 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
goto error;
}
+ if (!auto_backend_monitor_create(multi, primary_drm)) {
+ goto error;
+ }
+
success:
if (session_ptr != NULL) {
*session_ptr = session;
diff --git a/include/wlr/backend.h b/include/wlr/backend.h
index 9a8a2d87..24d8c6b5 100644
--- a/include/wlr/backend.h
+++ b/include/wlr/backend.h
@@ -37,6 +37,9 @@ struct wlr_backend {
*
* If session_ptr is not NULL, it's populated with the session which has been
* created with the backend, if any.
+ *
+ * The multi-backend will be destroyed if one of the primary underlying
+ * backends is destroyed (e.g. if the primary DRM device is unplugged).
*/
struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
struct wlr_session **session_ptr);