[PATCH weston v6 19/73] weston: migrate headless to head-based output API

Pekka Paalanen ppaalanen at gmail.com
Fri Feb 16 14:57:04 UTC 2018


From: Pekka Paalanen <pekka.paalanen at collabora.co.uk>

Migrate the headless frontend to use the new head-based output
configuration API: listen for heads_changed, and process all heads.

The simple_heads_changed() function is written to be able to cater for
all backends. The rest will be migrated individually.

The head destroy listeners are not exactly necessary, for headless
anyway, but this is an example excercising the API. Also
is_device_changed() check is mostly useful with DRM.

v3: Print "Detected a monitor change" only for enabled heads.

Signed-off-by: Pekka Paalanen <pekka.paalanen at collabora.co.uk>
---
 compositor/main.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 187 insertions(+), 10 deletions(-)

diff --git a/compositor/main.c b/compositor/main.c
index 979da2a0..5a2cec97 100644
--- a/compositor/main.c
+++ b/compositor/main.c
@@ -69,11 +69,19 @@ struct wet_output_config {
 	uint32_t transform;
 };
 
+struct wet_compositor;
+
+struct wet_head_tracker {
+	struct wl_listener head_destroy_listener;
+};
+
 struct wet_compositor {
 	struct weston_config *config;
 	struct wet_output_config *parsed_options;
 	struct wl_listener pending_output_listener;
 	bool drm_use_current_mode;
+	int (*simple_output_configure)(struct weston_output *output);
+	bool init_failed;
 };
 
 static FILE *weston_logfile = NULL;
@@ -1009,6 +1017,177 @@ wet_configure_windowed_output_from_config(struct weston_output *output,
 	return 0;
 }
 
+static int
+count_remaining_heads(struct weston_output *output, struct weston_head *to_go)
+{
+	struct weston_head *iter = NULL;
+	int n = 0;
+
+	while ((iter = weston_output_iterate_heads(output, iter))) {
+		if (iter != to_go)
+			n++;
+	}
+
+	return n;
+}
+
+static void
+wet_head_tracker_destroy(struct wet_head_tracker *track)
+{
+	wl_list_remove(&track->head_destroy_listener.link);
+	free(track);
+}
+
+static void
+handle_head_destroy(struct wl_listener *listener, void *data)
+{
+	struct weston_head *head = data;
+	struct weston_output *output;
+	struct wet_head_tracker *track =
+		container_of(listener, struct wet_head_tracker,
+			     head_destroy_listener);
+
+	wet_head_tracker_destroy(track);
+
+	output = weston_head_get_output(head);
+
+	/* On shutdown path, the output might be already gone. */
+	if (!output)
+		return;
+
+	if (count_remaining_heads(output, head) > 0)
+		return;
+
+	weston_output_destroy(output);
+}
+
+static struct wet_head_tracker *
+wet_head_tracker_from_head(struct weston_head *head)
+{
+	struct wl_listener *lis;
+
+	lis = weston_head_get_destroy_listener(head, handle_head_destroy);
+	if (!lis)
+		return NULL;
+
+	return container_of(lis, struct wet_head_tracker,
+			    head_destroy_listener);
+}
+
+/* Listen for head destroy signal.
+ *
+ * If a head is destroyed, we also destroy the associated output.
+ *
+ * Do not bother destroying the head trackers on shutdown, the backend will
+ * destroy the heads which calls our handler to destroy the trackers.
+ */
+static void
+wet_head_tracker_create(struct wet_compositor *compositor,
+			struct weston_head *head)
+{
+	struct wet_head_tracker *track;
+
+	track = zalloc(sizeof *track);
+	if (!track)
+		return;
+
+	track->head_destroy_listener.notify = handle_head_destroy;
+	weston_head_add_destroy_listener(head, &track->head_destroy_listener);
+}
+
+static void
+simple_head_enable(struct weston_compositor *compositor, struct weston_head *head)
+{
+	struct wet_compositor *wet = to_wet_compositor(compositor);
+	struct weston_output *output;
+	int ret = 0;
+
+	output = weston_compositor_create_output_with_head(compositor, head);
+	if (!output) {
+		weston_log("Could not create an output for head \"%s\".\n",
+			   weston_head_get_name(head));
+		wet->init_failed = true;
+
+		return;
+	}
+
+	if (wet->simple_output_configure)
+		ret = wet->simple_output_configure(output);
+	if (ret < 0) {
+		weston_log("Cannot configure output \"%s\".\n",
+			   weston_head_get_name(head));
+		weston_output_destroy(output);
+		wet->init_failed = true;
+
+		return;
+	}
+
+	if (weston_output_enable(output) < 0) {
+		weston_log("Enabling output \"%s\" failed.\n",
+			   weston_head_get_name(head));
+		weston_output_destroy(output);
+		wet->init_failed = true;
+
+		return;
+	}
+
+	wet_head_tracker_create(wet, head);
+
+	/* The weston_compositor will track and destroy the output on exit. */
+}
+
+static void
+simple_head_disable(struct weston_head *head)
+{
+	struct weston_output *output;
+	struct wet_head_tracker *track;
+
+	track = wet_head_tracker_from_head(head);
+	if (track)
+		wet_head_tracker_destroy(track);
+
+	output = weston_head_get_output(head);
+	assert(output);
+	weston_output_destroy(output);
+}
+
+static void
+simple_heads_changed(struct weston_compositor *compositor)
+{
+	struct weston_head *head = NULL;
+	bool connected;
+	bool enabled;
+	bool changed;
+
+	while ((head = weston_compositor_iterate_heads(compositor, head))) {
+		connected = weston_head_is_connected(head);
+		enabled = weston_head_is_enabled(head);
+		changed = weston_head_is_device_changed(head);
+
+		if (connected && !enabled) {
+			simple_head_enable(compositor, head);
+		} else if (!connected && enabled) {
+			simple_head_disable(head);
+		} else if (enabled && changed) {
+			weston_log("Detected a monitor change on head '%s', "
+				   "not bothering to do anything about it.\n",
+				   weston_head_get_name(head));
+		}
+		weston_head_reset_device_changed(head);
+	}
+}
+
+static void
+wet_set_simple_head_configurator(struct weston_compositor *compositor,
+				 int (*fn)(struct weston_output *))
+{
+	struct wet_compositor *wet = to_wet_compositor(compositor);
+
+	wet->simple_output_configure = fn;
+	weston_compositor_set_heads_changed_cb(compositor,
+					       simple_heads_changed);
+}
+
 static void
 configure_input_device(struct weston_compositor *compositor,
 		       struct libinput_device *device)
