From bbd0e23fa79ec39c872c09e49d09a9ccbda68bcd Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 26 Mar 2018 23:48:32 -0400 Subject: [PATCH] xdg-positioner constraint detection --- include/wlr/types/wlr_xdg_shell_v6.h | 18 ++-- rootston/xdg_shell_v6.c | 49 ++++++++++ types/wlr_output_layout.c | 8 +- types/wlr_xdg_shell_v6.c | 137 ++++++++++++++++++++++++++- 4 files changed, 198 insertions(+), 14 deletions(-) diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 47d78664..e192d36a 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -114,15 +114,6 @@ struct wlr_xdg_popup_v6 { struct wlr_box geometry; struct wlr_xdg_positioner_v6_attributes positioner; - struct wlr_box anchor_rect; - - struct { - int32_t width, height; - } size; - - struct { - int32_t x, y; - } offset; struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups }; @@ -305,4 +296,13 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( struct wlr_xdg_surface_v6 *surface, double sx, double sy, double *popup_sx, double *popup_sy); +/** + * Get the anchor point for this popup in the root parent's coordinate system. + */ +void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, + int *root_sx, int *root_sy); + +void wlr_positioner_v6_invert( + struct wlr_xdg_positioner_v6_attributes *positioner); + #endif diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 13d25331..36ecc897 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -45,6 +45,55 @@ static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, if (popup == NULL) { return NULL; } + + struct wlr_xdg_surface_v6 *parent = wlr_popup->parent; + double popup_lx = wlr_popup->geometry.x; + double popup_ly = wlr_popup->geometry.y; + while (parent->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + popup_lx += parent->popup->geometry.x; + popup_ly += parent->popup->geometry.y; + parent = parent->popup->parent; + } + + popup_lx += view->x + parent->geometry.x; + popup_ly += view->y + parent->geometry.y; + int popup_width = wlr_popup->geometry.width; + int popup_height = wlr_popup->geometry.height; + + int anchor_x, anchor_y; + wlr_xdg_popup_v6_get_anchor_point(wlr_popup, &anchor_x, &anchor_y); + anchor_x += popup_lx; + anchor_y += popup_ly; + + struct wlr_output_layout *layout = view->desktop->layout; + + // get the output that contains (or closest to) the anchor point + struct wlr_output *output = + wlr_output_layout_output_at(layout, anchor_x, anchor_y); + if (output == NULL) { + // TODO find the closest output to the anchor + assert(false); + } + + // does the output completely contain the popup? + struct wlr_box *output_box = wlr_output_layout_get_box(layout, output); + bool output_contains_popup_x = popup_lx >= output_box->x && + popup_lx + popup_width <= output_box->x + output_box->width; + bool output_contains_popup_y = popup_ly >= output_box->y && + popup_ly + popup_height <= output_box->y + output_box->height; + + if (!output_contains_popup_x) { + // TODO flip_x + // TODO slide_x + // TODO resize_x + } + + if (!output_contains_popup_y) { + // TODO flip_y + // TODO slide_y + // TODO resize_y + } + popup->wlr_popup = wlr_popup; popup->view_child.destroy = popup_destroy; view_child_init(&popup->view_child, view, wlr_popup->base->surface); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 2462bdd2..8d328c17 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -339,8 +339,12 @@ void wlr_output_layout_closest_point(struct wlr_output_layout *layout, } } - *dest_x = min_x; - *dest_y = min_y; + if (dest_x) { + *dest_x = min_x; + } + if (dest_y) { + *dest_y = min_y; + } } struct wlr_box *wlr_output_layout_get_box( diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 6fddfdbc..fc3a38d4 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -454,7 +454,6 @@ static struct wlr_box xdg_positioner_get_geometry( return geometry; } - static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation; static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource( @@ -593,7 +592,7 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, xdg_positioner_get_geometry(positioner->attrs, surface, parent); // positioner properties - memcpy(&surface->popup->positioner, &positioner->attrs, + memcpy(&surface->popup->positioner, positioner->attrs, sizeof(struct wlr_xdg_positioner_v6_attributes)); wl_list_insert(&parent->popups, &surface->popup->link); @@ -605,7 +604,6 @@ static void xdg_surface_handle_get_popup(struct wl_client *client, wlr_signal_emit_safe(&parent->events.new_popup, surface->popup); } - static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation; static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource( @@ -1591,3 +1589,136 @@ struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( return NULL; } + +void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup, + int *root_sx, int *root_sy) { + struct wlr_box rect = popup->positioner.anchor_rect; + enum wlr_positioner_v6_anchor anchor = popup->positioner.anchor; + int sx = 0, sy = 0; + + if (anchor == WLR_POSITIONER_V6_ANCHOR_NONE) { + sx = (rect.x + rect.width) / 2; + sy = (rect.y + rect.height) / 2; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_TOP) { + sx = (rect.x + rect.width) / 2; + sy = rect.y; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_BOTTOM) { + sx = (rect.x + rect.width) / 2; + sy = rect.y + rect.height; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_LEFT) { + sx = rect.x; + sy = (rect.y + rect.height) / 2; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_RIGHT) { + sx = rect.x + rect.width; + sy = (rect.y + rect.height) / 2; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_TOP | + WLR_POSITIONER_V6_ANCHOR_LEFT)) { + sx = rect.x; + sy = rect.y; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_TOP | + WLR_POSITIONER_V6_ANCHOR_RIGHT)) { + sx = rect.x + rect.width; + sy = rect.y; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_BOTTOM | + WLR_POSITIONER_V6_ANCHOR_LEFT)) { + sx = rect.x; + sy = rect.y + rect.height; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_BOTTOM | + WLR_POSITIONER_V6_ANCHOR_RIGHT)) { + sx = rect.x + rect.width; + sy = rect.y + rect.height; + } + + *root_sx = sx; + *root_sy = sy; + + /* + // XXX: THIS IS WILL WORK WITH XDG SHELL STABLE + switch (popup->positioner.anchor) { + case WLR_POSITIONER_ANCHOR_NONE: + sx = (rect.x + rect.width) / 2; + sy = (rect.y + rect.height) / 2; + break; + case WLR_POSITIONER_ANCHOR_TOP: + sx = (rect.x + rect.width) / 2; + sy = rect.y; + break; + case WLR_POSITIONER_ANCHOR_BOTTOM: + sx = (rect.x + rect.width) / 2; + sy = rect.y + rect.height; + break; + case WLR_POSITIONER_ANCHOR_LEFT: + sx = rect.x; + sy = (rect.y + rect.height) / 2; + break; + case WLR_POSITIONER_ANCHOR_RIGHT: + sx = rect.x + rect.width; + sy = (rect.y + rect.height) / 2; + break; + case WLR_POSITIONER_ANCHOR_TOP_LEFT: + sx = rect.x; + sy = rect.y; + break; + case WLR_POSITIONER_ANCHOR_BOTTOM_LEFT: + sx = rect.x; + sy = rect.y + rect.height; + break; + case WLR_POSITIONER_ANCHOR_TOP_RIGHT: + sx = rect.x + rect.width; + sy = rect.y; + break; + case WLR_POSITIONER_ANCHOR_BOTTOM_RIGHT: + sx = rect.x + rect.width; + sy = rect.y + rect.height; + break; + } + */ +} + +void wlr_positioner_v6_invert( + struct wlr_xdg_positioner_v6_attributes *positioner) { + enum wlr_positioner_v6_anchor anchor = positioner->anchor; + + if (anchor == WLR_POSITIONER_V6_ANCHOR_NONE) { + // already inverted + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_TOP) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_BOTTOM; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_BOTTOM) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_TOP; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_LEFT) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_RIGHT; + } else if (anchor == WLR_POSITIONER_V6_ANCHOR_RIGHT) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_LEFT; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_TOP | + WLR_POSITIONER_V6_ANCHOR_LEFT)) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_BOTTOM | WLR_POSITIONER_V6_ANCHOR_RIGHT; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_TOP | + WLR_POSITIONER_V6_ANCHOR_RIGHT)) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_BOTTOM | WLR_POSITIONER_V6_ANCHOR_LEFT; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_BOTTOM | + WLR_POSITIONER_V6_ANCHOR_LEFT)) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_TOP | WLR_POSITIONER_V6_ANCHOR_RIGHT; + } else if (anchor == (WLR_POSITIONER_V6_ANCHOR_BOTTOM | + WLR_POSITIONER_V6_ANCHOR_RIGHT)) { + positioner->anchor = WLR_POSITIONER_V6_ANCHOR_TOP | WLR_POSITIONER_V6_ANCHOR_LEFT; + } + + enum wlr_positioner_v6_gravity gravity = positioner->gravity; + switch (gravity) { + case WLR_POSITIONER_V6_GRAVITY_NONE: + // already inverted + break; + case WLR_POSITIONER_V6_GRAVITY_TOP: + positioner->gravity = WLR_POSITIONER_V6_GRAVITY_BOTTOM; + break; + case WLR_POSITIONER_V6_GRAVITY_BOTTOM: + positioner->gravity = WLR_POSITIONER_V6_GRAVITY_TOP; + break; + case WLR_POSITIONER_V6_GRAVITY_LEFT: + positioner->gravity = WLR_POSITIONER_V6_GRAVITY_RIGHT; + break; + case WLR_POSITIONER_V6_GRAVITY_RIGHT: + positioner->gravity = WLR_POSITIONER_V6_GRAVITY_LEFT; + break; + } +}