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 ddaa2e0d8b82ad957a67866c9f295824d6dddb00
Author: Cedric BAIL <[email protected]>
AuthorDate: Tue Aug 18 18:15:56 2026 -0600

    wl_test - put input in as an ecore event, not straight into evas
    
    The harness fed evas directly. That reaches everything a Wayland client
    sees, because E's wl_pointer and wl_touch handlers are evas callbacks on
    the client's frame object - and it silently misses everything E does on
    the ecore half of the same event.
    
    That half is not small. Relative pointer motion, pointer constraints, the
    screensaver's idle timer, xdg_popup grab dismissal and drag-and-drop all
    hang off ECORE_EVENT_MOUSE_* handlers, and none of them ever saw a
    synthesised event. Five features have hit it one at a time, and each was
    patched by having the harness call, by hand, whatever the ecore handler
    would have called next. That works until the sixth, and it leaves the
    harness carrying its own copy of E's input routing, free to drift from
    the real one without a single test noticing.
    
    So post the event and let E's own handlers run.
    
    The canvas feed then has to move into a handler too, and that is the part
    worth reading twice. ecore_event_add queues; it does not dispatch. "Post
    the event, then feed evas" would therefore run the two in the wrong
    order, and the order is load-bearing in at least two places E already
    documents: a pointer constraint that swallows a motion must stop the
    canvas being told the pointer went where the client asked, and a click
    that dismisses an xdg_popup grab must be seen before the evas feed moves
    focus to whatever is underneath. A real session gets that ordering for
    free because both halves are handlers on the same event - E's are
    appended with E_LIST_HANDLER_APPEND_PRE and can answer
    ECORE_CALLBACK_CANCEL - so registering the canvas feed at ordinary
    priority puts the harness in exactly the position ecore_evas holds.
    
    window is e_comp->ee_win because that is what the compositor's own code
    compares against - e_dnd's _drag_win among others - and an event on any
    other window is skipped by exactly the handlers this exists to reach.
    
    The hand-written replications on branches downstream of this one become
    redundant and are removed where they merge.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
 src/modules/wl_test/e_mod_main.c | 156 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 148 insertions(+), 8 deletions(-)

diff --git a/src/modules/wl_test/e_mod_main.c b/src/modules/wl_test/e_mod_main.c
index b590f4158..3c6457d5b 100644
--- a/src/modules/wl_test/e_mod_main.c
+++ b/src/modules/wl_test/e_mod_main.c
@@ -124,13 +124,91 @@ _wl_test_cb_zone_add(struct wl_client *client EINA_UNUSED, struct wl_resource *r
      ERR("wl_test: could not create wl_output for zone %d", num);
 }
 
+/* Input goes in the way the backends put it in: as an ecore event.
+ *
+ * The obvious shortcut is to feed evas directly, and this harness did that for
+ * a long time. It works for anything that reads input through an evas callback
+ * on a client's frame object, which is most of what a Wayland client sees -
+ * and it silently misses everything E does on the *ecore* half of the same
+ * event. That half is not small: relative pointer motion, pointer constraints,
+ * the screensaver's idle timer, key bindings, and drag-and-drop all hang off
+ * ECORE_EVENT_MOUSE_* / ECORE_EVENT_KEY_* handlers and never saw a thing.
+ *
+ * Four features hit that gap one at a time - E-20, E-09, E-12, E-15 - and each
+ * was patched by having the harness call, by hand, whatever the ecore handler
+ * would have called. That works until the fifth, and it means the harness has
+ * its own growing copy of E's input routing which can drift from the real one
+ * without any test noticing. This is the fix the plan called overdue: post the
+ * event, and let E's own handlers run.
+ *
+ * `window` is e_comp->ee_win because that is what the compositor's own code
+ * compares against - e_dnd's _drag_win, for one - and an event on any other
+ * window is skipped by exactly the handlers this exists to reach.
+ */
+static unsigned int
+_input_timestamp(void)
+{
+   /* ecore timestamps are milliseconds and only ever compared with each
+    * other, so any monotonic source will do. */
+   return (unsigned int)(ecore_time_get() * 1000.0);
+}
+
+static void
+_pointer_ecore_move(int x, int y)
+{
+   Ecore_Event_Mouse_Move *ev;
+
+   ev = calloc(1, sizeof(*ev));
+   if (!ev) return;
+
+   ev->window = e_comp->ee_win;
+   ev->event_window = e_comp->ee_win;
+   ev->root_window = e_comp->ee_win;
+   ev->timestamp = _input_timestamp();
+   ev->same_screen = 1;
+   ev->x = ev->root.x = x;
+   ev->y = ev->root.y = y;
+   ev->multi.x = ev->multi.root.x = x;
+   ev->multi.y = ev->multi.root.y = y;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+
+   ecore_event_add(ECORE_EVENT_MOUSE_MOVE, ev, NULL, NULL);
+}
+
+static void
+_pointer_ecore_button(int b, int pressed, int x, int y)
+{
+   Ecore_Event_Mouse_Button *ev;
+
+   ev = calloc(1, sizeof(*ev));
+   if (!ev) return;
+
+   ev->window = e_comp->ee_win;
+   ev->event_window = e_comp->ee_win;
+   ev->root_window = e_comp->ee_win;
+   ev->timestamp = _input_timestamp();
+   ev->same_screen = 1;
+   ev->buttons = b;
+   ev->x = ev->root.x = x;
+   ev->y = ev->root.y = y;
+   ev->multi.x = ev->multi.root.x = x;
+   ev->multi.y = ev->multi.root.y = y;
+   ev->multi.radius = 1;
+   ev->multi.radius_x = 1;
+   ev->multi.radius_y = 1;
+   ev->multi.pressure = 1.0;
+
+   ecore_event_add(pressed ? ECORE_EVENT_MOUSE_BUTTON_DOWN
+                           : ECORE_EVENT_MOUSE_BUTTON_UP, ev, NULL, NULL);
+}
+
 static void
 _wl_test_cb_pointer_warp(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, int32_t x, int32_t y)
 {
-   /* Feeding evas is enough: E's wayland pointer handlers are evas callbacks
-    * on the client's frame object, so a synthesised evas event reaches the
-    * client exactly as a real one would. No uinput, no libinput, no seat. */
-   evas_event_feed_mouse_move(e_comp->evas, x, y, 0, NULL);
+   _pointer_ecore_move(x, y);
 }
 
 static void
