diff options
author | Olivier Fourdan <ofourdan@redhat.com> | 2023-11-02 10:37:15 +0100 |
---|---|---|
committer | Olivier Fourdan <ofourdan@redhat.com> | 2024-03-20 09:05:36 +0100 |
commit | 4248bfb0da6e14c176acd0750393c66261d6f4c3 (patch) | |
tree | 6933010276adbcaf3c5bdd1de3b7b6d4a62140c1 /hw/xwayland | |
parent | cd0c43df13141cf100b16fea4ea0b93f6fff2325 (diff) |
xwayland: Keep track of outputs per window
Add a list of outputs a window is placed on, adding an output whenever
the surface enters the output and removing it once it leaves the output.
Note that not all Wayland compositors actually send a leave surface
event on output removal, so we need to make sure to remove the output
from the list for each window, otherwise we might end up pointing to
freed memory.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Reviewed-By: Kenny Levinsen <kl@kl.wtf>
Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/1197>
Diffstat (limited to 'hw/xwayland')
-rw-r--r-- | hw/xwayland/xwayland-output.c | 5 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.c | 52 | ||||
-rw-r--r-- | hw/xwayland/xwayland-window.h | 8 |
3 files changed, 62 insertions, 3 deletions
diff --git a/hw/xwayland/xwayland-output.c b/hw/xwayland/xwayland-output.c index 2c987a39f..f77ba8278 100644 --- a/hw/xwayland/xwayland-output.c +++ b/hw/xwayland/xwayland-output.c @@ -962,8 +962,13 @@ xwl_output_remove(struct xwl_output *xwl_output) { struct xwl_output *it; struct xwl_screen *xwl_screen = xwl_output->xwl_screen; + struct xwl_window *xwl_window; int width = 0, height = 0; + /* Not all compositors send a "leave" event on output removal */ + xorg_list_for_each_entry(xwl_window, &xwl_screen->window_list, link_window) + xwl_window_leave_output(xwl_window, xwl_output); + xorg_list_del(&xwl_output->link); if (xwl_output->randr_output) diff --git a/hw/xwayland/xwayland-window.c b/hw/xwayland/xwayland-window.c index d419e3070..b439c3a47 100644 --- a/hw/xwayland/xwayland-window.c +++ b/hw/xwayland/xwayland-window.c @@ -795,12 +795,50 @@ static const struct xdg_surface_listener xdg_surface_listener = { }; static void +xwl_window_enter_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output) +{ + struct xwl_window_output *window_output; + + window_output = xnfcalloc(1, sizeof(struct xwl_window_output)); + window_output->xwl_output = xwl_output; + xorg_list_add(&window_output->link, &xwl_window->xwl_output_list); +} + +void +xwl_window_leave_output(struct xwl_window *xwl_window, struct xwl_output *xwl_output) +{ + struct xwl_window_output *window_output, *tmp; + + xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) { + if (window_output->xwl_output == xwl_output) { + xorg_list_del(&window_output->link); + free(window_output); + } + } +} + +static void +xwl_window_free_outputs(struct xwl_window *xwl_window) +{ + struct xwl_window_output *window_output, *tmp; + + xorg_list_for_each_entry_safe(window_output, tmp, &xwl_window->xwl_output_list, link) { + xorg_list_del(&window_output->link); + free(window_output); + } +} + +static void xwl_window_surface_enter(void *data, struct wl_surface *wl_surface, struct wl_output *wl_output) { struct xwl_window *xwl_window = data; struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output); + + if (xwl_output) + xwl_window_enter_output(xwl_window, xwl_output); if (xwl_window->wl_output != wl_output) { xwl_window->wl_output = wl_output; @@ -816,6 +854,11 @@ xwl_window_surface_leave(void *data, struct wl_output *wl_output) { struct xwl_window *xwl_window = data; + struct xwl_screen *xwl_screen = xwl_window->xwl_screen; + struct xwl_output *xwl_output = xwl_output_from_wl_output(xwl_screen, wl_output); + + if (xwl_output) + xwl_window_leave_output(xwl_window, xwl_output); if (xwl_window->wl_output == wl_output) xwl_window->wl_output = NULL; @@ -913,9 +956,6 @@ xwl_create_root_surface(struct xwl_window *xwl_window) goto err_surf; } - wl_surface_add_listener(xwl_window->surface, - &surface_listener, xwl_window); - xdg_surface_add_listener(xwl_window->xdg_surface, &xdg_surface_listener, xwl_window); @@ -924,6 +964,9 @@ xwl_create_root_surface(struct xwl_window *xwl_window) xwl_window); } + wl_surface_add_listener(xwl_window->surface, + &surface_listener, xwl_window); + xwl_window_rootful_update_title(xwl_window); xwl_window_rootful_set_app_id(xwl_window); wl_surface_commit(xwl_window->surface); @@ -981,6 +1024,7 @@ ensure_surface_for_window(WindowPtr window) xwl_window->window = window; xwl_window->viewport_scale_x = 1.0; xwl_window->viewport_scale_y = 1.0; + xorg_list_init(&xwl_window->xwl_output_list); xwl_window->surface = wl_compositor_create_surface(xwl_screen->compositor); if (xwl_window->surface == NULL) { ErrorF("wl_display_create_surface failed\n"); @@ -1230,6 +1274,8 @@ xwl_unrealize_window(WindowPtr window) if (xwl_window->frame_callback) wl_callback_destroy(xwl_window->frame_callback); + xwl_window_free_outputs(xwl_window); + free(xwl_window); dixSetPrivate(&window->devPrivates, &xwl_window_private_key, NULL); diff --git a/hw/xwayland/xwayland-window.h b/hw/xwayland/xwayland-window.h index 08629877f..0e45f08d2 100644 --- a/hw/xwayland/xwayland-window.h +++ b/hw/xwayland/xwayland-window.h @@ -49,6 +49,11 @@ struct xwl_wl_surface { struct xorg_list link; }; +struct xwl_window_output { + struct xorg_list link; + struct xwl_output *xwl_output; +}; + struct xwl_window { struct xwl_screen *xwl_screen; struct wl_surface *surface; @@ -66,6 +71,7 @@ struct xwl_window { OsTimerPtr window_buffers_timer; struct wl_output *wl_output; struct wl_output *wl_output_fullscreen; + struct xorg_list xwl_output_list; struct xorg_list frame_callback_list; #ifdef XWL_HAS_LIBDECOR struct libdecor_frame *libdecor_frame; @@ -92,6 +98,8 @@ void xwl_window_rootful_update_fullscreen(struct xwl_window *xwl_window, struct xwl_output *xwl_output); void xwl_window_set_window_pixmap(WindowPtr window, PixmapPtr pixmap); +void xwl_window_leave_output(struct xwl_window *xwl_window, + struct xwl_output *xwl_output); Bool xwl_realize_window(WindowPtr window); Bool xwl_unrealize_window(WindowPtr window); Bool xwl_change_window_attributes(WindowPtr window, unsigned long mask); |