summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Fourdan <ofourdan@redhat.com>2023-11-02 10:37:15 +0100
committerOlivier Fourdan <ofourdan@redhat.com>2024-03-20 09:05:36 +0100
commit4248bfb0da6e14c176acd0750393c66261d6f4c3 (patch)
tree6933010276adbcaf3c5bdd1de3b7b6d4a62140c1
parentcd0c43df13141cf100b16fea4ea0b93f6fff2325 (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>
-rw-r--r--hw/xwayland/xwayland-output.c5
-rw-r--r--hw/xwayland/xwayland-window.c52
-rw-r--r--hw/xwayland/xwayland-window.h8
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);