@@ -147,10 +225,12 @@ _wl_test_cb_pointer_button(struct wl_client *client EINA_UNUSED, struct wl_resou
       default: b = (int)(button - BTN_LEFT) + 1; break;
      }
 
-   if (pressed)
-     evas_event_feed_mouse_down(e_comp->evas, b, EVAS_BUTTON_NONE, 0, NULL);
-   else
-     evas_event_feed_mouse_up(e_comp->evas, b, EVAS_BUTTON_NONE, 0, NULL);
+   {
+      Evas_Coord px, py;
+
+      evas_pointer_canvas_xy_get(e_comp->evas, &px, &py);
+      _pointer_ecore_button(b, pressed, px, py);
+   }
 }
 
 static void
@@ -254,6 +334,57 @@ _wl_test_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t vers
                                   _wl_test_cb_unbind);
 }
 
+
+/* The canvas half, and the reason it is a handler rather than a call right
+ * after ecore_event_add.
+ *
+ * ecore_event_add queues; it does not dispatch. So "post the event, then feed
+ * evas" would run the two in the wrong order, and the order is load-bearing in
+ * at least two places E already documents: a pointer constraint that swallows
+ * a motion must stop the canvas being told the pointer went where the client
+ * asked, and a click that dismisses an xdg_popup grab must be seen before the
+ * evas feed moves focus to whatever is underneath.
+ *
+ * A real session gets that ordering for free, because both halves are handlers
+ * on the same event: E's are appended with E_LIST_HANDLER_APPEND_PRE and can
+ * answer ECORE_CALLBACK_CANCEL to swallow it, and ecore_evas feeds the canvas
+ * from a later one. Registering at ordinary priority puts the harness in
+ * exactly that second position.
+ */
+static Eina_List *_input_handlers = NULL;
+
+static Eina_Bool
+_input_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Move *ev = event;
+
+   if (ev->window != e_comp->ee_win) return ECORE_CALLBACK_RENEW;
+   evas_event_feed_mouse_move(e_comp->evas, ev->x, ev->y, ev->timestamp, NULL);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_input_cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Button *ev = event;
+
+   if (ev->window != e_comp->ee_win) return ECORE_CALLBACK_RENEW;
+   evas_event_feed_mouse_down(e_comp->evas, ev->buttons, EVAS_BUTTON_NONE,
+                              ev->timestamp, NULL);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_input_cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Event_Mouse_Button *ev = event;
+
+   if (ev->window != e_comp->ee_win) return ECORE_CALLBACK_RENEW;
+   evas_event_feed_mouse_up(e_comp->evas, ev->buttons, EVAS_BUTTON_NONE,
+                            ev->timestamp, NULL);
+   return ECORE_CALLBACK_RENEW;
+}
+
 E_API void *
 e_modapi_init(E_Module *m)
 {
@@ -277,6 +408,13 @@ e_modapi_init(E_Module *m)
         return NULL;
      }
 
+   E_LIST_HANDLER_APPEND(_input_handlers, ECORE_EVENT_MOUSE_MOVE,
+                         _input_cb_mouse_move, NULL);
+   E_LIST_HANDLER_APPEND(_input_handlers, ECORE_EVENT_MOUSE_BUTTON_DOWN,
+                         _input_cb_mouse_down, NULL);
+   E_LIST_HANDLER_APPEND(_input_handlers, ECORE_EVENT_MOUSE_BUTTON_UP,
+                         _input_cb_mouse_up, NULL);
+
    INF("wl_test: test interface active - this build is not for production");
 
    return m;
@@ -292,6 +430,8 @@ e_modapi_shutdown(E_Module *m EINA_UNUSED)
      }
    _pending_syncs = eina_list_free(_pending_syncs);
 
+   E_FREE_LIST(_input_handlers, ecore_event_handler_del);
+
    if (_wl_test_global)
      {
         wl_global_destroy(_wl_test_global);

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to