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 02fb99541a098526e783871e6aef5db85ce7c4b0
Author: Cedric BAIL <[email protected]>
AuthorDate: Sun Aug 9 21:52:33 2026 -0600

    wl_desktop_shell - xdg_positioner anchor and gravity are not bitfields
    
    In zxdg_positioner_v6 anchor and gravity were bitmasks - top=1, bottom=2,
    left=4, right=8 - and corners were made by oring two of them. Stable
    xdg-shell renumbered them as a plain sequential enum: none=0, top=1,
    bottom=2, left=3, right=4, top_left=5, bottom_left=6, top_right=7,
    bottom_right=8. xdg.c was derived from the v6 implementation and kept the
    bit tests, which now mean nothing: "gravity & GRAVITY_LEFT" is "& 3",
    true for top, bottom and left alike.
    
    Three consequences, worst first.
    
    set_gravity rejected legal input. "(g & (TOP|BOTTOM)) == (TOP|BOTTOM)" is
    "(g & 3) == 3", so GRAVITY_LEFT (3) and GRAVITY_TOP_RIGHT (7) raised
    invalid_input and the client was killed for asking. set_anchor did not
    validate at all, where the spec asks for a range check; both now do just
    that, since sequential values have no invalid combination to look for.
    
    The slide adjustment read its direction through the same broken mask, so
    a popup sliding back on screen could be pushed the wrong way.
    
    The flip adjustment dropped corner anchors. It tested only for LEFT and
    RIGHT, so TOP_LEFT matched neither and was left as NONE - flipping x
    silently recentred the popup rather than moving it to TOP_RIGHT. Now
    mirrored one axis at a time, written out per value: no arithmetic maps 5
    to 7 and 6 to 8 while leaving 1 and 2 alone.
    
    wlcs, all XdgPopup suites: 49 passed 56 failed -> 57 passed 48 failed.
    ConstraintAdjustmentFlip 9 failed -> 5, ConstraintAdjustmentSlide 7 -> 5,
    Gravity 6 -> 4. Anchor, ConstraintAdjustmentNone and
    ConstraintAdjustmentResize are unchanged and are separate bugs.
    
    The comment on the helpers says not to reintroduce a bit test, and notes
    that constraint_adjustment genuinely is bitfield="true" so masking
    p->constrain is correct - the trap works in both directions.
    
    Co-Authored-By: Claude Opus 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01FtoiXoSKUmZb6Aix6U3GZS
---
 src/modules/wl_desktop_shell/xdg.c | 152 ++++++++++++++++++++++++++++++-------
 1 file changed, 124 insertions(+), 28 deletions(-)

diff --git a/src/modules/wl_desktop_shell/xdg.c b/src/modules/wl_desktop_shell/xdg.c
index 2f36f5937..35cdb5905 100644
--- a/src/modules/wl_desktop_shell/xdg.c
+++ b/src/modules/wl_desktop_shell/xdg.c
@@ -83,11 +83,111 @@ _e_xdg_positioner_set_anchor_rect(struct wl_client *wl_client EINA_UNUSED, struc
    EINA_RECTANGLE_SET(&p->anchor_rect, x, y, w, h);
 }
 
