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 bc22568e552555e8f4ec5cfa080ca4f6a9bcda93
Author: Cedric BAIL <[email protected]>
AuthorDate: Tue Aug 11 16:40:53 2026 -0600

    e_comp_wl - activate a pointer constraint without waiting for motion
    
    E only ever evaluated pointer constraints from the motion path:
    _e_comp_cb_mouse_move() is the sole caller of
    e_comp_wl_extension_pointer_constraints_update() in the tree. So a lock
    taken while the pointer was already sitting inside a focused surface was
    never activated and never announced - and that is not an edge case, it is
    the normal one. A client locks the pointer precisely *because* the pointer
    is already where it wants it; Chromium and Firefox both take pointer lock
    on a click in the content area, with the pointer stationary.
    
    Nothing has to move for the answer to change, so evaluate it in the three
    places where it can: creating the constraint, committing one, and the
    surface gaining the focus. The last of those was missing entirely - grep
    found no focus-change hook touching constraints anywhere - which is also
    why half the protocol was unimplemented in the other direction: a
    constraint has to deactivate when its surface loses the pointer, and a
    oneshot one is defunct from then on, so only a persistent one may be
    activated again. Hence the dead flag.
    
    Worth being precise about where this does *not* go: an earlier attempt put
    the activation pass at the end of pointer_constraints_commit() alone, and
    measured nothing at all. Instrumenting says why - the client commits its
    surface and only then asks for the lock, and never commits again, so under
    test that hook is never reached after a constraint exists. Creation is
    where it has to happen.
    
    wlcs PointerConstraints+RelativePointer: 8 passed -> 14.
    
    Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
    Claude-Session: https://claude.ai/code/session_01W6z4GbxmqypzCzUHPwzFMd
---
 src/bin/e_comp_wl_extensions.c | 94 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 90 insertions(+), 4 deletions(-)

diff --git a/src/bin/e_comp_wl_extensions.c b/src/bin/e_comp_wl_extensions.c
index 7de8de268..ec1099276 100644
--- a/src/bin/e_comp_wl_extensions.c
+++ b/src/bin/e_comp_wl_extensions.c
@@ -40,10 +40,86 @@ typedef struct Constraint
    Eina_Bool lock E_BITFIELD; // if not lock, confine
    Eina_Bool persistent E_BITFIELD;
    Eina_Bool active E_BITFIELD;
+   Eina_Bool dead E_BITFIELD; // oneshot, already deactivated once
 } Constraint;
 
 static Eina_List *active_constraints;
 
