clients/desktop-shell: preserve background/panel in clone mode

In shared-CRTC clone mode there are several wl_output globals for one
weston_output. Only one panel and background is needed per
weston_output, so the extra wl_outputs do not get their own panel and
background.

When a head is unplugged, the corresponding wl_output is removed. If
that was the wl_output associated with the background and panel
surfaces, we must transfer the ownership to a remaining wl_output that
was a clone to avoid losing the background and panel completely.

The transfer relies on desktop-shell.so implementation to register
background and panel surfaces with the weston_output, not the
weston_head, so it does not actually matter the wl_output used to bind
the surfaces is going away.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Daniel Stone <daniels@collabora.com>
This commit is contained in:
Pekka Paalanen 2017-12-07 15:30:18 +02:00
parent 1a0239e40f
commit c1bcce6a25

View File

@ -128,6 +128,8 @@ struct output {
uint32_t server_output_id;
struct wl_list link;
int x;
int y;
struct panel *panel;
struct background *background;
};
@ -1245,6 +1247,9 @@ output_handle_geometry(void *data,
{
struct output *output = data;
output->x = x;
output->y = y;
if (output->panel)
window_set_buffer_transform(output->panel->window, transform);
if (output->background)
@ -1328,6 +1333,49 @@ create_output(struct desktop *desktop, uint32_t id)
output_init(output, desktop);
}
static void
output_remove(struct desktop *desktop, struct output *output)
{
struct output *cur;
struct output *rep = NULL;
if (!output->background) {
output_destroy(output);
return;
}
/* Find a wl_output that is a clone of the removed wl_output.
* We don't want to leave the clone without a background or panel. */
wl_list_for_each(cur, &desktop->outputs, link) {
if (cur == output)
continue;
/* XXX: Assumes size matches. */
if (cur->x == output->x && cur->y == output->y) {
rep = cur;
break;
}
}
if (rep) {
/* If found, hand over the background and panel so they don't
* get destroyed. */
assert(!rep->background);
assert(!rep->panel);
rep->background = output->background;
output->background = NULL;
rep->background->owner = rep;
rep->panel = output->panel;
output->panel = NULL;
if (rep->panel)
rep->panel->owner = rep;
}
output_destroy(output);
}
static void
global_handler(struct display *display, uint32_t id,
const char *interface, uint32_t version, void *data)
@ -1357,7 +1405,7 @@ global_handler_remove(struct display *display, uint32_t id,
if (!strcmp(interface, "wl_output")) {
wl_list_for_each(output, &desktop->outputs, link) {
if (output->server_output_id == id) {
output_destroy(output);
output_remove(desktop, output);
break;
}
}