From c80e954123dc824cbdf679328200a5440d78f1e6 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Wed, 25 Oct 2017 15:51:37 +0300 Subject: [PATCH] compositor-wayland: migrate to head-based output API Follow the standard pattern used in the headless and x11 backend migration, but also cater for the two other backend modes: --sprawl or fullscreen-shell, and --fullscreen. Stops relying on the implicit weston_output::head. Unlike other backends, this uses the attach_head hook to do the required head setup that is not possible to do without an output, but must be done before weston_output_enable(). This also requires the detach_head hook for the one case where the user attaches a --fullscreen head and then detaches it without enabling the output. It is a little awkward to fully initialize heads as late as attach, but aside from the --sprawl/fullscreen-shell case, there is not really a way to know the head properties without creating the parent wl_surface and configuring it. Heads/outputs created for parent outputs now have distinct names instead of all being called "wlparent". Signed-off-by: Pekka Paalanen Reviewed-by: Ian Ray Acked-by: Derek Foreman --- libweston/compositor-wayland.c | 239 ++++++++++++++++++++++++--------- 1 file changed, 178 insertions(+), 61 deletions(-) diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c index 82e52b90..2473f087 100644 --- a/libweston/compositor-wayland.c +++ b/libweston/compositor-wayland.c @@ -137,7 +137,7 @@ struct wayland_output { struct wayland_parent_output { struct wayland_backend *backend; /**< convenience */ - struct wayland_output *output; + struct wayland_head *head; struct wl_list link; struct wl_output *global; @@ -161,6 +161,11 @@ struct wayland_parent_output { struct weston_mode *current_mode; }; +struct wayland_head { + struct weston_head base; + struct wayland_parent_output *parent_output; +}; + struct wayland_shm_buffer { struct wayland_output *output; struct wl_list link; @@ -210,6 +215,12 @@ struct wayland_input { struct gl_renderer_interface *gl_renderer; +static inline struct wayland_head * +to_wayland_head(struct weston_head *base) +{ + return container_of(base, struct wayland_head, base); +} + static inline struct wayland_output * to_wayland_output(struct weston_output *base) { @@ -1275,9 +1286,59 @@ err_output: return -1; } -static struct wayland_output * -wayland_output_create_common(struct weston_compositor *compositor, - const char *name) +static int +wayland_output_setup_for_parent_output(struct wayland_output *output, + struct wayland_parent_output *poutput); + +static int +wayland_output_setup_fullscreen(struct wayland_output *output, + struct wayland_head *head); + +static int +wayland_output_attach_head(struct weston_output *output_base, + struct weston_head *head_base) +{ + struct wayland_backend *b = to_wayland_backend(output_base->compositor); + struct wayland_output *output = to_wayland_output(output_base); + struct wayland_head *head = to_wayland_head(head_base); + + if (!wl_list_empty(&output->base.head_list)) + return -1; + + if (head->parent_output) { + if (wayland_output_setup_for_parent_output(output, + head->parent_output) < 0) + return -1; + } else if (b->fullscreen) { + if (wayland_output_setup_fullscreen(output, head) < 0) + return -1; + } else { + /* A floating window, nothing to do. */ + } + + return 0; +} + +static void +wayland_output_detach_head(struct weston_output *output_base, + struct weston_head *head) +{ + struct wayland_output *output = to_wayland_output(output_base); + + /* Rely on the disable hook if the output was enabled. We do not + * support cloned heads, so detaching is guaranteed to disable the + * output. + */ + if (output->base.enabled) + return; + + /* undo setup fullscreen */ + if (output->parent.surface) + wayland_backend_destroy_output_surface(output); +} + +static struct weston_output * +wayland_output_create(struct weston_compositor *compositor, const char *name) { struct wayland_output *output; char *title; @@ -1302,29 +1363,87 @@ wayland_output_create_common(struct weston_compositor *compositor, output->base.destroy = wayland_output_destroy; output->base.disable = wayland_output_disable; output->base.enable = wayland_output_enable; + output->base.attach_head = wayland_output_attach_head; + output->base.detach_head = wayland_output_detach_head; + + weston_compositor_add_pending_output(&output->base, compositor); + + return &output->base; +} + +static struct wayland_head * +wayland_head_create(struct weston_compositor *compositor, const char *name) +{ + struct wayland_head *head; + + assert(name); + + head = zalloc(sizeof *head); + if (!head) + return NULL; + + weston_head_init(&head->base, name); + weston_head_set_connection_status(&head->base, true); + weston_compositor_add_head(compositor, &head->base); - return output; + return head; } static int -wayland_output_create(struct weston_compositor *compositor, const char *name) +wayland_head_create_windowed(struct weston_compositor *compositor, + const char *name) { - struct wayland_output *output; + if (!wayland_head_create(compositor, name)) + return -1; - output = wayland_output_create_common(compositor, name); - if (!output) + return 0; +} + +static int +wayland_head_create_for_parent_output(struct weston_compositor *compositor, + struct wayland_parent_output *poutput) +{ + struct wayland_head *head; + char name[100]; + int ret; + + ret = snprintf(name, sizeof(name), "wlparent-%d", poutput->id); + if (ret < 1 || (unsigned)ret >= sizeof(name)) return -1; - weston_compositor_add_pending_output(&output->base, compositor); + head = wayland_head_create(compositor, name); + if (!head) + return -1; + + assert(!poutput->head); + head->parent_output = poutput; + poutput->head = head; + + weston_head_set_monitor_strings(&head->base, + poutput->physical.make, + poutput->physical.model, NULL); + weston_head_set_physical_size(&head->base, + poutput->physical.width, + poutput->physical.height); return 0; } +static void +wayland_head_destroy(struct wayland_head *head) +{ + if (head->parent_output) + head->parent_output->head = NULL; + + weston_head_release(&head->base); + free(head); +} + static int wayland_output_set_size(struct weston_output *base, int width, int height) { struct wayland_output *output = to_wayland_output(base); - struct weston_head *head = &output->base.head; + struct weston_head *head; int output_width, output_height; /* We can only be called once. */ @@ -1345,6 +1464,13 @@ wayland_output_set_size(struct weston_output *base, int width, int height) return -1; } + wl_list_for_each(head, &output->base.head_list, output_link) { + weston_head_set_monitor_strings(head, "wayland", "none", NULL); + + /* XXX: Calculate proper size. */ + weston_head_set_physical_size(head, width, height); + } + output_width = width * output->base.scale; output_height = height * output->base.scale; @@ -1358,25 +1484,15 @@ wayland_output_set_size(struct weston_output *base, int width, int height) output->base.current_mode = &output->mode; - weston_head_set_monitor_strings(head, "wayland", "none", NULL); - - /* XXX: Calculate proper size. */ - weston_head_set_physical_size(head, width, height); - return 0; } static int -wayland_output_create_for_parent_output(struct wayland_backend *b, - struct wayland_parent_output *poutput) +wayland_output_setup_for_parent_output(struct wayland_output *output, + struct wayland_parent_output *poutput) { - struct wayland_output *output; struct weston_mode *mode; - output = wayland_output_create_common(b->compositor, "wlparent"); - if (!output) - return -1; - if (poutput->current_mode) { mode = poutput->current_mode; } else if (poutput->preferred_mode) { @@ -1386,7 +1502,7 @@ wayland_output_create_for_parent_output(struct wayland_backend *b, struct weston_mode, link); } else { weston_log("No valid modes found. Skipping output.\n"); - goto out; + return -1; } output->base.scale = 1; @@ -1394,13 +1510,6 @@ wayland_output_create_for_parent_output(struct wayland_backend *b, output->parent.output = poutput->global; - weston_head_set_monitor_strings(&output->base.head, - poutput->physical.make, - poutput->physical.model, NULL); - weston_head_set_physical_size(&output->base.head, - poutput->physical.width, - poutput->physical.height); - wl_list_insert_list(&output->base.mode_list, &poutput->mode_list); wl_list_init(&poutput->mode_list); @@ -1410,33 +1519,21 @@ wayland_output_create_for_parent_output(struct wayland_backend *b, /* output->mode is unused in this path. */ - weston_compositor_add_pending_output(&output->base, b->compositor); - return 0; - -out: - weston_output_release(&output->base); - free(output->title); - free(output); - - return -1; } static int -wayland_output_create_fullscreen(struct wayland_backend *b) +wayland_output_setup_fullscreen(struct wayland_output *output, + struct wayland_head *head) { - struct wayland_output *output; + struct wayland_backend *b = to_wayland_backend(output->base.compositor); int width = 0, height = 0; - output = wayland_output_create_common(b->compositor, "wayland-fullscreen"); - if (!output) - return -1; - output->base.scale = 1; output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL; if (wayland_backend_create_output_surface(output) < 0) - goto err_surface; + return -1; /* What should size be set if conditional is false? */ if (b->parent.xdg_shell || b->parent.shell) { @@ -1456,16 +1553,15 @@ wayland_output_create_fullscreen(struct wayland_backend *b) if (wayland_output_set_size(&output->base, width, height) < 0) goto err_set_size; - weston_compositor_add_pending_output(&output->base, b->compositor); + /* The head is not attached yet, so set_size did not set these. */ + weston_head_set_monitor_strings(&head->base, "wayland", "none", NULL); + /* XXX: Calculate proper size. */ + weston_head_set_physical_size(&head->base, width, height); return 0; err_set_size: wayland_backend_destroy_output_surface(output); -err_surface: - weston_output_release(&output->base); - free(output->title); - free(output); return -1; } @@ -2286,16 +2382,32 @@ find_mode(struct wl_list *list, int32_t width, int32_t height, uint32_t refresh) return mode; } +static struct weston_output * +wayland_parent_output_get_enabled_output(struct wayland_parent_output *poutput) +{ + struct wayland_head *head = poutput->head; + + if (!head) + return NULL; + + if (!weston_head_is_enabled(&head->base)) + return NULL; + + return weston_head_get_output(&head->base); +} + static void wayland_parent_output_mode(void *data, struct wl_output *wl_output_proxy, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { struct wayland_parent_output *output = data; + struct weston_output *enabled_output; struct weston_mode *mode; - if (output->output) { - mode = find_mode(&output->output->base.mode_list, + enabled_output = wayland_parent_output_get_enabled_output(output); + if (enabled_output) { + mode = find_mode(&enabled_output->mode_list, width, height, refresh); if (!mode) return; @@ -2329,7 +2441,7 @@ output_sync_callback(void *data, struct wl_callback *callback, uint32_t unused) assert(output->backend->sprawl_across_outputs); - wayland_output_create_for_parent_output(output->backend, output); + wayland_head_create_for_parent_output(output->backend->compositor, output); } static const struct wl_callback_listener output_sync_listener = { @@ -2377,8 +2489,8 @@ wayland_parent_output_destroy(struct wayland_parent_output *output) if (output->sync_cb) wl_callback_destroy(output->sync_cb); - if (output->output) - wayland_output_destroy(&output->output->base); + if (output->head) + wayland_head_destroy(output->head); wl_output_destroy(output->global); free(output->physical.make); @@ -2483,11 +2595,15 @@ static void wayland_destroy(struct weston_compositor *ec) { struct wayland_backend *b = to_wayland_backend(ec); + struct weston_head *base, *next; wl_event_source_remove(b->parent.wl_source); weston_compositor_shutdown(ec); + wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) + wayland_head_destroy(to_wayland_head(base)); + if (b->parent.shm) wl_shm_destroy(b->parent.shm); @@ -2642,6 +2758,7 @@ wayland_backend_create(struct weston_compositor *compositor, } b->base.destroy = wayland_destroy; + b->base.create_output = wayland_output_create; loop = wl_display_get_event_loop(compositor->wl_display); @@ -2686,7 +2803,7 @@ wayland_backend_destroy(struct wayland_backend *b) static const struct weston_windowed_output_api windowed_api = { wayland_output_set_size, - wayland_output_create, + wayland_head_create_windowed, }; static void @@ -2723,14 +2840,14 @@ weston_backend_init(struct weston_compositor *compositor, wl_display_roundtrip(b->parent.wl_display); wl_list_for_each(poutput, &b->parent.output_list, link) - wayland_output_create_for_parent_output(b, poutput); + wayland_head_create_for_parent_output(compositor, poutput); return 0; } if (new_config.fullscreen) { - if (wayland_output_create_fullscreen(b) < 0) { - weston_log("Unable to create a fullscreen output.\n"); + if (!wayland_head_create(compositor, "wayland-fullscreen")) { + weston_log("Unable to create a fullscreen head.\n"); goto err_outputs; }