Skip to content

Commit

Permalink
Mock server: add checks for popups and clicking actions (from GTK3 ve…
Browse files Browse the repository at this point in the history
…rsion)
  • Loading branch information
wmww committed Sep 2, 2024
1 parent 5e49dc9 commit 5a7b524
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 8 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ pacman -S --needed meson ninja gtk4 wayland gobject-introspection libgirepositor

### Running the Tests
* `ninja -C build test`
* Or, to run a specific test and print the complete output `meson test <testname> --verbose -C build`

## Licensing
100% MIT (unlike the GTK3 version of this library which contained GPL code copied from GTK)
72 changes: 64 additions & 8 deletions test/mock-server/overrides.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ typedef enum
SURFACE_ROLE_LAYER,
} SurfaceRole;

typedef struct
typedef struct SurfaceData SurfaceData;

struct SurfaceData
{
SurfaceRole role;
struct wl_resource* surface;
Expand All @@ -22,15 +24,19 @@ typedef struct
char has_committed_buffer; // This surface has a non-null committed buffer
char initial_commit_for_role; // Set to 1 when a role is created for a surface, and cleared after the first commit
char layer_send_configure; // If to send a layer surface configure on the next commit
char click_on_surface; // If to click on the surface next commit
int layer_set_w; // The width to configure the layer surface with
int layer_set_h; // The height to configure the layer surface with
uint32_t layer_anchor; // The layer surface's anchor
} SurfaceData;
uint32_t click_serial; // The most recent serial that was used to click on this surface
SurfaceData* most_recent_popup; // Start of the popup linked list
SurfaceData* previous_popup_sibling; // Forms a linked list of popups
SurfaceData* popup_parent;
};

static struct wl_resource* seat_global = NULL;
static struct wl_resource* pointer_global = NULL;
static struct wl_resource* output_global = NULL;
static uint32_t click_serial = 0;

// Needs to be called before any role objects are assigned
static void surface_data_set_role(SurfaceData* data, SurfaceRole role)
Expand All @@ -48,6 +54,26 @@ static void surface_data_set_role(SurfaceData* data, SurfaceRole role)
data->initial_commit_for_role = 1;
}

static void surface_data_unmap(SurfaceData* data) {
SurfaceData* popup = data->most_recent_popup;
while (popup) {
// Popups must be unmapped before their parents
ASSERT(!popup->surface);
ASSERT(!popup->layer_surface);
ASSERT(!popup->xdg_popup);
ASSERT(!popup->xdg_toplevel);
ASSERT(!popup->xdg_surface);
popup = popup->previous_popup_sibling;
}
}

static void surface_data_add_pupup(SurfaceData* parent, SurfaceData* popup) {
ASSERT(!popup->previous_popup_sibling);
popup->previous_popup_sibling = parent->most_recent_popup;
parent->most_recent_popup = popup;
popup->popup_parent = parent;
}

