Merge pull request #972 from emersion/fix-xdg-shell-popups

Fix xdg-shell stable popups
This commit is contained in:
Drew DeVault 2018-05-13 10:15:08 -04:00 committed by GitHub
commit 658a00602b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 107 additions and 54 deletions

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;
} }
@ -1656,20 +1691,17 @@ void wlr_xdg_popup_get_anchor_point(struct wlr_xdg_popup *popup,
void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup, void wlr_xdg_popup_get_toplevel_coords(struct wlr_xdg_popup *popup,
int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) { int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) {
assert(strcmp(popup->parent->role, wlr_desktop_xdg_toplevel_role) == 0 struct wlr_xdg_surface *parent =
|| strcmp(popup->parent->role, wlr_desktop_xdg_popup_role) == 0); wlr_xdg_surface_from_wlr_surface(popup->parent);
struct wlr_xdg_surface *parent = popup->parent->role_data;
while (parent != NULL && parent->role == WLR_XDG_SURFACE_ROLE_POPUP) { while (parent != NULL && parent->role == WLR_XDG_SURFACE_ROLE_POPUP) {
popup_sx += parent->popup->geometry.x; popup_sx += parent->popup->geometry.x;
popup_sy += parent->popup->geometry.y; popup_sy += parent->popup->geometry.y;
parent = parent->popup->parent->role_data; parent = wlr_xdg_surface_from_wlr_surface(parent->popup->parent);
} }
assert(parent); assert(parent);
*toplevel_sx = popup_sx + parent->geometry.x; *toplevel_sx = popup_sx + parent->geometry.x;
*toplevel_sy = popup_sy + parent->geometry.y; *toplevel_sy = popup_sy + parent->geometry.y;
} }
static void xdg_popup_box_constraints(struct wlr_xdg_popup *popup, static void xdg_popup_box_constraints(struct wlr_xdg_popup *popup,
@ -1837,41 +1869,64 @@ void wlr_xdg_popup_unconstrain_from_box(struct wlr_xdg_popup *popup,
} }
} }
static enum xdg_positioner_anchor positioner_anchor_invert_x(
enum xdg_positioner_anchor anchor) {
switch (anchor) {
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_BOTTOM_LEFT:
return XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
case XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT:
return XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
default:
return anchor;
}
}
static enum xdg_positioner_gravity positioner_gravity_invert_x(
enum xdg_positioner_gravity gravity) {
// gravity and edge enums are the same
return (enum xdg_positioner_gravity)positioner_anchor_invert_x(
(enum xdg_positioner_anchor)gravity);
}
static enum xdg_positioner_anchor positioner_anchor_invert_y(
enum xdg_positioner_anchor anchor) {
switch (anchor) {
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_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) { void wlr_positioner_invert_x(struct wlr_xdg_positioner *positioner) {
if (positioner->anchor & XDG_POSITIONER_ANCHOR_LEFT) { positioner->anchor = positioner_anchor_invert_x(positioner->anchor);
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_LEFT; positioner->gravity = positioner_gravity_invert_x(positioner->gravity);
positioner->anchor |= XDG_POSITIONER_ANCHOR_RIGHT;
} else if (positioner->anchor & XDG_POSITIONER_ANCHOR_RIGHT) {
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_RIGHT;
positioner->anchor |= XDG_POSITIONER_ANCHOR_LEFT;
} }
if (positioner->gravity & XDG_POSITIONER_GRAVITY_RIGHT) { void wlr_positioner_invert_y(struct wlr_xdg_positioner *positioner) {
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_RIGHT; positioner->anchor = positioner_anchor_invert_y(positioner->anchor);
positioner->gravity |= XDG_POSITIONER_GRAVITY_LEFT; positioner->gravity = positioner_gravity_invert_y(positioner->gravity);
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_LEFT) {
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_LEFT;
positioner->gravity |= XDG_POSITIONER_GRAVITY_RIGHT;
}
}
void wlr_positioner_invert_y(
struct wlr_xdg_positioner *positioner) {
if (positioner->anchor & XDG_POSITIONER_ANCHOR_TOP) {
positioner->anchor &= ~XDG_POSITIONER_ANCHOR_TOP;
positioner->anchor |= XDG_POSITIONER_ANCHOR_BOTTOM;
} 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) {
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_TOP;
positioner->gravity |= XDG_POSITIONER_GRAVITY_BOTTOM;
} else if (positioner->gravity & XDG_POSITIONER_GRAVITY_BOTTOM) {
positioner->gravity &= ~XDG_POSITIONER_GRAVITY_BOTTOM;
positioner->gravity |= XDG_POSITIONER_GRAVITY_TOP;
}
} }
struct xdg_surface_iterator_data { struct xdg_surface_iterator_data {

View file

@ -1673,12 +1673,10 @@ void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup,
popup_sy += parent->popup->geometry.y; popup_sy += parent->popup->geometry.y;
parent = parent->popup->parent; parent = parent->popup->parent;
} }
assert(parent); assert(parent);
*toplevel_sx = popup_sx + parent->geometry.x; *toplevel_sx = popup_sx + parent->geometry.x;
*toplevel_sy = popup_sy + parent->geometry.y; *toplevel_sy = popup_sy + parent->geometry.y;
} }
static void xdg_popup_v6_box_constraints(struct wlr_xdg_popup_v6 *popup, static void xdg_popup_v6_box_constraints(struct wlr_xdg_popup_v6 *popup,