@@ -1136,10 +1315,9 @@ load_drm_backend(struct weston_compositor *c,
 	return ret;
 }
 
-static void
-headless_backend_output_configure(struct wl_listener *listener, void *data)
+static int
+headless_backend_output_configure(struct weston_output *output)
 {
-	struct weston_output *output = data;
 	struct wet_output_config defaults = {
 		.width = 1024,
 		.height = 640,
@@ -1147,10 +1325,7 @@ headless_backend_output_configure(struct wl_listener *listener, void *data)
 		.transform = WL_OUTPUT_TRANSFORM_NORMAL
 	};
 
-	if (wet_configure_windowed_output_from_config(output, &defaults) < 0)
-		weston_log("Cannot configure output \"%s\".\n", output->name);
-
-	weston_output_enable(output);
+	return wet_configure_windowed_output_from_config(output, &defaults);
 }
 
 static int
@@ -1188,6 +1363,8 @@ load_headless_backend(struct weston_compositor *c,
 	config.base.struct_version = WESTON_HEADLESS_BACKEND_CONFIG_VERSION;
 	config.base.struct_size = sizeof(struct weston_headless_backend_config);
 
+	wet_set_simple_head_configurator(c, headless_backend_output_configure);
+
 	/* load the actual wayland backend and configure it */
 	ret = weston_compositor_load_backend(c, WESTON_BACKEND_HEADLESS,
 					     &config.base);
@@ -1195,8 +1372,6 @@ load_headless_backend(struct weston_compositor *c,
 	if (ret < 0)
 		return ret;
 
-	wet_set_pending_output_handler(c, headless_backend_output_configure);
-
 	if (!no_outputs) {
 		api = weston_windowed_output_get_api(c);
 
@@ -1675,7 +1850,7 @@ int main(int argc, char *argv[])
 	struct wl_client *primary_client;
 	struct wl_listener primary_client_destroyed;
 	struct weston_seat *seat;
-	struct wet_compositor user_data;
+	struct wet_compositor user_data = { 0 };
 	int require_input;
 	int32_t wait_for_debugger = 0;
 
@@ -1790,6 +1965,8 @@ int main(int argc, char *argv[])
 	}
 
 	weston_pending_output_coldplug(ec);
+	if (user_data.init_failed)
+		goto out;
 
 	if (idle_time < 0)
 		weston_config_section_get_int(section, "idle-time", &idle_time, -1);
-- 
2.13.6



More information about the wayland-devel mailing list