+static Eina_Bool _inside_tiler(Eina_Tiler *r, Eina_Bool active, int x, int y, int px, int py, int *ax, int *ay);
+
+/* A constraint becomes active when its surface holds the focus and the pointer
+ * is already inside it, and nothing has to move for that to become true: a
+ * client locks the pointer precisely *because* the pointer is already sitting
+ * where it wants it, which is what both browsers do on a click in the content
+ * area. So the motion path cannot be the only thing that evaluates this - it
+ * was, and a lock taken over a stationary pointer was simply never announced.
+ *
+ * Called from the places where the answer can change without motion: creating
+ * the constraint, committing one, and the surface gaining the focus. */
+static void
+_constraints_activate(E_Client *ec)
+{
+   Eina_List *l;
+   Constraint *c;
+   int px, py;
+
+   if ((!ec) || (!ec->comp_data) || (!ec->frame)) return;
+   if (ec != e_client_focused_get()) return;
+   evas_pointer_canvas_xy_get(e_comp->evas, &px, &py);
+   if (!e_comp_object_coords_inside_input_area(ec->frame, px, py)) return;
+
+   EINA_LIST_FOREACH(ec->comp_data->constraints, l, c)
+     {
+        int ax = 0, ay = 0;
+
+        if (c->active || c->dead) continue;
+        if (!_inside_tiler(c->region, EINA_FALSE, px - ec->client.x, py - ec->client.y,
+              px - ec->client.x, py - ec->client.y, &ax, &ay))
+          continue;
+        c->active = 1;
+        active_constraints = eina_list_append(active_constraints, c);
+        if (c->lock)
+          zwp_locked_pointer_v1_send_locked(c->res);
+        else
+          zwp_confined_pointer_v1_send_confined(c->res);
+     }
+}
+
+/* The protocol requires a constraint to deactivate when its surface stops
+ * being the one the pointer is directed at, and a oneshot constraint is
+ * defunct from then on - only a persistent one may be activated again. */
+static void
+_constraints_deactivate(E_Client *ec)
+{
+   Eina_List *l;
+   Constraint *c;
+
+   if ((!ec) || (!ec->comp_data)) return;
+   EINA_LIST_FOREACH(ec->comp_data->constraints, l, c)
+     {
+        if (!c->active) continue;
+        c->active = 0;
+        if (!c->persistent) c->dead = 1;
+        active_constraints = eina_list_remove(active_constraints, c);
+        if (c->lock)
+          zwp_locked_pointer_v1_send_unlocked(c->res);
+        else
+          zwp_confined_pointer_v1_send_unconfined(c->res);
+     }
+}
+
+static void
+_e_comp_wl_extensions_client_focus_set(void *d EINA_UNUSED, E_Client *ec)
+{
+   _constraints_activate(ec);
+}
+
+static void
+_e_comp_wl_extensions_client_focus_unset(void *d EINA_UNUSED, E_Client *ec)
+{
+   _constraints_deactivate(ec);
+}
+
 static void
 _e_comp_wl_extensions_client_move_begin(void *d EINA_UNUSED, E_Client *ec)
 {
@@ -494,15 +570,20 @@ _e_comp_wl_zwp_pointer_constraints_v1_lock_pointer(struct wl_client *client, str
 
    c = do_constraint(&zwp_locked_pointer_v1_interface, &_e_comp_wl_locked_pointer_v1_interface,
      client, resource, id, surface, pointer, region, lifetime);
-   if (c)
-     c->lock = 1;
+   if (!c) return;
+   c->lock = 1;
+   _constraints_activate(c->ec);
 }
 
 static void
 _e_comp_wl_zwp_pointer_constraints_v1_confine_pointer(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface, struct wl_resource *pointer, struct wl_resource *region, uint32_t lifetime)
 {
-   do_constraint(&zwp_confined_pointer_v1_interface, &_e_comp_wl_confined_pointer_v1_interface,
+   Constraint *c;
+
+   c = do_constraint(&zwp_confined_pointer_v1_interface, &_e_comp_wl_confined_pointer_v1_interface,
      client, resource, id, surface, pointer, region, lifetime);
+   if (c)
+     _constraints_activate(c->ec);
 }
 
 /////////////////////////////////////////////////////////
@@ -1021,6 +1102,9 @@ e_comp_wl_extensions_init(void)
    e_client_hook_add(E_CLIENT_HOOK_MOVE_BEGIN, _e_comp_wl_extensions_client_move_begin, NULL);
    e_client_hook_add(E_CLIENT_HOOK_MOVE_END, _e_comp_wl_extensions_client_move_end, NULL);
 
+   e_client_hook_add(E_CLIENT_HOOK_FOCUS_SET, _e_comp_wl_extensions_client_focus_set, NULL);
+   e_client_hook_add(E_CLIENT_HOOK_FOCUS_UNSET, _e_comp_wl_extensions_client_focus_unset, NULL);
+
    act = e_action_add("key_route");
    act->func.go_key = _e_comp_wl_action_route_act_key_route_go;
    act->func.end_key = _e_comp_wl_action_route_act_key_route_go_end;
@@ -1079,6 +1163,8 @@ e_comp_wl_extension_pointer_constraints_commit(E_Client *ec)
              c->pending_xy = NULL;
           }
      }
+   /* a newly committed region can be what makes a constraint eligible */
+   _constraints_activate(ec);
 }
 
 static Eina_Bool
@@ -1211,7 +1297,7 @@ e_comp_wl_extension_pointer_constraints_update(E_Client *ec, int x, int y)
         int ax = px - ec->client.x, ay = py - ec->client.y;
         Eina_Bool inside_region = _inside_tiler(c->region, c->active, x - ec->client.x, y - ec->client.y,
           px - ec->client.x, py - ec->client.y, &ax, &ay);
-        if ((!c->active) && inside && inside_region)
+        if ((!c->active) && (!c->dead) && inside && inside_region)
           {
              c->active = 1;
              active_constraints = eina_list_append(active_constraints, c);

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

Reply via email to