This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch wl/real-browser
in repository enlightenment.
View the commit online.
commit fac134f984bdbeb32c6f3cca21207ff23787066d
Author: Cedric BAIL <[email protected]>
AuthorDate: Sun Aug 16 21:54:37 2026 -0600
wl_test - hand out compositor-assigned window names
Every request in this protocol so far names a surface by passing a wl_surface
object, and object references are per-connection. That is fine for a test that
is also the client. It is exactly nothing for a test whose job is to drive a
browser: the harness starts the program, it does not own its wl_display, and
there is no way to say which window it means. The wlcs shim only gets around
this by binding wl_test on the client's own display, which it can because it
opened that connection itself.
So the compositor hands out its own names. get_clients answers with a
client_info per window and then clients_done; the id in it is what everything
else in v4 will take in place of an object.
Enumeration rather than subscription alone, and deliberately: with it there is
no ordering requirement between a driver connecting and the program under test
mapping a window. That removes the whole class of "the driver missed the add
event" flake before it can exist. clients_done is what separates "that is all
of them" from "none yet" - the difference between a test that waits and a test
that hangs.
Ids are assigned lazily rather than from a client-add hook, because the module
can be force-loaded after windows already exist, and lazily assigned is stable
from first mention onwards, which is all a caller can observe. Never reused;
0 means "no window", so numbering starts at 1 and a parentless toplevel says
parent=0 without ambiguity.
Two details worth stating rather than discovering:
* VISIBLE comes from the frame object, not ec->visible. They disagree, and
when they do the frame is the one telling the truth - an internal window
whose canvas failed to be created keeps ec->visible set with nothing on
screen, which is what made a phantom window look like a compositing bug in
8c3c361b3. What a test wants to know is whether anything is painted.
* title and app_id are empty strings, never null. The wire cannot carry a
null string anyway, and a caller comparing app_ids should not have to
guard first.
app_id is ec->icccm.class: xdg_toplevel.set_app_id puts it there (xdg.c).
test_client_list.c maps a toplevel the protocol-correct way, then finds it
again by app_id without once mentioning the wl_surface - which is exactly the
shape a browser test has to take. Watched it fail first with "invalid version
for global wl_test: expected at most 3, got 4", which is the right reason.
Also fixes a truncation warning in the staging path added by 9390f074b:
truncating there would stage the module where E does not look, which comes
back as a compositor that answers nothing.
Suite: wl-globals, all eight protocol tests and e_wlcs_driver pass.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
---
src/modules/wl_test/e_mod_main.c | 96 +++++++++-
src/modules/wl_test/wl-test.xml | 81 +++++++-
src/tests/wayland/meson.build | 1 +
src/tests/wayland/test_client_list.c | 358 +++++++++++++++++++++++++++++++++++
src/tests/wlcs/e_wlcs.c | 11 +-
5 files changed, 543 insertions(+), 4 deletions(-)
diff --git a/src/modules/wl_test/e_mod_main.c b/src/modules/wl_test/e_mod_main.c
index d0212122d..821adec3d 100644
--- a/src/modules/wl_test/e_mod_main.c
+++ b/src/modules/wl_test/e_mod_main.c
@@ -18,6 +18,15 @@ static struct wl_listener _client_created_listener;
static Eina_Hash *_client_serials = NULL; /* wl_client* -> serial */
static unsigned int _next_serial = 0;
+/* Compositor-assigned window names, so a caller can talk about a window
+ * belonging to a connection it does not own. Assigned lazily rather than from
+ * a client-add hook: the module can be force-loaded after windows already
+ * exist, and a lazily assigned id is stable from its first mention onwards,
+ * which is all anyone can observe. Never reused - 0 means "no window", so
+ * numbering starts at 1. */
+static Eina_Hash *_client_ids = NULL; /* E_Client* -> id */
+static unsigned int _next_client_id = 0;
+
/* Pending sync requests, drained from an ecore job so that one main loop
* iteration has run before sync_done goes out. */
static Eina_List *_pending_syncs = NULL;
@@ -54,6 +63,87 @@ _wl_test_ec_get(struct wl_resource *surface)
return ec;
}
+static unsigned int
+_wl_test_client_id(E_Client *ec)
+{
+ unsigned int id;
+
+ if (!ec) return 0;
+ id = (unsigned int)(uintptr_t)eina_hash_find(_client_ids, &ec);
+ if (id) return id;
+
+ id = ++_next_client_id;
+ eina_hash_add(_client_ids, &ec, (void *)(uintptr_t)id);
+ return id;
+}
+
+static unsigned int
+_wl_test_client_states(E_Client *ec)
+{
+ unsigned int states = 0;
+
+ if (ec->focused) states |= WL_TEST_CLIENT_STATE_FOCUSED;
+ /* The frame object, not ec->visible. They disagree, and when they do the
+ * frame is the one telling the truth: an internal window whose canvas
+ * failed to be created is left with ec->visible set and nothing on screen,
+ * which is how a phantom window came to look like a compositing bug for a
+ * while. What a test wants to know is whether anything is being painted. */
+ if (ec->frame && evas_object_visible_get(ec->frame))
+ states |= WL_TEST_CLIENT_STATE_VISIBLE;
+ if (ec->iconic) states |= WL_TEST_CLIENT_STATE_ICONIFIED;
+ if (ec->maximized & E_MAXIMIZE_HORIZONTAL)
+ states |= WL_TEST_CLIENT_STATE_MAXIMIZED_H;
+ if (ec->maximized & E_MAXIMIZE_VERTICAL)
+ states |= WL_TEST_CLIENT_STATE_MAXIMIZED_V;
+ if (ec->fullscreen) states |= WL_TEST_CLIENT_STATE_FULLSCREEN;
+ if (ec->sticky) states |= WL_TEST_CLIENT_STATE_STICKY;
+ if (ec->shaded) states |= WL_TEST_CLIENT_STATE_SHADED;
+ if (ec->internal) states |= WL_TEST_CLIENT_STATE_INTERNAL;
+
+ return states;
+}
+
+static void
+_wl_test_send_client_info(struct wl_resource *resource, E_Client *ec)
+{
+ unsigned int output = 0;
+ Eina_List *l;
+ E_Zone *zone;
+ int i = 0;
+
+ EINA_LIST_FOREACH(e_comp->zones, l, zone)
+ {
+ if (zone == ec->zone) { output = i; break; }
+ i++;
+ }
+
+ /* Empty strings rather than null: the wire cannot carry a null string
+ * anyway, and a caller comparing app_ids should not have to guard first. */
+ wl_test_send_client_info(resource,
+ _wl_test_client_id(ec),
+ ec->netwm.pid,
+ ec->icccm.title ?: "",
+ ec->icccm.class ?: "",
+ _wl_test_client_id(ec->parent),
+ ec->x, ec->y, ec->w, ec->h,
+ _wl_test_client_states(ec),
+ output);
+}
+
+static void
+_wl_test_cb_get_clients(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
+{
+ E_Client *ec;
+
+ E_CLIENT_FOREACH(ec)
+ {
+ if (e_object_is_del(E_OBJECT(ec))) continue;
+ _wl_test_send_client_info(resource, ec);
+ }
+
+ wl_test_send_clients_done(resource);
+}
+
static void
_wl_test_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
{
@@ -368,6 +458,8 @@ static const struct wl_test_interface _wl_test_implementation =
/* version 3, appended in the order the protocol declares them */
_wl_test_cb_get_surface_buffer_info,
_wl_test_cb_output_scale_set,
+ /* version 4 */
+ _wl_test_cb_get_clients,
};
static void
@@ -402,12 +494,13 @@ e_modapi_init(E_Module *m)
}
_client_serials = eina_hash_pointer_new(NULL);
+ _client_ids = eina_hash_pointer_new(NULL);
_client_created_listener.notify = _wl_test_cb_client_created;
wl_display_add_client_created_listener(e_comp_wl->wl.disp,
&_client_created_listener);
- _wl_test_global = wl_global_create(e_comp_wl->wl.disp, &wl_test_interface, 3,
+ _wl_test_global = wl_global_create(e_comp_wl->wl.disp, &wl_test_interface, 4,
NULL, _wl_test_cb_bind);
if (!_wl_test_global)
{
@@ -439,6 +532,7 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
wl_list_remove(&_client_created_listener.link);
E_FREE_FUNC(_client_serials, eina_hash_free);
+ E_FREE_FUNC(_client_ids, eina_hash_free);
return 1;
}
diff --git a/src/modules/wl_test/wl-test.xml b/src/modules/wl_test/wl-test.xml
index 1b0fab907..1b5c6244c 100644
--- a/src/modules/wl_test/wl-test.xml
+++ b/src/modules/wl_test/wl-test.xml
@@ -23,7 +23,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="wl_test" version="3">
+ <interface name="wl_test" version="4">
<description summary="private interface for the compositor test suite">
A back door into the compositor for its own test suite. It exposes
internal state and synthesises input, so it is deliberately NOT built
@@ -270,5 +270,84 @@
<arg name="index" type="uint" summary="0-based, in wl_output creation order"/>
<arg name="scale" type="int"/>
</request>
+
+ <!-- Version 4: naming a window you do not own.
+
+ Everything above addresses a surface by passing a wl_surface object.
+ Object references are per-connection, so that only ever works for a
+ surface belonging to the client that sends the request. The wlcs shim
+ gets around it by binding wl_test on the *client's* display, which it
+ can because it opened that connection itself (e_wlcs.c,
+ _server_position_window_absolute).
+
+ Nothing owns a browser's connection. To ask anything at all about a
+ window belonging to a program the harness merely started, the
+ compositor has to hand out its own names for windows, and take them
+ back in place of an object. That is what the ids below are. -->
+
+ <enum name="client_state" bitfield="true" since="4">
+ <description summary="what the compositor believes about a window">
+ Every bit is a field E already keeps on an E_Client, reported rather
+ than derived, so a test asserts E's own view and not a restatement of
+ it.
+ </description>
+ <entry name="focused" value="0x001"/>
+ <entry name="visible" value="0x002"/>
+ <entry name="iconified" value="0x004"/>
+ <entry name="maximized_h" value="0x008"/>
+ <entry name="maximized_v" value="0x010"/>
+ <entry name="fullscreen" value="0x020"/>
+ <entry name="sticky" value="0x040"/>
+ <entry name="shaded" value="0x080"/>
+ <entry name="internal" value="0x100" summary="one of E's own windows"/>
+ </enum>
+
+ <request name="get_clients" since="4">
+ <description summary="enumerate every window the compositor knows about">
+ Answered with a client_info per window, then clients_done.
+
+ Enumeration rather than subscription alone, and deliberately so: with
+ it there is no ordering requirement between a test connecting and the
+ program it is testing mapping a window, which removes the whole class
+ of "the driver missed the event" flake before it can exist.
+ </description>
+ </request>
+
+ <event name="client_info" since="4">
+ <description summary="the compositor's own view of one window">
+ Geometry is the frame in compositor coordinates - what E would use to
+ paint it - matching surface_info rather than what the client asked
+ for.
+
+ The id is assigned by the compositor, is stable for the life of the
+ window, and is never reused. title and app_id are empty strings rather
+ than null when the client has not set them, so a caller never has to
+ test for null before comparing.
+
+ pid comes from wl_client_get_credentials, so it is the process that
+ opened the connection. For anything that re-execs or hands off to a
+ zygote - which is every browser - that is not necessarily the process
+ the harness started, so match on app_id and treat pid as a
+ cross-check.
+ </description>
+ <arg name="id" type="uint"/>
+ <arg name="pid" type="int"/>
+ <arg name="title" type="string"/>
+ <arg name="app_id" type="string"/>
+ <arg name="parent" type="uint" summary="id of the parent window, or 0"/>
+ <arg name="x" type="int"/>
+ <arg name="y" type="int"/>
+ <arg name="w" type="int"/>
+ <arg name="h" type="int"/>
+ <arg name="states" type="uint" enum="client_state"/>
+ <arg name="output" type="uint" summary="0-based zone index"/>
+ </event>
+
+ <event name="clients_done" since="4">
+ <description summary="end of a get_clients reply">
+ What separates the enumeration from anything watch_clients sends
+ afterwards on the same connection.
+ </description>
+ </event>
</interface>
</protocol>
diff --git a/src/tests/wayland/meson.build b/src/tests/wayland/meson.build
index 8befa0ff1..d4c7d5172 100644
--- a/src/tests/wayland/meson.build
+++ b/src/tests/wayland/meson.build
@@ -60,6 +60,7 @@ wl_protocol_tests = [
['output', 'test_output.c'],
['activation', 'test_activation.c'],
['buffer-scale', 'test_buffer_scale.c'],
+ ['client-list', 'test_client_list.c'],
]
foreach t: wl_protocol_tests
diff --git a/src/tests/wayland/test_client_list.c b/src/tests/wayland/test_client_list.c
new file mode 100644
index 000000000..ce7ee6b17
--- /dev/null
+++ b/src/tests/wayland/test_client_list.c
@@ -0,0 +1,358 @@
+/* wl_test.get_clients - naming a window the caller does not own.
+ *
+ * Everything else in this protocol addresses a surface by handing over a
+ * wl_surface object, which only works for a surface on the sending
+ * connection. That is enough for a test that is also the client, and it is
+ * exactly nothing for a test whose job is to drive a browser: the harness
+ * starts the program, it does not own its wl_display, and there is no way to
+ * name one of its windows.
+ *
+ * So the compositor hands out its own ids. This asserts the two properties
+ * that make them worth having:
+ *
+ * - the enumeration finds a window this test mapped, and reports the title,
+ * app_id and frame geometry the compositor actually holds for it;
+ * - clients_done arrives, so a caller can tell "that is all of them" from
+ * "none yet", which is the difference between a test that waits and a
+ * test that hangs.
+ *
+ * The window is our own only because an in-tree test has nothing else to map.
+ * Nothing here goes through the wl_surface object: the test finds its own
+ * window by app_id, exactly as a browser test will.
+ */
+/* memfd_create is behind __USE_GNU in <sys/mman.h>. */
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <wayland-client.h>
+#include "wl-test-client-protocol.h"
+#include "xdg-shell-client-protocol.h"
+
+#define FAIL(fmt, ...) \
+ do { fprintf(stderr, "test-client-list: " fmt "\n", ##__VA_ARGS__); return 1; } while (0)
+
+#define APP_ID "e.test.client_list"
+#define TITLE "client list under test"
+#define W 320
+#define H 240
+
+typedef struct
+{
+ unsigned int id;
+ int pid;
+ char title[256];
+ char app_id[256];
+ unsigned int parent;
+ int x, y, w, h;
+ unsigned int states;
+ unsigned int output;
+} Info;
+
+typedef struct
+{
+ struct wl_compositor *compositor;
+ struct wl_shm *shm;
+ struct xdg_wm_base *wm_base;
+ struct wl_test *tester;
+ uint32_t tester_version;
+
+ Info infos[64];
+ int info_count;
+ int done_count;
+
+ int configured;
+} Ctx;
+
+static Ctx ctx;
+
+/* ------------------------------------------------------------- wl_test */
+
+static void
+_client_serial(void *data, struct wl_test *t, uint32_t serial)
+{
+ (void)data; (void)t; (void)serial;
+}
+
+static void
+_surface_info(void *data, struct wl_test *t, struct wl_surface *s,
+ int32_t x, int32_t y, int32_t w, int32_t h,
+ uint32_t vis, uint32_t foc)
+{
+ (void)data; (void)t; (void)s; (void)x; (void)y; (void)w; (void)h;
+ (void)vis; (void)foc;
+}
+
+static void
+_surface_unknown(void *data, struct wl_test *t, struct wl_surface *s)
+{
+ (void)data; (void)t; (void)s;
+}
+
+static void
+_sync_done(void *data, struct wl_test *t)
+{
+ (void)data; (void)t;
+}
+
+static void
+_surface_buffer_info(void *data, struct wl_test *t, struct wl_surface *s,
+ int32_t scale, int32_t transform, int32_t oscale)
+{
+ (void)data; (void)t; (void)s; (void)scale; (void)transform; (void)oscale;
+}
+
+static void
+_client_info(void *data, struct wl_test *t, uint32_t id, int32_t pid,
+ const char *title, const char *app_id, uint32_t parent,
+ int32_t x, int32_t y, int32_t w, int32_t h,
+ uint32_t states, uint32_t output)
+{
+ Ctx *c = data;
+ Info *i;
+
+ (void)t;
+ if (c->info_count >= (int)(sizeof(c->infos) / sizeof(c->infos[0]))) return;
+
+ i = &c->infos[c->info_count++];
+ i->id = id;
+ i->pid = pid;
+ snprintf(i->title, sizeof(i->title), "%s", title ?: "");
+ snprintf(i->app_id, sizeof(i->app_id), "%s", app_id ?: "");
+ i->parent = parent;
+ i->x = x; i->y = y; i->w = w; i->h = h;
+ i->states = states;
+ i->output = output;
+}
+
+static void
+_clients_done(void *data, struct wl_test *t)
+{
+ Ctx *c = data;
+
+ (void)t;
+ c->done_count++;
+}
+
+static const struct wl_test_listener _test_listener =
+{
+ _client_serial,
+ _surface_info,
+ _surface_unknown,
+ _sync_done,
+ _surface_buffer_info,
+ _client_info,
+ _clients_done,
+};
+
+/* ------------------------------------------------------------- xdg-shell */
+
+static void
+_wm_base_ping(void *data, struct xdg_wm_base *b, uint32_t serial)
+{
+ (void)data;
+ xdg_wm_base_pong(b, serial);
+}
+
+static const struct xdg_wm_base_listener _wm_base_listener = { _wm_base_ping };
+
+static void
+_xdg_surface_configure(void *data, struct xdg_surface *s, uint32_t serial)
+{
+ Ctx *c = data;
+
+ xdg_surface_ack_configure(s, serial);
+ c->configured++;
+}
+
+static const struct xdg_surface_listener _xdg_surface_listener =
+{
+ _xdg_surface_configure
+};
+
+static void
+_toplevel_configure(void *data, struct xdg_toplevel *t, int32_t w, int32_t h,
+ struct wl_array *states)
+{
+ (void)data; (void)t; (void)w; (void)h; (void)states;
+}
+
+static void
+_toplevel_close(void *data, struct xdg_toplevel *t)
+{
+ (void)data; (void)t;
+}
+
+static const struct xdg_toplevel_listener _toplevel_listener =
+{
+ _toplevel_configure,
+ _toplevel_close
+};
+
+/* ------------------------------------------------------------- registry */
+
+static void
+_global_add(void *data, struct wl_registry *reg, uint32_t id,
+ const char *iface, uint32_t version)
+{
+ Ctx *c = data;
+
+ if (!strcmp(iface, "wl_compositor"))
+ c->compositor = wl_registry_bind(reg, id, &wl_compositor_interface,
+ version < 4 ? version : 4);
+ else if (!strcmp(iface, "wl_shm"))
+ c->shm = wl_registry_bind(reg, id, &wl_shm_interface, 1);
+ else if (!strcmp(iface, "xdg_wm_base"))
+ c->wm_base = wl_registry_bind(reg, id, &xdg_wm_base_interface, 1);
+ else if (!strcmp(iface, "wl_test"))
+ {
+ c->tester_version = version;
+ /* Deliberately the version this test needs, not whatever is on
+ * offer: binding lower would make a missing request look like a
+ * silent no-op instead of a failure to start. */
+ c->tester = wl_registry_bind(reg, id, &wl_test_interface, 4);
+ }
+}
+
+static void
+_global_remove(void *data, struct wl_registry *reg, uint32_t id)
+{
+ (void)data; (void)reg; (void)id;
+}
+
+static const struct wl_registry_listener _registry_listener =
+{
+ _global_add, _global_remove
+};
+
+/* ------------------------------------------------------------- buffer */
+
+static struct wl_buffer *
+_buffer_make(Ctx *c, int w, int h)
+{
+ struct wl_shm_pool *pool;
+ struct wl_buffer *buf;
+ int stride = w * 4, size = stride * h, fd;
+ void *map;
+
+ fd = memfd_create("e-test-client-list", MFD_CLOEXEC);
+ if (fd < 0) return NULL;
+ if (ftruncate(fd, size) < 0) { close(fd); return NULL; }
+
+ map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED) { close(fd); return NULL; }
+ memset(map, 0xff, size);
+ munmap(map, size);
+
+ pool = wl_shm_create_pool(c->shm, fd, size);
+ buf = wl_shm_pool_create_buffer(pool, 0, w, h, stride,
+ WL_SHM_FORMAT_ARGB8888);
+ wl_shm_pool_destroy(pool);
+ close(fd);
+ return buf;
+}
+
+/* ------------------------------------------------------------- the test */
+
+int
+main(void)
+{
+ struct wl_display *disp;
+ struct wl_registry *registry;
+ struct wl_surface *surface;
+ struct xdg_surface *xdg_surface;
+ struct xdg_toplevel *toplevel;
+ struct wl_buffer *buffer;
+ Info *mine = NULL;
+ int i;
+
+ disp = wl_display_connect(NULL);
+ if (!disp) FAIL("cannot connect to WAYLAND_DISPLAY");
+
+ registry = wl_display_get_registry(disp);
+ wl_registry_add_listener(registry, &_registry_listener, &ctx);
+ wl_display_roundtrip(disp);
+
+ if (!ctx.compositor) FAIL("no wl_compositor");
+ if (!ctx.shm) FAIL("no wl_shm");
+ if (!ctx.wm_base) FAIL("no xdg_wm_base");
+ if (!ctx.tester)
+ FAIL("no wl_test at version 4 (advertised %u)", ctx.tester_version);
+
+ wl_test_add_listener(ctx.tester, &_test_listener, &ctx);
+ xdg_wm_base_add_listener(ctx.wm_base, &_wm_base_listener, &ctx);
+
+ /* Map a toplevel the protocol-correct way: role, empty commit, wait for
+ * the configure, then attach. */
+ surface = wl_compositor_create_surface(ctx.compositor);
+ xdg_surface = xdg_wm_base_get_xdg_surface(ctx.wm_base, surface);
+ xdg_surface_add_listener(xdg_surface, &_xdg_surface_listener, &ctx);
+ toplevel = xdg_surface_get_toplevel(xdg_surface);
+ xdg_toplevel_add_listener(toplevel, &_toplevel_listener, &ctx);
+ xdg_toplevel_set_title(toplevel, TITLE);
+ xdg_toplevel_set_app_id(toplevel, APP_ID);
+ wl_surface_commit(surface);
+
+ while (!ctx.configured)
+ if (wl_display_dispatch(disp) < 0) FAIL("disconnected waiting for configure");
+
+ buffer = _buffer_make(&ctx, W, H);
+ if (!buffer) FAIL("cannot make a buffer");
+ wl_surface_attach(surface, buffer, 0, 0);
+ wl_surface_damage(surface, 0, 0, W, H);
+ wl_surface_commit(surface);
+
+ /* wl_test.sync, not wl_display.sync: the map lands from a job. */
+ wl_test_sync(ctx.tester);
+ wl_display_roundtrip(disp);
+
+ wl_test_get_clients(ctx.tester);
+ wl_display_roundtrip(disp);
+
+ if (ctx.done_count != 1)
+ FAIL("expected exactly one clients_done, got %d", ctx.done_count);
+ if (ctx.info_count < 1)
+ FAIL("get_clients reported no windows at all");
+
+ for (i = 0; i < ctx.info_count; i++)
+ if (!strcmp(ctx.infos[i].app_id, APP_ID)) { mine = &ctx.infos[i]; break; }
+
+ if (!mine)
+ {
+ fprintf(stderr, "test-client-list: %d window(s), none with app_id '%s':\n",
+ ctx.info_count, APP_ID);
+ for (i = 0; i < ctx.info_count; i++)
+ fprintf(stderr, " id=%u pid=%d app_id='%s' title='%s' %dx%d+%d+%d\n",
+ ctx.infos[i].id, ctx.infos[i].pid, ctx.infos[i].app_id,
+ ctx.infos[i].title, ctx.infos[i].w, ctx.infos[i].h,
+ ctx.infos[i].x, ctx.infos[i].y);
+ return 1;
+ }
+
+ if (mine->id == 0)
+ FAIL("id 0 is reserved for 'no window', so no window may have it");
+ if (strcmp(mine->title, TITLE))
+ FAIL("title is '%s', expected '%s'", mine->title, TITLE);
+ if (mine->pid != (int)getpid())
+ FAIL("pid is %d, expected %d", mine->pid, (int)getpid());
+ if ((mine->w != W) || (mine->h != H))
+ FAIL("frame is %dx%d, expected %dx%d", mine->w, mine->h, W, H);
+ if (!(mine->states & WL_TEST_CLIENT_STATE_VISIBLE))
+ FAIL("a mapped window with a buffer is not reported visible (states=0x%x)",
+ mine->states);
+ if (mine->parent != 0)
+ FAIL("a toplevel with no parent reports parent=%u", mine->parent);
+
+ printf("test-client-list: ok (%d window(s), mine id=%u %dx%d+%d+%d states=0x%x)\n",
+ ctx.info_count, mine->id, mine->w, mine->h, mine->x, mine->y,
+ mine->states);
+
+ xdg_toplevel_destroy(toplevel);
+ xdg_surface_destroy(xdg_surface);
+ wl_surface_destroy(surface);
+ wl_buffer_destroy(buffer);
+ wl_display_disconnect(disp);
+ return 0;
+}
diff --git a/src/tests/wlcs/e_wlcs.c b/src/tests/wlcs/e_wlcs.c
index ea9286f08..4eaa613f9 100644
--- a/src/tests/wlcs/e_wlcs.c
+++ b/src/tests/wlcs/e_wlcs.c
@@ -233,8 +233,15 @@ _stage_test_module(const char *home, char *e_home, size_t e_home_size)
}
snprintf(e_home, e_home_size, "%s/.e", home);
- snprintf(dir, sizeof(dir), "%s/e/modules/wl_test/%s",
- e_home, E_WLCS_TEST_MODULE_ARCH);
+ /* Truncating here would silently stage the module at a path E does not
+ * search, which comes back as a compositor that answers nothing. */
+ if (snprintf(dir, sizeof(dir), "%s/e/modules/wl_test/%s",
+ e_home, E_WLCS_TEST_MODULE_ARCH) >= (int)sizeof(dir))
+ {
+ fprintf(stderr, "e_wlcs: module staging path too long under %s\n",
+ e_home);
+ return -1;
+ }
/* mkdir -p, in place: walk the string turning each '/' into a NUL, make
* that prefix, put it back. */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.