+/* xdg_positioner's anchor and gravity are plain sequential enums in stable
+ * xdg-shell - none=0, top=1, bottom=2, left=3, right=4, top_left=5,
+ * bottom_left=6, top_right=7, bottom_right=8 - and NOT a bitfield. In
+ * zxdg_positioner_v6 they were (1, 2, 4, 8), which is where the bit tests this
+ * file used to be full of came from: the stable implementation was derived
+ * from the v6 one and the enum changed underneath it.
+ *
+ * Testing them with & gives nonsense. "gravity & GRAVITY_LEFT" is "& 3", true
+ * for top, bottom and left alike. These four predicates are the only sanctioned
+ * way to ask which way an anchor or a gravity points; do not reintroduce a bit
+ * test. Note constraint_adjustment IS a real bitfield (bitfield="true" in the
+ * xml), so masking p->constrain is correct and stays. */
+static Eina_Bool
+_anchor_is_left(enum xdg_positioner_anchor a)
+{
+   return (a == XDG_POSITIONER_ANCHOR_LEFT) ||
+          (a == XDG_POSITIONER_ANCHOR_TOP_LEFT) ||
+          (a == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT);
+}
+
+static Eina_Bool
+_anchor_is_right(enum xdg_positioner_anchor a)
+{
+   return (a == XDG_POSITIONER_ANCHOR_RIGHT) ||
+          (a == XDG_POSITIONER_ANCHOR_TOP_RIGHT) ||
+          (a == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
+}
+
+static Eina_Bool
+_anchor_is_top(enum xdg_positioner_anchor a)
+{
+   return (a == XDG_POSITIONER_ANCHOR_TOP) ||
+          (a == XDG_POSITIONER_ANCHOR_TOP_LEFT) ||
+          (a == XDG_POSITIONER_ANCHOR_TOP_RIGHT);
+}
+
+static Eina_Bool
+_anchor_is_bottom(enum xdg_positioner_anchor a)
+{
+   return (a == XDG_POSITIONER_ANCHOR_BOTTOM) ||
+          (a == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT) ||
+          (a == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT);
+}
+
+/* Mirror one axis, leaving the other alone. Flipping x on top_left has to give
+ * top_right, not "right" and not "none" - the y half of a corner survives the
+ * flip. Spelled out per value because the enum is not positional: there is no
+ * arithmetic that turns 5 into 7 and 6 into 8 while leaving 1 and 2 alone. */
+static enum xdg_positioner_anchor
+_anchor_flip_x(enum xdg_positioner_anchor a)
+{
+   switch (a)
+     {
+      case XDG_POSITIONER_ANCHOR_LEFT:         return XDG_POSITIONER_ANCHOR_RIGHT;
+      case XDG_POSITIONER_ANCHOR_RIGHT:        return XDG_POSITIONER_ANCHOR_LEFT;
+      case XDG_POSITIONER_ANCHOR_TOP_LEFT:     return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
+      case XDG_POSITIONER_ANCHOR_TOP_RIGHT:    return XDG_POSITIONER_ANCHOR_TOP_LEFT;
+      case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:  return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
+      case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
+      default:                                 return a;  /* none, top, bottom */
+     }
+}
+
+static enum xdg_positioner_anchor
+_anchor_flip_y(enum xdg_positioner_anchor a)
+{
+   switch (a)
+     {
+      case XDG_POSITIONER_ANCHOR_TOP:          return XDG_POSITIONER_ANCHOR_BOTTOM;
+      case XDG_POSITIONER_ANCHOR_BOTTOM:       return XDG_POSITIONER_ANCHOR_TOP;
+      case XDG_POSITIONER_ANCHOR_TOP_LEFT:     return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
+      case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:  return XDG_POSITIONER_ANCHOR_TOP_LEFT;
+      case XDG_POSITIONER_ANCHOR_TOP_RIGHT:    return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
+      case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT: return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
+      default:                                 return a;  /* none, left, right */
+     }
+}
+
+/* The gravity enum has the same layout and the same values as the anchor one,
+ * so the anchor helpers answer gravity questions too once it is cast. Kept as
+ * named wrappers rather than raw casts at every call site. */
+#define _gravity_is_left(g)   _anchor_is_left((enum xdg_positioner_anchor)(g))
+#define _gravity_is_right(g)  _anchor_is_right((enum xdg_positioner_anchor)(g))
+#define _gravity_is_top(g)    _anchor_is_top((enum xdg_positioner_anchor)(g))
+#define _gravity_is_bottom(g) _anchor_is_bottom((enum xdg_positioner_anchor)(g))
+#define _gravity_flip_x(g) \
+  ((enum xdg_positioner_gravity)_anchor_flip_x((enum xdg_positioner_anchor)(g)))
+#define _gravity_flip_y(g) \
+  ((enum xdg_positioner_gravity)_anchor_flip_y((enum xdg_positioner_anchor)(g)))
+
 static void
 _e_xdg_positioner_set_anchor(struct wl_client *wl_client EINA_UNUSED, struct wl_resource *resource, enum xdg_positioner_anchor anchor)
 {
    Positioner *p = wl_resource_get_user_data(resource);
 
+   /* "If the anchor is not in the 'anchor' enum, an invalid_input error is
+    * raised." - xdg-shell.xml, xdg_positioner.set_anchor. A range check is the
+    * whole of it; there is no invalid combination to look for, because the
+    * values are not combined. */
+   if (anchor > XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT)
+     {
+        wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+                               "anchor %u is not a value of the anchor enum", anchor);
+        return;
+     }
    p->anchor = anchor;
 }
 
@@ -96,14 +196,17 @@ _e_xdg_positioner_set_gravity(struct wl_client *wl_client EINA_UNUSED, struct wl
 {
    Positioner *p = wl_resource_get_user_data(resource);
 
-   if ((gravity & (XDG_POSITIONER_GRAVITY_TOP | XDG_POSITIONER_GRAVITY_BOTTOM)) ==
-       (XDG_POSITIONER_GRAVITY_TOP | XDG_POSITIONER_GRAVITY_BOTTOM))
-     wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid gravity values passed");
-   else if ((gravity & (XDG_POSITIONER_GRAVITY_LEFT | XDG_POSITIONER_GRAVITY_RIGHT)) ==
-       (XDG_POSITIONER_GRAVITY_LEFT | XDG_POSITIONER_GRAVITY_RIGHT))
-     wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT, "Invalid gravity values passed");
-   else
-     p->gravity = gravity;
+   /* Was two bit tests inherited from v6, and they rejected legal input: with
+    * the stable numbering "(g & (TOP|BOTTOM)) == (TOP|BOTTOM)" is "(g & 3) == 3",
+    * which is true for GRAVITY_LEFT (3) and GRAVITY_TOP_RIGHT (7). A client
+    * asking for either was killed with a protocol error. */
+   if (gravity > XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT)
+     {
+        wl_resource_post_error(resource, XDG_POSITIONER_ERROR_INVALID_INPUT,
+                               "gravity %u is not a value of the gravity enum", gravity);
+        return;
+     }
+   p->gravity = gravity;
 }
 
 static void
