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.