static void wl_surface_frame(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
NEW_ID_ARG(callback, 0);
Expand All @@ -65,24 +91,28 @@ static void wl_surface_attach(struct wl_resource *resource, const struct wl_mess
RESOURCE_ARG(wl_buffer, buffer, 0);
SurfaceData* data = wl_resource_get_user_data(resource);
data->has_pending_buffer = (buffer != NULL);
data->click_on_surface = 1;
}

static void wl_surface_commit(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
SurfaceData* data = wl_resource_get_user_data(resource);
data->has_committed_buffer = data->has_pending_buffer;

// leave the contents of has_pending_buffer alone
if (data->pending_frame)
{
wl_callback_send_done(data->pending_frame, 0);
wl_resource_destroy(data->pending_frame);
data->pending_frame = NULL;
}

if (data->initial_commit_for_role)
{
ASSERT(!data->has_committed_buffer);
data->initial_commit_for_role = 0;
}

if (data->layer_surface && data->layer_send_configure)
{
char horiz = (
Expand All @@ -103,22 +133,25 @@ static void wl_surface_commit(struct wl_resource *resource, const struct wl_mess
height = DEFAULT_OUTPUT_HEIGHT;
zwlr_layer_surface_v1_send_configure(data->layer_surface, wl_display_next_serial(display), width, height);
data->layer_send_configure = 0;
}

if (data->click_on_surface) {
// Move the pointer onto the surface and click
// This is needed to trigger a tooltip or popup menu to open for the popup tests
ASSERT(pointer_global);
wl_pointer_send_enter(
pointer_global,
wl_display_next_serial(display),
data->surface,
wl_fixed_from_double(5.0), wl_fixed_from_double(5.0));
wl_fixed_from_double(50), wl_fixed_from_double(50));
wl_pointer_send_frame(pointer_global);
click_serial = wl_display_next_serial(display);
data->click_serial = wl_display_next_serial(display);
wl_pointer_send_button(
pointer_global,
click_serial, 0,
data->click_serial, 0,
BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
wl_pointer_send_frame(pointer_global);
data->click_on_surface = 0;
}
}

Expand All @@ -129,7 +162,9 @@ static void wl_surface_destroy(struct wl_resource* resource, const struct wl_mes
ASSERT(!data->xdg_toplevel);
ASSERT(!data->xdg_surface);
ASSERT(!data->layer_surface);
free(data);
data->surface = NULL;
// Don't free surfaces to guarantee traversing popups is always safe
// We're employing the missile memory management pattern here https://x.com/pomeranian99/status/858856994438094848
}

static void wl_compositor_create_surface(struct wl_resource* resource, const struct wl_message* message, union wl_argument* args)
Expand Down Expand Up @@ -222,11 +257,13 @@ static void xdg_toplevel_destroy(struct wl_resource *resource, const struct wl_m
SurfaceData* data = wl_resource_get_user_data(resource);
ASSERT(data->xdg_surface);
data->xdg_toplevel = NULL;
surface_data_unmap(data);
}

static void xdg_surface_get_popup(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
NEW_ID_ARG(id, 0);
RESOURCE_ARG(xdg_surface, parent, 1);
struct wl_resource* popup = wl_resource_create(
wl_resource_get_client(resource),
&xdg_popup_interface,
Expand All @@ -239,21 +276,29 @@ static void xdg_surface_get_popup(struct wl_resource *resource, const struct wl_
surface_data_set_role(data, SURFACE_ROLE_XDG_POPUP);
wl_resource_set_user_data(popup, data);
data->xdg_popup = popup;
if (parent) {
SurfaceData* parent_data = wl_resource_get_user_data(parent);
surface_data_add_pupup(parent_data, data);
}
}

static void xdg_popup_grab(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
SurfaceData* data = wl_resource_get_user_data(resource);
RESOURCE_ARG(wl_seat, seat, 0);
UINT_ARG(serial, 1);
ASSERT_EQ(seat, seat_global, "%p");
ASSERT_EQ(serial, click_serial, "%u");
ASSERT(data->popup_parent);
ASSERT(data->popup_parent->click_serial);
ASSERT_EQ(serial, data->popup_parent->click_serial, "%u");
}

static void xdg_popup_destroy(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
SurfaceData* data = wl_resource_get_user_data(resource);
ASSERT(data->xdg_surface);
data->xdg_popup = NULL;
surface_data_unmap(data);
}

static void zwlr_layer_surface_v1_set_anchor(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
Expand All @@ -274,6 +319,15 @@ static void zwlr_layer_surface_v1_set_size(struct wl_resource *resource, const s
data->layer_set_h = height;
}

static void zwlr_layer_surface_v1_get_popup(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
RESOURCE_ARG(xdg_popup, popup, 0);
SurfaceData* data = wl_resource_get_user_data(resource);
SurfaceData* popup_data = wl_resource_get_user_data(popup);
ASSERT(!popup_data->popup_parent);
surface_data_add_pupup(data, popup_data);
}

static void zwlr_layer_shell_v1_get_layer_surface(struct wl_resource *resource, const struct wl_message* message, union wl_argument* args)
{
NEW_ID_ARG(id, 0);
Expand All @@ -295,6 +349,7 @@ static void zwlr_layer_surface_v1_destroy(struct wl_resource *resource, const st
{
SurfaceData* data = wl_resource_get_user_data(resource);
data->layer_surface = NULL;
surface_data_unmap(data);
}

void init()
Expand All @@ -315,6 +370,7 @@ void init()
OVERRIDE_REQUEST(zwlr_layer_shell_v1, get_layer_surface);
OVERRIDE_REQUEST(zwlr_layer_surface_v1, set_anchor);
OVERRIDE_REQUEST(zwlr_layer_surface_v1, set_size);
OVERRIDE_REQUEST(zwlr_layer_surface_v1, get_popup);
OVERRIDE_REQUEST(zwlr_layer_surface_v1, destroy);

wl_global_create(display, &wl_seat_interface, 6, NULL, wl_seat_bind);
Expand Down

0 comments on commit 5a7b524

Please sign in to comment.