From 550984c95ef0bee1886dbb54e35edc0852772e2f Mon Sep 17 00:00:00 2001 From: Dima Ryazanov Date: Fri, 15 May 2015 22:38:28 -0700 Subject: [PATCH 1/3] xwayland: Destroy xwl_output when wl_output gets removed This makes Xwayland correctly handle a monitor getting unplugged. [Marek]: use xorg_list_for_each_entry_safe Signed-off-by: Dima Ryazanov Signed-off-by: Marek Chalupa --- hw/xwayland/xwayland-output.c | 1 + hw/xwayland/xwayland.c | 11 ++++++++++- hw/xwayland/xwayland.h | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index dd169e806..927224ac2 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -165,6 +165,7 @@ xwl_output_create(struct xwl_screen *xwl_screen, uint32_t id) xwl_output->output = wl_registry_bind(xwl_screen->registry, id, &wl_output_interface, 2); + xwl_output->server_output_id = id; wl_output_add_listener(xwl_output->output, &output_listener, xwl_output); snprintf(name, sizeof name, "XWAYLAND%d", serial++); diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index f25bc006b..e31becf5e 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -410,7 +410,16 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, static void global_remove(void *data, struct wl_registry *registry, uint32_t name) { - /* Nothing to do here, wl_compositor and wl_shm should not be removed */ + struct xwl_screen *xwl_screen = data; + struct xwl_output *xwl_output, *tmp_xwl_output; + + xorg_list_for_each_entry_safe(xwl_output, tmp_xwl_output, + &xwl_screen->output_list, link) { + if (xwl_output->server_output_id == name) { + xwl_output_destroy(xwl_output); + break; + } + } } static const struct wl_registry_listener registry_listener = { diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 53ca420cf..a7d71193d 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -142,6 +142,7 @@ struct xwl_seat { struct xwl_output { struct xorg_list link; struct wl_output *output; + uint32_t server_output_id; struct xwl_screen *xwl_screen; RROutputPtr randr_output; RRCrtcPtr randr_crtc; From 95014ad2a7815282efdecc895bf14742b4b3ccb3 Mon Sep 17 00:00:00 2001 From: Dima Ryazanov Date: Tue, 12 May 2015 10:21:18 -0700 Subject: [PATCH 2/3] xwayland: Remove the output from the list after destroying it [Marek Chalupa]: rebased to master Signed-off-by: Dima Ryazanov --- hw/xwayland/xwayland-output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 927224ac2..28aec8e15 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -185,6 +185,7 @@ void xwl_output_destroy(struct xwl_output *xwl_output) { wl_output_destroy(xwl_output->output); + xorg_list_del(&xwl_output->link); free(xwl_output); } From 21f384b7b8b571151805674c9d384e2ad7f8b7ea Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 21 May 2015 15:43:43 +0200 Subject: [PATCH 3/3] xwayland: do not add output into output_list multiple times output.done event can be sent even on some property change, not only when announcing the output. Therefore we must check if we already have it otherwise we may corrupt the list by adding it multiple times. This fixes bug when xwayland looped indefinitely in output.done handler and that can be reproduced following these steps (under X without multi-monitor setup): 1) run weston --output-count=2 2) run xterm, move it so that half is on one output and half on the other 3) close second output, try run weston-terminal weston sends updated outputs which trigger this bug. v2. factor out common code into function move expecting_events into right branch Signed-off-by: Marek Chalupa --- hw/xwayland/xwayland-output.c | 42 +++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 28aec8e15..1546eaa01 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -113,29 +113,47 @@ output_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, xwl_output->rotation, NULL, 1, &xwl_output->randr_output); } +static inline void +output_get_new_size(struct xwl_output *xwl_output, + int *height, int *width) +{ + if (*width < xwl_output->x + xwl_output->width) + *width = xwl_output->x + xwl_output->width; + + if (*height < xwl_output->y + xwl_output->height) + *height = xwl_output->y + xwl_output->height; +} + static void output_handle_done(void *data, struct wl_output *wl_output) { - struct xwl_output *xwl_output = data; + struct xwl_output *it, *xwl_output = data; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; - int width, height; + int width = 0, height = 0, has_this_output = 0; - xorg_list_append(&xwl_output->link, &xwl_screen->output_list); + xorg_list_for_each_entry(it, &xwl_screen->output_list, link) { + /* output done event is sent even when some property + * of output is changed. That means that we may already + * have this output. If it is true, we must not add it + * into the output_list otherwise we'll corrupt it */ + if (it == xwl_output) + has_this_output = 1; - width = 0; - height = 0; - xorg_list_for_each_entry(xwl_output, &xwl_screen->output_list, link) { - if (width < xwl_output->x + xwl_output->width) - width = xwl_output->x + xwl_output->width; - if (height < xwl_output->y + xwl_output->height) - height = xwl_output->y + xwl_output->height; + output_get_new_size(it, &height, &width); + } + + if (!has_this_output) { + xorg_list_append(&xwl_output->link, &xwl_screen->output_list); + + /* we did not check this output for new screen size, do it now */ + output_get_new_size(xwl_output, &height, &width); + + --xwl_screen->expecting_event; } xwl_screen->width = width; xwl_screen->height = height; RRScreenSizeNotify(xwl_screen->screen); - - xwl_screen->expecting_event--; } static void