diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build index ac838231c..ce24c3fc8 100644 --- a/src/tests/wayland-test-clients/meson.build +++ b/src/tests/wayland-test-clients/meson.build @@ -73,6 +73,9 @@ wayland_test_clients = [ { 'name': 'xdg-activation', }, + { + 'name': 'xdg-foreign', + }, { 'name': 'xdg-toplevel-bounds', }, diff --git a/src/tests/wayland-test-clients/xdg-foreign.c b/src/tests/wayland-test-clients/xdg-foreign.c new file mode 100644 index 000000000..42bd83c0f --- /dev/null +++ b/src/tests/wayland-test-clients/xdg-foreign.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2022 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "config.h" + +#include + +#include "wayland-test-client-utils.h" + +#include "xdg-foreign-unstable-v1-client-protocol.h" +#include "xdg-foreign-unstable-v2-client-protocol.h" + +static WaylandDisplay *display; + +static struct zxdg_exporter_v1 *exporter_v1; +static struct zxdg_exporter_v2 *exporter_v2; +static struct zxdg_importer_v1 *importer_v1; +static struct zxdg_importer_v2 *importer_v2; + +static void +handle_xdg_exported_v2_handle (void *data, + struct zxdg_exported_v2 *zxdg_exported_v2, + const char *handle) +{ + char **handle_ptr = data; + + *handle_ptr = g_strdup (handle); +} + +static const struct zxdg_exported_v2_listener exported_v2_listener = { + handle_xdg_exported_v2_handle, +}; + +static void +handle_xdg_exported_v1_handle (void *data, + struct zxdg_exported_v1 *zxdg_exported_v1, + const char *handle) +{ + char **handle_ptr = data; + + *handle_ptr = g_strdup (handle); +} + +static const struct zxdg_exported_v1_listener exported_v1_listener = { + handle_xdg_exported_v1_handle, +}; + +static void +handle_registry_global (void *user_data, + struct wl_registry *registry, + uint32_t id, + const char *interface, + uint32_t version) +{ + if (strcmp (interface, "zxdg_exporter_v1") == 0) + { + exporter_v1 = wl_registry_bind (registry, id, + &zxdg_exporter_v1_interface, 1); + } + else if (strcmp (interface, "zxdg_exporter_v2") == 0) + { + exporter_v2 = wl_registry_bind (registry, id, + &zxdg_exporter_v2_interface, 1); + } + else if (strcmp (interface, "zxdg_importer_v1") == 0) + { + importer_v1 = wl_registry_bind (registry, id, + &zxdg_importer_v1_interface, 1); + } + else if (strcmp (interface, "zxdg_importer_v2") == 0) + { + importer_v2 = wl_registry_bind (registry, id, + &zxdg_importer_v2_interface, 1); + } +} + +static void +handle_registry_global_remove (void *user_data, + struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener = { + handle_registry_global, + handle_registry_global_remove +}; + +static void +xdg_imported_v1_destroyed (void *data, + struct zxdg_imported_v1 *zxdg_imported_v1) +{ + gboolean *destroyed = data; + + *destroyed = TRUE; +} + +static const struct zxdg_imported_v1_listener xdg_imported_v1_listener = { + xdg_imported_v1_destroyed, +}; + +static void +xdg_imported_v2_destroyed (void *data, + struct zxdg_imported_v2 *zxdg_imported_v2) +{ + gboolean *destroyed = data; + + *destroyed = TRUE; +} + +static const struct zxdg_imported_v2_listener xdg_imported_v2_listener = { + xdg_imported_v2_destroyed, +}; + +int +main (int argc, + char **argv) +{ + WaylandSurface *window1; + WaylandSurface *window2; + WaylandSurface *window3; + WaylandSurface *window4; + g_autofree char *handle1 = NULL; + g_autofree char *handle3 = NULL; + struct wl_registry *registry; + struct zxdg_exported_v1 *exported1; /* for window1 */ + struct zxdg_exported_v2 *exported3; /* for window2 */ + struct zxdg_imported_v2 *imported1; /* for window1 */ + struct zxdg_imported_v1 *imported3; /* for window2 */ + gboolean imported1_destroyed = FALSE; + gboolean imported3_destroyed = FALSE; + + display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER); + + registry = wl_display_get_registry (display->display); + wl_registry_add_listener (registry, ®istry_listener, NULL); + wl_display_roundtrip (display->display); + + g_assert_nonnull (exporter_v1); + g_assert_nonnull (exporter_v2); + g_assert_nonnull (importer_v1); + g_assert_nonnull (importer_v2); + + window1 = wayland_surface_new (display, "xdg-foreign-window1", + 100, 100, 0xff50ff50); + window2 = wayland_surface_new (display, "xdg-foreign-window2", + 100, 100, 0xff0000ff); + window3 = wayland_surface_new (display, "xdg-foreign-window3", + 100, 100, 0xff2020ff); + window4 = wayland_surface_new (display, "xdg-foreign-window4", + 100, 100, 0xff40ffff); + + exported1 = zxdg_exporter_v1_export (exporter_v1, window1->wl_surface); + zxdg_exported_v1_add_listener (exported1, &exported_v1_listener, &handle1); + + exported3 = zxdg_exporter_v2_export_toplevel (exporter_v2, + window3->wl_surface); + zxdg_exported_v2_add_listener (exported3, &exported_v2_listener, &handle3); + + while (!handle1 && !handle3) + { + if (wl_display_dispatch (display->display) == -1) + return EXIT_FAILURE; + } + + zxdg_importer_v2_import_toplevel (importer_v2, "don't crash on bogus handle"); + zxdg_importer_v1_import (importer_v1, "don't crash on bogus handle"); + + imported1 = zxdg_importer_v2_import_toplevel (importer_v2, handle1); + zxdg_imported_v2_add_listener (imported1, &xdg_imported_v2_listener, + &imported1_destroyed); + imported3 = zxdg_importer_v1_import (importer_v1, handle3); + zxdg_imported_v1_add_listener (imported3, &xdg_imported_v1_listener, + &imported3_destroyed); + + /* + * +------+ + * | W1 +------+ + * | | W2 +------+ + * | | | W3 +----+ + * | | | | W4 | + * +----+----+----+----+ + * ^ ^ + * |_ exported with v1, imported with v2 + * |__ exported with v2, imported with v1 + */ + + zxdg_imported_v2_set_parent_of (imported1, window2->wl_surface); + xdg_toplevel_set_parent (window3->xdg_toplevel, + window2->xdg_toplevel); + zxdg_imported_v1_set_parent_of (imported3, window4->wl_surface); + + wl_surface_commit (window1->wl_surface); + wl_surface_commit (window2->wl_surface); + wl_surface_commit (window3->wl_surface); + wl_surface_commit (window4->wl_surface); + + test_driver_sync_point (display->test_driver, 0, NULL); + + wait_for_sync_event (display, 0); + + zxdg_exported_v1_destroy (exported1); + zxdg_exported_v2_destroy (exported3); + + while (!imported1_destroyed || !imported3_destroyed) + { + if (wl_display_dispatch (display->display) == -1) + return EXIT_FAILURE; + } + + wayland_surface_free (window1); + wayland_surface_free (window2); + wayland_surface_free (window3); + wayland_surface_free (window4); + + g_object_unref (display); + + return EXIT_SUCCESS; +} diff --git a/src/tests/wayland-unit-tests.c b/src/tests/wayland-unit-tests.c index 9b2ba7594..5bfc8592c 100644 --- a/src/tests/wayland-unit-tests.c +++ b/src/tests/wayland-unit-tests.c @@ -643,6 +643,39 @@ toplevel_bounds_monitors (void) meta_wayland_test_client_finish (wayland_test_client); } +static void +xdg_foreign_set_parent_of (void) +{ + MetaWaylandTestClient *wayland_test_client; + MetaWindow *window1; + MetaWindow *window2; + MetaWindow *window3; + MetaWindow *window4; + + wayland_test_client = + meta_wayland_test_client_new (test_context, "xdg-foreign"); + + wait_for_sync_point (0); + wait_until_after_paint (); + + window1 = find_client_window ("xdg-foreign-window1"); + window2 = find_client_window ("xdg-foreign-window2"); + window3 = find_client_window ("xdg-foreign-window3"); + window4 = find_client_window ("xdg-foreign-window4"); + + g_assert_true (meta_window_get_transient_for (window4) == + window3); + g_assert_true (meta_window_get_transient_for (window3) == + window2); + g_assert_true (meta_window_get_transient_for (window2) == + window1); + g_assert_null (meta_window_get_transient_for (window1)); + + meta_wayland_test_driver_emit_sync_event (test_driver, 0); + + meta_wayland_test_client_finish (wayland_test_client); +} + static void on_before_tests (void) { @@ -686,6 +719,8 @@ init_tests (void) toplevel_bounds_struts); g_test_add_func ("/wayland/toplevel/bounds/monitors", toplevel_bounds_monitors); + g_test_add_func ("/wayland/xdg-foreign/set-parent-of", + xdg_foreign_set_parent_of); } int