diff options
Diffstat (limited to 'src/tests')
-rw-r--r-- | src/tests/meson.build | 8 | ||||
-rw-r--r-- | src/tests/monitor-configs/kms-cursor-hotplug-off.xml | 30 | ||||
-rw-r--r-- | src/tests/monitor-configs/kms-cursor-hotplug-on.xml | 40 | ||||
-rw-r--r-- | src/tests/native-kms-cursor-hotplug.c | 166 | ||||
-rw-r--r-- | src/tests/wayland-test-clients/kms-cursor-hotplug-helper.c | 286 | ||||
-rw-r--r-- | src/tests/wayland-test-clients/meson.build | 6 |
6 files changed, 536 insertions, 0 deletions
diff --git a/src/tests/meson.build b/src/tests/meson.build index 3768b83da..1b0a93ed7 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -409,6 +409,14 @@ if have_native_tests ], 'variants': kms_test_variants, }, + { + 'name': 'kms-cursor-hotplug', + 'suite': 'backends/native', + 'sources': [ + 'native-kms-cursor-hotplug.c', + wayland_test_utils, + ], + }, ] privileged_test_cases += kms_test_cases diff --git a/src/tests/monitor-configs/kms-cursor-hotplug-off.xml b/src/tests/monitor-configs/kms-cursor-hotplug-off.xml new file mode 100644 index 000000000..2eccd7887 --- /dev/null +++ b/src/tests/monitor-configs/kms-cursor-hotplug-off.xml @@ -0,0 +1,30 @@ +<monitors version="2"> + <configuration> + <logicalmonitor> + <x>0</x> + <y>0</y> + <primary>yes</primary> + <monitor> + <monitorspec> + <connector>Meta-0</connector> + <vendor>MetaTestVendor</vendor> + <product>MetaVirtualMonitor</product> + <serial>0x1234</serial> + </monitorspec> + <mode> + <width>100</width> + <height>100</height> + <rate>60</rate> + </mode> + </monitor> + </logicalmonitor> + <disabled> + <monitorspec> + <connector>Virtual-1</connector> + <vendor>unknown</vendor> + <product>unknown</product> + <serial>unknown</serial> + </monitorspec> + </disabled> + </configuration> +</monitors> diff --git a/src/tests/monitor-configs/kms-cursor-hotplug-on.xml b/src/tests/monitor-configs/kms-cursor-hotplug-on.xml new file mode 100644 index 000000000..67c0aacbd --- /dev/null +++ b/src/tests/monitor-configs/kms-cursor-hotplug-on.xml @@ -0,0 +1,40 @@ +<monitors version="2"> + <configuration> + <logicalmonitor> + <x>0</x> + <y>0</y> + <primary>yes</primary> + <monitor> + <monitorspec> + <connector>Virtual-1</connector> + <vendor>unknown</vendor> + <product>unknown</product> + <serial>unknown</serial> + </monitorspec> + <mode> + <width>1024</width> + <height>768</height> + <rate>60.003841</rate> + </mode> + </monitor> + </logicalmonitor> + <logicalmonitor> + <x>1024</x> + <y>0</y> + <primary>no</primary> + <monitor> + <monitorspec> + <connector>Meta-0</connector> + <vendor>MetaTestVendor</vendor> + <product>MetaVirtualMonitor</product> + <serial>0x1234</serial> + </monitorspec> + <mode> + <width>100</width> + <height>100</height> + <rate>60</rate> + </mode> + </monitor> + </logicalmonitor> + </configuration> +</monitors> diff --git a/src/tests/native-kms-cursor-hotplug.c b/src/tests/native-kms-cursor-hotplug.c new file mode 100644 index 000000000..1a9978c19 --- /dev/null +++ b/src/tests/native-kms-cursor-hotplug.c @@ -0,0 +1,166 @@ +/* + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + */ + +#include "config.h" + +#include "backends/meta-monitor-config-manager.h" +#include "backends/meta-virtual-monitor.h" +#include "core/window-private.h" +#include "meta-test/meta-context-test.h" +#include "meta/meta-backend.h" +#include "meta/meta-cursor-tracker.h" +#include "tests/meta-test-utils.h" +#include "tests/meta-wayland-test-driver.h" +#include "tests/meta-wayland-test-utils.h" +#include "tests/native-screen-cast.h" +#include "tests/native-virtual-monitor.h" +#include "wayland/meta-cursor-sprite-wayland.h" +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-seat.h" + +static MetaContext *test_context; + +static void +meta_test_cursor_hotplug (void) +{ + MetaBackend *backend = meta_context_get_backend (test_context); + MetaMonitorManager *monitor_manager = + meta_backend_get_monitor_manager (backend); + MetaCursorRenderer *cursor_renderer = meta_backend_get_cursor_renderer (backend); + MetaWaylandCompositor *wayland_compositor = + meta_context_get_wayland_compositor (test_context); + MetaWaylandSeat *wayland_seat = wayland_compositor->seat; + g_autoptr (MetaWaylandTestDriver) test_driver = NULL; + MetaCursorSprite *cursor_sprite; + g_autoptr (MetaVirtualMonitorInfo) monitor_info = NULL; + MetaVirtualMonitor *virtual_monitor; + ClutterSeat *seat; + g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL; + MetaWaylandTestClient *test_client; + MetaWindow *window; + GError *error = NULL; + + test_driver = meta_wayland_test_driver_new (wayland_compositor); + + seat = meta_backend_get_default_seat (backend); + virtual_pointer = clutter_seat_create_virtual_device (seat, + CLUTTER_POINTER_DEVICE); + + meta_set_custom_monitor_config_full (backend, "kms-cursor-hotplug-off.xml", + META_MONITORS_CONFIG_FLAG_NONE); + + monitor_info = meta_virtual_monitor_info_new (100, 100, 60.0, + "MetaTestVendor", + "MetaVirtualMonitor", + "0x1234"); + virtual_monitor = meta_monitor_manager_create_virtual_monitor (monitor_manager, + monitor_info, + &error); + if (!virtual_monitor) + g_error ("Failed to create virtual monitor: %s", error->message); + meta_monitor_manager_reload (monitor_manager); + + clutter_virtual_input_device_notify_absolute_motion (virtual_pointer, + g_get_monotonic_time (), + 50, 50); + + test_client = meta_wayland_test_client_new (test_context, + "kms-cursor-hotplug-helper"); + if (!test_client) + g_error ("Failed to launch test client: %s", error->message); + + while (TRUE) + { + window = meta_find_window_from_title (test_context, + "kms-cursor-hotplug-helper"); + if (window && window->visible_to_compositor) + break; + g_main_context_iteration (NULL, TRUE); + } + + meta_window_move_frame (window, FALSE, 0, 0); + meta_wait_for_paint (test_context); + + cursor_renderer = meta_backend_get_cursor_renderer (backend); + + while (TRUE) + { + cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer); + if (cursor_sprite) + break; + g_main_context_iteration (NULL, TRUE); + } + g_assert_true (META_IS_CURSOR_SPRITE_WAYLAND (cursor_sprite)); + + /* + * This tests a particular series of events: + * + * 1) Unplug the mouse + * 2) Client attaches a new cursor buffer + * 3) Client destroys cursor surface + * 4) Monitor hotplug + * + * This would cause a NULL pointer deference when getting the buffer from the + * cursor surface when trying to realize the hardware cursor buffer on the + * hotplugged monitor. + */ + + g_clear_object (&virtual_pointer); + while (!(wayland_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) + g_main_context_iteration (NULL, TRUE); + + meta_wayland_test_driver_emit_sync_event (test_driver, 0); + meta_wayland_test_driver_wait_for_sync_point (test_driver, 0); + + meta_set_custom_monitor_config_full (backend, "kms-cursor-hotplug-on.xml", + META_MONITORS_CONFIG_FLAG_NONE); + meta_monitor_manager_reload (monitor_manager); + meta_wait_for_paint (test_context); + + meta_wayland_test_driver_emit_sync_event (test_driver, 1); + meta_wayland_test_client_finish (test_client); +} + +static void +init_tests (void) +{ + g_test_add_func ("/wayland/cursor-hotplug", + meta_test_cursor_hotplug); +} + +int +main (int argc, + char **argv) +{ + g_autoptr (MetaContext) context = NULL; + + context = meta_create_test_context (META_CONTEXT_TEST_TYPE_VKMS, + META_CONTEXT_TEST_FLAG_NO_X11 | + META_CONTEXT_TEST_FLAG_TEST_CLIENT); + g_assert (meta_context_configure (context, &argc, &argv, NULL)); + + test_context = context; + + init_tests (); + + return meta_context_test_run_tests (META_CONTEXT_TEST (context), + META_TEST_RUN_FLAG_NONE); +} + diff --git a/src/tests/wayland-test-clients/kms-cursor-hotplug-helper.c b/src/tests/wayland-test-clients/kms-cursor-hotplug-helper.c new file mode 100644 index 000000000..ac9dd5822 --- /dev/null +++ b/src/tests/wayland-test-clients/kms-cursor-hotplug-helper.c @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib.h> +#include <wayland-client.h> +#include <wayland-cursor.h> + +#include "wayland-test-client-utils.h" + +static WaylandDisplay *display; + +static struct wl_registry *wl_registry; +static struct wl_seat *wl_seat; +static struct wl_pointer *wl_pointer; +static uint32_t enter_serial; + +static struct wl_surface *surface; +static struct xdg_surface *xdg_surface; +static struct xdg_toplevel *xdg_toplevel; +struct wl_surface *cursor_surface; +struct wl_cursor_theme *cursor_theme; +struct wl_cursor *cursor; +struct wl_cursor *cursor2; + +static gboolean running; + +static void +init_surface (void) +{ + xdg_toplevel_set_title (xdg_toplevel, "kms-cursor-hotplug-helper"); + wl_surface_commit (surface); +} + +static void +draw_main (int width, + int height) +{ + draw_surface (display, surface, width, height, 0xff00ff00); +} + +static void +handle_xdg_toplevel_configure (void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t width, + int32_t height, + struct wl_array *state) +{ +} + +static void +handle_xdg_toplevel_close (void *data, + struct xdg_toplevel *xdg_toplevel) +{ + g_assert_not_reached (); +} + +static void +handle_xdg_toplevel_configure_bounds (void *data, + struct xdg_toplevel *xdg_toplevel, + int32_t bounds_width, + int32_t bounds_height) +{ +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener = { + handle_xdg_toplevel_configure, + handle_xdg_toplevel_close, + handle_xdg_toplevel_configure_bounds, +}; + +static void +handle_xdg_surface_configure (void *data, + struct xdg_surface *xdg_surface, + uint32_t serial) +{ + draw_main (100, 100); + xdg_surface_ack_configure (xdg_surface, serial); + wl_surface_commit (surface); +} + +static const struct xdg_surface_listener xdg_surface_listener = { + handle_xdg_surface_configure, +}; + + +static void +pointer_handle_enter (void *data, + struct wl_pointer *pointer, + uint32_t serial, + struct wl_surface *surface, + wl_fixed_t sx, + wl_fixed_t sy) +{ + struct wl_buffer *buffer; + struct wl_cursor_image *image; + + image = cursor->images[0]; + buffer = wl_cursor_image_get_buffer (image); + + enter_serial = serial; + wl_pointer_set_cursor (pointer, serial, + cursor_surface, + image->hotspot_x, + image->hotspot_y); + wl_surface_attach (cursor_surface, buffer, 0, 0); + wl_surface_damage (cursor_surface, 0, 0, + image->width, image->height); + wl_surface_commit (cursor_surface); +} + +static void +pointer_handle_leave (void *data, + struct wl_pointer *pointer, + uint32_t serial, + struct wl_surface *surface) +{ +} + +static void +pointer_handle_motion (void *data, + struct wl_pointer *pointer, + uint32_t time, + wl_fixed_t sx, + wl_fixed_t sy) +{ +} + +static void +pointer_handle_button (void *data, + struct wl_pointer *pointer, + uint32_t serial, + uint32_t time, + uint32_t button, + uint32_t state) +{ +} + +static void +pointer_handle_axis (void *data, + struct wl_pointer *pointer, + uint32_t time, + uint32_t axis, + wl_fixed_t value) +{ +} + +static const struct wl_pointer_listener pointer_listener = { + pointer_handle_enter, + pointer_handle_leave, + pointer_handle_motion, + pointer_handle_button, + pointer_handle_axis, +}; + +static void +seat_handle_capabilities (void *data, + struct wl_seat *wl_seat, + enum wl_seat_capability caps) +{ + if (caps & WL_SEAT_CAPABILITY_POINTER) + { + wl_pointer = wl_seat_get_pointer (wl_seat); + wl_pointer_add_listener (wl_pointer, &pointer_listener, NULL); + } +} + +static void +seat_handle_name (void *data, + struct wl_seat *seat, + const char *name) +{ +} + +static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, + seat_handle_name, +}; + +static void +handle_registry_global (void *data, + struct wl_registry *registry, + uint32_t id, + const char *interface, + uint32_t version) +{ + if (strcmp (interface, "wl_seat") == 0) + { + wl_seat = wl_registry_bind (registry, id, + &wl_seat_interface, + 1); + wl_seat_add_listener (wl_seat, &seat_listener, NULL); + } +} + +static void +handle_registry_global_remove (void *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 +on_sync_event (WaylandDisplay *display, + uint32_t serial) +{ + if (serial == 1) + { + running = FALSE; + } + else if (serial == 0) + { + struct wl_buffer *buffer; + struct wl_cursor_image *image; + + image = cursor2->images[0]; + buffer = wl_cursor_image_get_buffer (image); + + wl_surface_attach (cursor_surface, buffer, 0, 0); + wl_surface_damage (cursor_surface, 0, 0, + image->width, image->height); + wl_surface_commit (cursor_surface); + + wl_surface_destroy (cursor_surface); + + test_driver_sync_point (display->test_driver, 0, NULL); + } +} + +int +main (int argc, + char **argv) +{ + display = wayland_display_new (WAYLAND_DISPLAY_CAPABILITY_TEST_DRIVER); + wl_registry = wl_display_get_registry (display->display); + wl_registry_add_listener (wl_registry, ®istry_listener, display); + wl_display_roundtrip (display->display); + + g_signal_connect (display, "sync-event", G_CALLBACK (on_sync_event), NULL); + + surface = wl_compositor_create_surface (display->compositor); + xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base, surface); + xdg_surface_add_listener (xdg_surface, &xdg_surface_listener, NULL); + xdg_toplevel = xdg_surface_get_toplevel (xdg_surface); + xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL); + + cursor_surface = wl_compositor_create_surface (display->compositor); + cursor_theme = wl_cursor_theme_load (NULL, 24, display->shm); + cursor = wl_cursor_theme_get_cursor (cursor_theme, "left_ptr"); + cursor2 = wl_cursor_theme_get_cursor (cursor_theme, "right_ptr"); + g_assert_nonnull (cursor); + g_assert_nonnull (cursor2); + + init_surface (); + wl_surface_commit (surface); + + running = TRUE; + while (running) + { + if (wl_display_dispatch (display->display) == -1) + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/src/tests/wayland-test-clients/meson.build b/src/tests/wayland-test-clients/meson.build index eafda40e4..6c1b76a25 100644 --- a/src/tests/wayland-test-clients/meson.build +++ b/src/tests/wayland-test-clients/meson.build @@ -57,6 +57,12 @@ wayland_test_clients = [ 'name': 'fullscreen', }, { + 'name': 'kms-cursor-hotplug-helper', + 'extra_deps': [ + wayland_cursor_dep, + ], + }, + { 'name': 'dma-buf-scanout', 'extra_deps': [ libdrm_dep, |