This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch wl/browser-all
in repository enlightenment.

View the commit online.

commit 187ec44f72beca6388eb2474f921a1217590ee18
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     |  93 +++++++++
 src/modules/wl_test/wl-test.xml      |  79 ++++++++
 src/tests/wayland/meson.build        |   1 +
 src/tests/wayland/test_client_list.c | 367 +++++++++++++++++++++++++++++++++++
 src/tests/wlcs/e_wlcs.c              |  11 +-
 5 files changed, 549 insertions(+), 2 deletions(-)

diff --git a/src/modules/wl_test/e_mod_main.c b/src/modules/wl_test/e_mod_main.c
index 4389086b6..5b4a60096 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)
 {
@@ -394,6 +484,7 @@ static const struct wl_test_interface _wl_test_implementation =
    /* version 4 */
    _wl_test_cb_get_idle_inhibit,
    _wl_test_cb_screensaver_enable,
+   _wl_test_cb_get_clients,
 };
 
 static void
@@ -428,6 +519,7 @@ 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,
@@ -465,6 +557,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 5eae6d896..5acabbf08 100644
--- a/src/modules/wl_test/wl-test.xml
+++ b/src/modules/wl_test/wl-test.xml
@@ -308,5 +308,84 @@
       <description summary="reply to get_idle_inhibit"/>
       <arg name="inhibited" type="uint" summary="nonzero if the screen will not blank"/>
     </event>
+
+    <!-- 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 ee787799b..b50dbe257 100644
--- a/src/tests/wayland/meson.build
+++ b/src/tests/wayland/meson.build
@@ -67,6 +67,7 @@ wl_protocol_tests = [
   ['fractional-scale', 'test_fractional_scale.c'],
   ['idle-inhibit', 'test_idle_inhibit.c'],
   ['shortcuts-inhibit', 'test_shortcuts_inhibit.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..ba26c8908
--- /dev/null
+++ b/src/tests/wayland/test_client_list.c
@@ -0,0 +1,367 @@
+/* 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
+_idle_inhibit(void *data, struct wl_test *t, uint32_t inhibited)
+{
+   (void)data; (void)t; (void)inhibited;
+}
+
+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,
+   /* idle_inhibit is not this test's business, but the slots are positional:
+    * a stub keeps _client_info on the opcode the protocol gives it. */
+   _idle_inhibit,
+   _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.

Reply via email to