@@ -678,14 +781,12 @@ _apply_positioner_x(int x, Positioner *p, Eina_Bool invert)
 
    if (invert)
      {
-        if (p->anchor == XDG_POSITIONER_ANCHOR_LEFT)
-          an = XDG_POSITIONER_ANCHOR_RIGHT;
-        else if (p->anchor == XDG_POSITIONER_ANCHOR_RIGHT)
-          an = XDG_POSITIONER_ANCHOR_LEFT;
-        if (p->gravity == XDG_POSITIONER_GRAVITY_LEFT)
-          grav |= XDG_POSITIONER_GRAVITY_RIGHT;
-        else if (p->gravity == XDG_POSITIONER_GRAVITY_RIGHT)
-          grav |= XDG_POSITIONER_GRAVITY_LEFT;
+        /* Mirror the x half only. The old code tested for LEFT and RIGHT
+         * alone, so a corner anchor such as TOP_LEFT matched neither and was
+         * left as NONE - the flip silently recentred the popup instead of
+         * moving it to TOP_RIGHT. */
+        an = _anchor_flip_x(p->anchor);
+        grav = _gravity_flip_x(p->gravity);
      }
    else
      {
@@ -738,14 +839,9 @@ _apply_positioner_y(int y, Positioner *p, Eina_Bool invert)
 
    if (invert)
      {
-        if (p->anchor == XDG_POSITIONER_ANCHOR_TOP)
-          an = XDG_POSITIONER_ANCHOR_BOTTOM;
-        else if (p->anchor == XDG_POSITIONER_ANCHOR_BOTTOM)
-          an = XDG_POSITIONER_ANCHOR_TOP;
-        if (p->gravity == XDG_POSITIONER_GRAVITY_TOP)
-          grav |= XDG_POSITIONER_GRAVITY_BOTTOM;
-        else if (p->gravity == XDG_POSITIONER_GRAVITY_BOTTOM)
-          grav |= XDG_POSITIONER_GRAVITY_TOP;
+        /* Mirror the y half only; see _apply_positioner_x. */
+        an = _anchor_flip_y(p->anchor);
+        grav = _gravity_flip_y(p->gravity);
      }
    else
      {
@@ -797,14 +893,14 @@ _apply_positioner_slide(E_Client *ec, Positioner *p, int zx, int zy, int zw, int
      {
         int sx = ec->x;
 
-        if (p->gravity & XDG_POSITIONER_GRAVITY_LEFT)
+        if (_gravity_is_left(p->gravity))
           {
              if (ec->x + ec->w > zx + zw)
                sx = MAX(zx + zw - ec->w, ec->parent->x + p->anchor_rect.x - ec->w);
              else if (ec->x < zx)
                sx = MIN(zx, ec->parent->x + p->anchor_rect.x + p->anchor_rect.w);
           }
-        else if (p->gravity & XDG_POSITIONER_GRAVITY_RIGHT)
+        else if (_gravity_is_right(p->gravity))
           {
              if (ec->x < zx)
                sx = MIN(zx, ec->parent->x + p->anchor_rect.x + p->anchor_rect.w);
@@ -820,14 +916,14 @@ _apply_positioner_slide(E_Client *ec, Positioner *p, int zx, int zy, int zw, int
      {
         int sy = ec->y;
 
-        if (p->gravity & XDG_POSITIONER_GRAVITY_TOP)
+        if (_gravity_is_top(p->gravity))
           {
              if (ec->y + ec->h > zy + zh)
                sy = MAX(zy + zh - ec->h, ec->parent->y + p->anchor_rect.y - ec->h);
              else if (ec->y < zy)
                sy = MIN(zy, ec->parent->y + p->anchor_rect.y + p->anchor_rect.h);
           }
-        else if (p->gravity & XDG_POSITIONER_GRAVITY_BOTTOM)
+        else if (_gravity_is_bottom(p->gravity))
           {
              if (ec->y < zy)
                sy = MIN(zy, ec->parent->y + p->anchor_rect.y + p->anchor_rect.h);

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

Reply via email to