xdg-shell: fix positioner

The anchor and gravity bitfields in xdg-shell-unstable-v6 have
been changed to a plain enum whose values cannot be used as a
bitfield in xdg-shell. While it makes input validation easier, it
also makes positioner operations a pain in the ass.
This commit is contained in:
emersion 2018-05-12 23:24:16 +01:00
parent b28f06eca0
commit cc12d03545
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48

View file

@ -422,6 +422,37 @@ static void xdg_shell_handle_create_positioner(struct wl_client *wl_client,
positioner, xdg_positioner_destroy); positioner, xdg_positioner_destroy);
} }
static bool positioner_anchor_has_edge(enum xdg_positioner_anchor anchor,
enum xdg_positioner_anchor edge) {
switch (edge) {
case XDG_POSITIONER_ANCHOR_TOP:
return anchor == XDG_POSITIONER_ANCHOR_TOP ||
anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT ||
anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT;
case XDG_POSITIONER_ANCHOR_BOTTOM:
return anchor == XDG_POSITIONER_ANCHOR_BOTTOM ||
anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT ||
anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
case XDG_POSITIONER_ANCHOR_LEFT:
return anchor == XDG_POSITIONER_ANCHOR_LEFT ||
anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT ||
anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
case XDG_POSITIONER_ANCHOR_RIGHT:
return anchor == XDG_POSITIONER_ANCHOR_RIGHT ||
anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT ||
anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
default:
assert(false); // not reached
}
}
static bool positioner_gravity_has_edge(enum xdg_positioner_gravity gravity,
enum xdg_positioner_gravity edge) {
// gravity and edge enums are the same
return positioner_anchor_has_edge((enum xdg_positioner_anchor)gravity,
(enum xdg_positioner_anchor)edge);
}
struct wlr_box wlr_xdg_positioner_get_geometry( struct wlr_box wlr_xdg_positioner_get_geometry(
struct wlr_xdg_positioner *positioner) { struct wlr_xdg_positioner *positioner) {
struct wlr_box geometry = { struct wlr_box geometry = {
@ -431,9 +462,11 @@ struct wlr_box wlr_xdg_positioner_get_geometry(
.height = positioner->size.height, .height = positioner->size.height,
}; };
if (positioner->anchor & XDG_POSITIONER_ANCHOR_TOP) { if (positioner_anchor_has_edge(positioner->anchor,
XDG_POSITIONER_ANCHOR_TOP)) {
geometry.y += positioner->anchor_rect.y; geometry.y += positioner->anchor_rect.y;
} else if (positioner->anchor & XDG_POSITIONER_ANCHOR_BOTTOM) { } else if (positioner_anchor_has_edge(positioner->anchor,
XDG_POSITIONER_ANCHOR_BOTTOM)) {
geometry.y += geometry.y +=
positioner->anchor_rect.y + positioner->anchor_rect.height; positioner->anchor_rect.y + positioner->anchor_rect.height;
} else { } else {
@ -441,26 +474,32 @@ struct wlr_box wlr_xdg_positioner_get_geometry(
positioner->anchor_rect.y + positioner->anchor_rect.height / 2; positioner->anchor_rect.y + positioner->anchor_rect.height / 2;
} }
if (positioner->anchor & XDG_POSITIONER_ANCHOR_LEFT) { if (positioner_anchor_has_edge(positioner->anchor,
XDG_POSITIONER_ANCHOR_LEFT)) {
geometry.x += positioner->anchor_rect.x; geometry.x += positioner->anchor_rect.x;
} else if (positioner->anchor & XDG_POSITIONER_ANCHOR_RIGHT) { } else if (positioner_anchor_has_edge(positioner->anchor,
XDG_POSITIONER_ANCHOR_RIGHT)) {
geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width; geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width;
} else { } else {
geometry.x += geometry.x +=
positioner->anchor_rect.x + positioner->anchor_rect.width / 2; positioner->anchor_rect.x + positioner->anchor_rect.width / 2;
} }
if (positioner->gravity & XDG_POSITIONER_GRAVITY_TOP) { if (positioner_gravity_has_edge(positioner->gravity,
XDG_POSITIONER_GRAVITY_TOP)) {
geometry.y -= geometry.height; geometry.y -= geometry.height;
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_BOTTOM) { } else if (positioner_gravity_has_edge(positioner->gravity,
XDG_POSITIONER_GRAVITY_BOTTOM)) {
geometry.y = geometry.y; geometry.y = geometry.y;
} else { } else {
geometry.y -= geometry.height / 2; geometry.y -= geometry.height / 2;
} }
if (positioner->gravity & XDG_POSITIONER_GRAVITY_LEFT) { if (positioner_gravity_has_edge(positioner->gravity,
XDG_POSITIONER_GRAVITY_LEFT)) {
geometry.x -= geometry.width; geometry.x -= geometry.width;
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_RIGHT) { } else if (positioner_gravity_has_edge(positioner->gravity,
XDG_POSITIONER_GRAVITY_RIGHT)) {
geometry.x = geometry.x; geometry.x = geometry.x;
} else { } else {
geometry.x -= geometry.width / 2; geometry.x -= geometry.width / 2;
@ -1632,20 +1671,16 @@ void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup,
} else if (anchor == XDG_POSITIONER_ANCHOR_RIGHT) { } else if (anchor == XDG_POSITIONER_ANCHOR_RIGHT) {
sx = rect.x + rect.width; sx = rect.x + rect.width;
sy = (rect.y + rect.height) / 2; sy = (rect.y + rect.height) / 2;
} else if (anchor == (XDG_POSITIONER_ANCHOR_TOP | } else if (anchor == XDG_POSITIONER_ANCHOR_TOP_LEFT) {
XDG_POSITIONER_ANCHOR_LEFT)) {
sx = rect.x; sx = rect.x;
sy = rect.y; sy = rect.y;
} else if (anchor == (XDG_POSITIONER_ANCHOR_TOP | } else if (anchor == XDG_POSITIONER_ANCHOR_TOP_RIGHT) {
XDG_POSITIONER_ANCHOR_RIGHT)) {
sx = rect.x + rect.width; sx = rect.x + rect.width;
sy = rect.y; sy = rect.y;
} else if (anchor == (XDG_POSITIONER_ANCHOR_BOTTOM | } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM_LEFT) {
XDG_POSITIONER_ANCHOR_LEFT)) {
sx = rect.x; sx = rect.x;
sy = rect.y + rect.height; sy = rect.y + rect.height;
} else if (anchor == (XDG_POSITIONER_ANCHOR_BOTTOM | } else if (anchor == XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT) {
XDG_POSITIONER_ANCHOR_RIGHT)) {
sx = rect.x + rect.width; sx = rect.x + rect.width;
sy = rect.y + rect.height; sy = rect.y + rect.height;
} }
@ -1834,43 +1869,66 @@ void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup,
} }
} }
void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner) { static enum xdg_positioner_anchor positioner_anchor_invert_x(
if (positioner->anchor & XDG_POSITIONER_ANCHOR_LEFT) { enum xdg_positioner_anchor anchor) {
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_LEFT; switch (anchor) {
positioner->anchor |= XDG_POSITIONER_ANCHOR_RIGHT; case XDG_POSITIONER_ANCHOR_LEFT:
} else if (positioner->anchor & XDG_POSITIONER_ANCHOR_RIGHT) { return XDG_POSITIONER_ANCHOR_RIGHT;
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_RIGHT; case XDG_POSITIONER_ANCHOR_RIGHT:
positioner->anchor |= XDG_POSITIONER_ANCHOR_LEFT; return XDG_POSITIONER_ANCHOR_LEFT;
} case XDG_POSITIONER_ANCHOR_TOP_LEFT:
return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
if (positioner->gravity & XDG_POSITIONER_GRAVITY_RIGHT) { case XDG_POSITIONER_ANCHOR_BOTTOM_LEFT:
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_RIGHT; return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
positioner->gravity |= XDG_POSITIONER_GRAVITY_LEFT; case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_LEFT) { return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_LEFT; default:
positioner->gravity |= XDG_POSITIONER_GRAVITY_RIGHT; return anchor;
} }
} }
void wlr_positioner_invert_y( static enum xdg_positioner_gravity positioner_gravity_invert_x(
struct wlr_xdg_positioner *positioner) { enum xdg_positioner_gravity gravity) {
if (positioner->anchor & XDG_POSITIONER_ANCHOR_TOP) { // gravity and edge enums are the same
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_TOP; return (enum xdg_positioner_gravity)positioner_anchor_invert_x(
positioner->anchor |= XDG_POSITIONER_ANCHOR_BOTTOM; (enum xdg_positioner_anchor)gravity);
} else if (positioner->anchor & XDG_POSITIONER_ANCHOR_BOTTOM) { }
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_BOTTOM;
positioner->anchor |= XDG_POSITIONER_ANCHOR_TOP;
}
if (positioner->gravity & XDG_POSITIONER_GRAVITY_TOP) { static enum xdg_positioner_anchor positioner_anchor_invert_y(
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_TOP; enum xdg_positioner_anchor anchor) {
positioner->gravity |= XDG_POSITIONER_GRAVITY_BOTTOM; switch (anchor) {
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_BOTTOM) { case XDG_POSITIONER_ANCHOR_TOP:
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_BOTTOM; return XDG_POSITIONER_ANCHOR_BOTTOM;
positioner->gravity |= XDG_POSITIONER_GRAVITY_TOP; 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_BOTTOM_RIGHT:
return XDG_POSITIONER_ANCHOR_TOP_RIGHT;
default:
return anchor;
} }
} }
static enum xdg_positioner_gravity positioner_gravity_invert_y(
enum xdg_positioner_gravity gravity) {
// gravity and edge enums are the same
return (enum xdg_positioner_gravity)positioner_anchor_invert_y(
(enum xdg_positioner_anchor)gravity);
}
void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner) {
positioner->anchor = positioner_anchor_invert_x(positioner->anchor);
positioner->gravity = positioner_gravity_invert_x(positioner->gravity);
}
void wlr_positioner_invert_y(struct wlr_xdg_positioner *positioner) {
positioner->anchor = positioner_anchor_invert_y(positioner->anchor);
positioner->gravity = positioner_gravity_invert_y(positioner->gravity);
}
struct xdg_surface_iterator_data { struct xdg_surface_iterator_data {
wlr_surface_iterator_func_t user_iterator; wlr_surface_iterator_func_t user_iterator;
void *user_data; void *user_data;