mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 10:30:47 -05:00
tests/wayland-unit-tests: Add test case for remapping popup with subsurface
This test reproduces the crash in https://gitlab.gnome.org/GNOME/mutter/-/issues/1828. It does not reproduce with 'window-actor/wayland: Remove subsurface actors on dispose' (dd416dd3e2
). applied. This test case differs slightly from the one that came with thedd416dd3e2
as in that it uses withdrawn popup surfaces instead of explicitly client managed state. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1993>
This commit is contained in:
parent
8a43123765
commit
3602762a18
@ -117,6 +117,7 @@ void meta_backend_prepare_shutdown (MetaBackend *backend);
|
|||||||
META_EXPORT_TEST
|
META_EXPORT_TEST
|
||||||
ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
|
ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
|
||||||
|
|
||||||
|
META_EXPORT_TEST
|
||||||
ClutterSeat * meta_backend_get_default_seat (MetaBackend *bakcend);
|
ClutterSeat * meta_backend_get_default_seat (MetaBackend *bakcend);
|
||||||
|
|
||||||
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
|
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,
|
||||||
|
@ -85,6 +85,8 @@ void meta_window_actor_assign_surface_actor (MetaWindowActor *self,
|
|||||||
|
|
||||||
META_EXPORT_TEST
|
META_EXPORT_TEST
|
||||||
MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
|
MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
|
||||||
|
|
||||||
|
META_EXPORT_TEST
|
||||||
MetaWindowActor *meta_window_actor_from_actor (ClutterActor *actor);
|
MetaWindowActor *meta_window_actor_from_actor (ClutterActor *actor);
|
||||||
|
|
||||||
void meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor,
|
void meta_window_actor_set_geometry_scale (MetaWindowActor *window_actor,
|
||||||
|
@ -48,6 +48,7 @@ common_sources = [
|
|||||||
wayland_test_clients = [
|
wayland_test_clients = [
|
||||||
'subsurface-remap-toplevel',
|
'subsurface-remap-toplevel',
|
||||||
'subsurface-reparenting',
|
'subsurface-reparenting',
|
||||||
|
'subsurface-parent-unmapped',
|
||||||
'invalid-subsurfaces',
|
'invalid-subsurfaces',
|
||||||
'invalid-xdg-shell-actions',
|
'invalid-xdg-shell-actions',
|
||||||
'xdg-apply-limits',
|
'xdg-apply-limits',
|
||||||
|
494
src/tests/wayland-test-clients/subsurface-parent-unmapped.c
Normal file
494
src/tests/wayland-test-clients/subsurface-parent-unmapped.c
Normal file
@ -0,0 +1,494 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 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 <linux/input-event-codes.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
|
|
||||||
|
#include "wayland-test-client-utils.h"
|
||||||
|
|
||||||
|
#include "test-driver-client-protocol.h"
|
||||||
|
#include "xdg-shell-client-protocol.h"
|
||||||
|
|
||||||
|
static struct wl_display *display;
|
||||||
|
static struct wl_registry *registry;
|
||||||
|
static struct wl_compositor *compositor;
|
||||||
|
static struct wl_subcompositor *subcompositor;
|
||||||
|
static struct xdg_wm_base *xdg_wm_base;
|
||||||
|
static struct wl_shm *shm;
|
||||||
|
static struct wl_seat *seat;
|
||||||
|
static struct wl_pointer *pointer;
|
||||||
|
static struct test_driver *test_driver;
|
||||||
|
|
||||||
|
static struct wl_surface *toplevel_surface;
|
||||||
|
static struct xdg_surface *toplevel_xdg_surface;
|
||||||
|
static struct xdg_toplevel *xdg_toplevel;
|
||||||
|
|
||||||
|
static struct wl_surface *popup_surface;
|
||||||
|
static struct xdg_surface *popup_xdg_surface;
|
||||||
|
static struct xdg_popup *xdg_popup;
|
||||||
|
|
||||||
|
static struct wl_surface *subsurface_surface;
|
||||||
|
static struct wl_subsurface *subsurface;
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_buffer_release (void *data,
|
||||||
|
struct wl_buffer *buffer)
|
||||||
|
{
|
||||||
|
wl_buffer_destroy (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_buffer_listener buffer_listener = {
|
||||||
|
handle_buffer_release
|
||||||
|
};
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
create_shm_buffer (int width,
|
||||||
|
int height,
|
||||||
|
struct wl_buffer **out_buffer,
|
||||||
|
void **out_data,
|
||||||
|
int *out_size)
|
||||||
|
{
|
||||||
|
struct wl_shm_pool *pool;
|
||||||
|
static struct wl_buffer *buffer;
|
||||||
|
int fd, size, stride;
|
||||||
|
int bytes_per_pixel;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
stride = width * bytes_per_pixel;
|
||||||
|
size = stride * height;
|
||||||
|
|
||||||
|
fd = create_anonymous_file (size);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Creating a buffer file for %d B failed: %m\n",
|
||||||
|
size);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||||
|
if (data == MAP_FAILED)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "mmap failed: %m\n");
|
||||||
|
close (fd);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = wl_shm_create_pool (shm, fd, size);
|
||||||
|
buffer = wl_shm_pool_create_buffer (pool, 0,
|
||||||
|
width, height,
|
||||||
|
stride,
|
||||||
|
WL_SHM_FORMAT_ARGB8888);
|
||||||
|
wl_buffer_add_listener (buffer, &buffer_listener, buffer);
|
||||||
|
wl_shm_pool_destroy (pool);
|
||||||
|
close (fd);
|
||||||
|
|
||||||
|
*out_buffer = buffer;
|
||||||
|
*out_data = data;
|
||||||
|
*out_size = size;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill (void *buffer_data,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
uint32_t color)
|
||||||
|
{
|
||||||
|
uint32_t *pixels = buffer_data;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
pixels[y * width + x] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw (struct wl_surface *surface,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
uint32_t color)
|
||||||
|
{
|
||||||
|
struct wl_buffer *buffer;
|
||||||
|
void *buffer_data;
|
||||||
|
int size;
|
||||||
|
|
||||||
|
if (!create_shm_buffer (width, height,
|
||||||
|
&buffer, &buffer_data, &size))
|
||||||
|
g_error ("Failed to create shm buffer");
|
||||||
|
|
||||||
|
fill (buffer_data, width, height, color);
|
||||||
|
|
||||||
|
wl_surface_attach (surface, buffer, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_main (void)
|
||||||
|
{
|
||||||
|
draw (toplevel_surface, 200, 200, 0xff00ffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_popup (void)
|
||||||
|
{
|
||||||
|
draw (popup_surface, 100, 100, 0xff005500);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
draw_subsurface (void)
|
||||||
|
{
|
||||||
|
draw (subsurface_surface, 100, 50, 0xff001f00);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||||
|
handle_xdg_toplevel_configure,
|
||||||
|
handle_xdg_toplevel_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_toplevel_xdg_surface_configure (void *data,
|
||||||
|
struct xdg_surface *xdg_surface,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
xdg_surface_ack_configure (xdg_surface, serial);
|
||||||
|
draw_main ();
|
||||||
|
wl_surface_commit (toplevel_surface);
|
||||||
|
wl_display_flush (display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xdg_surface_listener toplevel_xdg_surface_listener = {
|
||||||
|
handle_toplevel_xdg_surface_configure,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_xdg_wm_base_ping (void *data,
|
||||||
|
struct xdg_wm_base *xdg_wm_base,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
xdg_wm_base_pong (xdg_wm_base, serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||||
|
handle_xdg_wm_base_ping,
|
||||||
|
};
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
handle_popup_frame_callback (void *data,
|
||||||
|
struct wl_callback *callback,
|
||||||
|
uint32_t time)
|
||||||
|
{
|
||||||
|
wl_callback_destroy (callback);
|
||||||
|
test_driver_sync_point (test_driver, 0, popup_surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wl_callback_listener frame_listener = {
|
||||||
|
handle_popup_frame_callback,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_popup_xdg_surface_configure (void *data,
|
||||||
|
struct xdg_surface *xdg_surface,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
struct wl_callback *frame_callback;
|
||||||
|
|
||||||
|
draw_popup ();
|
||||||
|
|
||||||
|
draw_subsurface ();
|
||||||
|
wl_surface_commit (subsurface_surface);
|
||||||
|
|
||||||
|
xdg_surface_ack_configure (xdg_surface, serial);
|
||||||
|
frame_callback = wl_surface_frame (popup_surface);
|
||||||
|
wl_callback_add_listener (frame_callback, &frame_listener, NULL);
|
||||||
|
wl_surface_commit (popup_surface);
|
||||||
|
wl_display_flush (display);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct xdg_surface_listener popup_xdg_surface_listener = {
|
||||||
|
handle_popup_xdg_surface_configure,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
pointer_handle_button (void *data,
|
||||||
|
struct wl_pointer *pointer,
|
||||||
|
uint32_t serial,
|
||||||
|
uint32_t time,
|
||||||
|
uint32_t button,
|
||||||
|
uint32_t state)
|
||||||
|
{
|
||||||
|
struct xdg_positioner *positioner;
|
||||||
|
static int click_count = 0;
|
||||||
|
|
||||||
|
if (button != BTN_LEFT || state != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Create a grabbing popup surface */
|
||||||
|
popup_xdg_surface = xdg_wm_base_get_xdg_surface (xdg_wm_base,
|
||||||
|
popup_surface);
|
||||||
|
xdg_surface_add_listener (popup_xdg_surface,
|
||||||
|
&popup_xdg_surface_listener, NULL);
|
||||||
|
positioner = xdg_wm_base_create_positioner (xdg_wm_base);
|
||||||
|
xdg_positioner_set_size (positioner, 100, 100);
|
||||||
|
xdg_positioner_set_anchor_rect (positioner, 0, 0, 1, 1);
|
||||||
|
xdg_popup = xdg_surface_get_popup (popup_xdg_surface, toplevel_xdg_surface,
|
||||||
|
positioner);
|
||||||
|
xdg_positioner_destroy (positioner);
|
||||||
|
xdg_popup_grab (xdg_popup, seat, serial);
|
||||||
|
wl_surface_commit (popup_surface);
|
||||||
|
|
||||||
|
if (click_count == 1)
|
||||||
|
{
|
||||||
|
/* This ensure that the second time the popup is opened, the commit
|
||||||
|
* is handled accurately. This passing verifies we don't reproduce
|
||||||
|
* https://gitlab.gnome.org/GNOME/mutter/-/issues/1828.
|
||||||
|
*/
|
||||||
|
wl_display_roundtrip (display);
|
||||||
|
exit (EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
click_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
pointer = wl_seat_get_pointer (wl_seat);
|
||||||
|
wl_pointer_add_listener (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
|
||||||
|
test_driver_handle_sync_event (void *data,
|
||||||
|
struct test_driver *test_driver,
|
||||||
|
uint32_t serial)
|
||||||
|
{
|
||||||
|
g_assert (serial == 0);
|
||||||
|
|
||||||
|
/* Sync event 0 is sent when the popup window actor is destryed;
|
||||||
|
* prepare for opening a popup for the same wl_surface.
|
||||||
|
*/
|
||||||
|
wl_surface_attach (popup_surface, NULL, 0, 0);
|
||||||
|
wl_surface_commit (popup_surface);
|
||||||
|
g_clear_pointer (&xdg_popup, xdg_popup_destroy);
|
||||||
|
g_clear_pointer (&popup_xdg_surface, xdg_surface_destroy);
|
||||||
|
|
||||||
|
/* This will trigger a click again, opening the popup a second time. */
|
||||||
|
test_driver_sync_point (test_driver, 1, toplevel_surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct test_driver_listener test_driver_listener = {
|
||||||
|
test_driver_handle_sync_event,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_registry_global (void *data,
|
||||||
|
struct wl_registry *registry,
|
||||||
|
uint32_t id,
|
||||||
|
const char *interface,
|
||||||
|
uint32_t version)
|
||||||
|
{
|
||||||
|
if (strcmp (interface, "wl_compositor") == 0)
|
||||||
|
{
|
||||||
|
compositor = wl_registry_bind (registry, id, &wl_compositor_interface, 1);
|
||||||
|
}
|
||||||
|
else if (strcmp (interface, "wl_subcompositor") == 0)
|
||||||
|
{
|
||||||
|
subcompositor = wl_registry_bind (registry,
|
||||||
|
id, &wl_subcompositor_interface, 1);
|
||||||
|
}
|
||||||
|
else if (strcmp (interface, "xdg_wm_base") == 0)
|
||||||
|
{
|
||||||
|
xdg_wm_base = wl_registry_bind (registry, id,
|
||||||
|
&xdg_wm_base_interface, 1);
|
||||||
|
xdg_wm_base_add_listener (xdg_wm_base, &xdg_wm_base_listener, NULL);
|
||||||
|
}
|
||||||
|
else if (strcmp (interface, "wl_shm") == 0)
|
||||||
|
{
|
||||||
|
shm = wl_registry_bind (registry,
|
||||||
|
id, &wl_shm_interface, 1);
|
||||||
|
}
|
||||||
|
else if (strcmp (interface, "wl_seat") == 0)
|
||||||
|
{
|
||||||
|
seat = wl_registry_bind (registry, id, &wl_seat_interface, 1);
|
||||||
|
wl_seat_add_listener (seat, &seat_listener, NULL);
|
||||||
|
}
|
||||||
|
else if (strcmp (interface, "test_driver") == 0)
|
||||||
|
{
|
||||||
|
test_driver = wl_registry_bind (registry, id, &test_driver_interface, 1);
|
||||||
|
test_driver_add_listener (test_driver, &test_driver_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
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc,
|
||||||
|
char **argv)
|
||||||
|
{
|
||||||
|
display = wl_display_connect (NULL);
|
||||||
|
registry = wl_display_get_registry (display);
|
||||||
|
wl_registry_add_listener (registry, ®istry_listener, NULL);
|
||||||
|
wl_display_roundtrip (display);
|
||||||
|
|
||||||
|
if (!shm)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "No wl_shm global\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!xdg_wm_base)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "No xdg_wm_base global\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_display_roundtrip (display);
|
||||||
|
|
||||||
|
g_assert_nonnull (test_driver);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This test case does the following:
|
||||||
|
*
|
||||||
|
* 1) Open a toplevel
|
||||||
|
* 2) Open a popup in response to a pointer click
|
||||||
|
* 3) Place a subsurface on that popup
|
||||||
|
* 4) After painting, get the popup dismissed by the compositor
|
||||||
|
* 5) Once the popup window actor is destroyed, trigger a new pointer click
|
||||||
|
* 6) Open the popup again using the same wl_surface, thus with the same
|
||||||
|
* subsurface association set up.
|
||||||
|
*/
|
||||||
|
|
||||||
|
toplevel_surface = wl_compositor_create_surface (compositor);
|
||||||
|
toplevel_xdg_surface = xdg_wm_base_get_xdg_surface (xdg_wm_base,
|
||||||
|
toplevel_surface);
|
||||||
|
xdg_surface_add_listener (toplevel_xdg_surface,
|
||||||
|
&toplevel_xdg_surface_listener, NULL);
|
||||||
|
xdg_toplevel = xdg_surface_get_toplevel (toplevel_xdg_surface);
|
||||||
|
xdg_toplevel_add_listener (xdg_toplevel, &xdg_toplevel_listener, NULL);
|
||||||
|
xdg_toplevel_set_title (xdg_toplevel, "subsurface-parent-unmapped");
|
||||||
|
wl_surface_commit (toplevel_surface);
|
||||||
|
|
||||||
|
popup_surface = wl_compositor_create_surface (compositor);
|
||||||
|
subsurface_surface = wl_compositor_create_surface (compositor);
|
||||||
|
subsurface = wl_subcompositor_get_subsurface (subcompositor,
|
||||||
|
subsurface_surface,
|
||||||
|
popup_surface);
|
||||||
|
wl_subsurface_set_position (subsurface, 0, 0);
|
||||||
|
wl_subsurface_set_desync (subsurface);
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
if (wl_display_dispatch (display) == -1)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -20,6 +20,7 @@
|
|||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
#include "backends/meta-virtual-monitor.h"
|
#include "backends/meta-virtual-monitor.h"
|
||||||
|
#include "compositor/meta-window-actor-private.h"
|
||||||
#include "core/display-private.h"
|
#include "core/display-private.h"
|
||||||
#include "core/window-private.h"
|
#include "core/window-private.h"
|
||||||
#include "meta-test/meta-context-test.h"
|
#include "meta-test/meta-context-test.h"
|
||||||
@ -37,6 +38,7 @@ typedef struct _WaylandTestClient
|
|||||||
static MetaContext *test_context;
|
static MetaContext *test_context;
|
||||||
static MetaWaylandTestDriver *test_driver;
|
static MetaWaylandTestDriver *test_driver;
|
||||||
static MetaVirtualMonitor *virtual_monitor;
|
static MetaVirtualMonitor *virtual_monitor;
|
||||||
|
static ClutterVirtualInputDevice *virtual_pointer;
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_test_client_path (const char *test_client_name)
|
get_test_client_path (const char *test_client_name)
|
||||||
@ -185,6 +187,187 @@ subsurface_invalid_xdg_shell_actions (void)
|
|||||||
g_test_assert_expected_messages ();
|
g_test_assert_expected_messages ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_after_paint (ClutterStage *stage,
|
||||||
|
ClutterStageView *view,
|
||||||
|
gboolean *was_painted)
|
||||||
|
{
|
||||||
|
*was_painted = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wait_for_paint (ClutterActor *stage)
|
||||||
|
{
|
||||||
|
gboolean was_painted = FALSE;
|
||||||
|
gulong was_painted_id;
|
||||||
|
|
||||||
|
was_painted_id = g_signal_connect (CLUTTER_STAGE (stage),
|
||||||
|
"after-paint",
|
||||||
|
G_CALLBACK (on_after_paint),
|
||||||
|
&was_painted);
|
||||||
|
|
||||||
|
while (!was_painted)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
|
||||||
|
g_signal_handler_disconnect (stage, was_painted_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_effects_completed_idle (gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaWindowActor *actor = user_data;
|
||||||
|
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||||
|
ClutterActor *stage = meta_backend_get_stage (backend);
|
||||||
|
MetaWindow *window = meta_window_actor_get_meta_window (actor);
|
||||||
|
MetaRectangle buffer_rect;
|
||||||
|
|
||||||
|
/* Move the window to a known position and perform a mouse click, allowing a
|
||||||
|
* popup to be mapped. */
|
||||||
|
|
||||||
|
meta_window_move_frame (window, FALSE, 0, 0);
|
||||||
|
|
||||||
|
clutter_actor_queue_redraw (stage);
|
||||||
|
clutter_stage_schedule_update (CLUTTER_STAGE (stage));
|
||||||
|
|
||||||
|
wait_for_paint (stage);
|
||||||
|
|
||||||
|
meta_window_get_buffer_rect (window, &buffer_rect);
|
||||||
|
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
buffer_rect.x + 10,
|
||||||
|
buffer_rect.y + 10);
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_PRESSED);
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_RELEASED);
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_effects_completed (MetaWindowActor *actor)
|
||||||
|
{
|
||||||
|
g_idle_add (on_effects_completed_idle, actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_window_added (MetaStack *stack,
|
||||||
|
MetaWindow *window)
|
||||||
|
{
|
||||||
|
MetaWindowActor *actor = meta_window_actor_from_window (window);
|
||||||
|
|
||||||
|
g_assert_nonnull (actor);
|
||||||
|
|
||||||
|
if (g_strcmp0 (meta_window_get_title (window),
|
||||||
|
"subsurface-parent-unmapped") != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_signal_connect (actor, "effects-completed",
|
||||||
|
G_CALLBACK (on_effects_completed),
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_window_actor_destroyed (MetaWindowActor *actor,
|
||||||
|
MetaWaylandTestDriver *test_driver)
|
||||||
|
{
|
||||||
|
meta_wayland_test_driver_emit_sync_event (test_driver, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_unmap_sync_point (MetaWaylandTestDriver *test_driver,
|
||||||
|
unsigned int sequence,
|
||||||
|
struct wl_resource *surface_resource,
|
||||||
|
struct wl_client *wl_client)
|
||||||
|
{
|
||||||
|
if (sequence == 0)
|
||||||
|
{
|
||||||
|
/* Dismiss popup by clicking outside. */
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
390, 390);
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_PRESSED);
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_RELEASED);
|
||||||
|
|
||||||
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
ClutterActor *actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface));
|
||||||
|
MetaWindowActor *window_actor = meta_window_actor_from_actor (actor);
|
||||||
|
g_signal_connect (window_actor, "destroy",
|
||||||
|
G_CALLBACK (on_window_actor_destroyed),
|
||||||
|
test_driver);
|
||||||
|
}
|
||||||
|
else if (sequence == 1)
|
||||||
|
{
|
||||||
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
||||||
|
ClutterActor *actor = CLUTTER_ACTOR (meta_wayland_surface_get_actor (surface));
|
||||||
|
MetaWindowActor *window_actor = meta_window_actor_from_actor (actor);
|
||||||
|
MetaWindow *window = meta_window_actor_get_meta_window (window_actor);
|
||||||
|
MetaRectangle buffer_rect;
|
||||||
|
|
||||||
|
/* Click inside the window to allow mapping a popup. */
|
||||||
|
|
||||||
|
meta_window_get_buffer_rect (window, &buffer_rect);
|
||||||
|
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
buffer_rect.x + 10,
|
||||||
|
buffer_rect.y + 10);
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_PRESSED);
|
||||||
|
clutter_virtual_input_device_notify_button (virtual_pointer,
|
||||||
|
CLUTTER_CURRENT_TIME,
|
||||||
|
CLUTTER_BUTTON_PRIMARY,
|
||||||
|
CLUTTER_BUTTON_STATE_RELEASED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
subsurface_parent_unmapped (void)
|
||||||
|
{
|
||||||
|
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||||
|
MetaDisplay *display = meta_context_get_display (test_context);
|
||||||
|
WaylandTestClient *wayland_test_client;
|
||||||
|
ClutterSeat *seat;
|
||||||
|
gulong window_added_id;
|
||||||
|
gulong sync_point_id;
|
||||||
|
|
||||||
|
seat = meta_backend_get_default_seat (backend);
|
||||||
|
virtual_pointer = clutter_seat_create_virtual_device (seat,
|
||||||
|
CLUTTER_POINTER_DEVICE);
|
||||||
|
|
||||||
|
wayland_test_client = wayland_test_client_new ("subsurface-parent-unmapped");
|
||||||
|
|
||||||
|
window_added_id =
|
||||||
|
g_signal_connect (display->stack, "window-added",
|
||||||
|
G_CALLBACK (on_window_added),
|
||||||
|
virtual_pointer);
|
||||||
|
sync_point_id =
|
||||||
|
g_signal_connect (test_driver, "sync-point",
|
||||||
|
G_CALLBACK (on_unmap_sync_point),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
wayland_test_client_finish (wayland_test_client);
|
||||||
|
|
||||||
|
g_clear_object (&virtual_pointer);
|
||||||
|
g_signal_handler_disconnect (test_driver, sync_point_id);
|
||||||
|
g_signal_handler_disconnect (display->stack, window_added_id);
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum _ApplyLimitState
|
typedef enum _ApplyLimitState
|
||||||
{
|
{
|
||||||
APPLY_LIMIT_STATE_INIT,
|
APPLY_LIMIT_STATE_INIT,
|
||||||
@ -306,6 +489,8 @@ init_wayland_tests (void)
|
|||||||
subsurface_invalid_subsurfaces);
|
subsurface_invalid_subsurfaces);
|
||||||
g_test_add_func ("/wayland/subsurface/invalid-xdg-shell-actions",
|
g_test_add_func ("/wayland/subsurface/invalid-xdg-shell-actions",
|
||||||
subsurface_invalid_xdg_shell_actions);
|
subsurface_invalid_xdg_shell_actions);
|
||||||
|
g_test_add_func ("/wayland/subsurface/parent-unmapped",
|
||||||
|
subsurface_parent_unmapped);
|
||||||
g_test_add_func ("/wayland/toplevel/apply-limits",
|
g_test_add_func ("/wayland/toplevel/apply-limits",
|
||||||
toplevel_apply_limits);
|
toplevel_apply_limits);
|
||||||
g_test_add_func ("/wayland/toplevel/activation",
|
g_test_add_func ("/wayland/toplevel/activation",
|
||||||
|
@ -348,6 +348,7 @@ gboolean meta_wayland_surface_is_shortcuts_inhibited (MetaWaylandSurf
|
|||||||
|
|
||||||
CoglTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface);
|
CoglTexture * meta_wayland_surface_get_texture (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
|
META_EXPORT_TEST
|
||||||
MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface);
|
MetaSurfaceActor * meta_wayland_surface_get_actor (MetaWaylandSurface *surface);
|
||||||
|
|
||||||
void meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface);
|
void meta_wayland_surface_notify_geometry_changed (MetaWaylandSurface *surface);
|
||||||
|
Loading…
Reference in New Issue
Block a user