diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 9f898b38..03376788 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -122,4 +122,11 @@ void wlr_surface_make_subsurface(struct wlr_surface *surface, */ struct wlr_surface *wlr_surface_get_main_surface(struct wlr_surface *surface); +/** + * Find a subsurface within this surface at the surface-local coordinates. + * Returns the surface and coordinates in the topmost surface coordinate system + * or NULL if no subsurface is found at that location. + */ +struct wlr_subsurface *wlr_surface_subsurface_at(struct wlr_surface *surface, + double sx, double sy, double *sub_x, double *sub_y); #endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 00295ec1..48da6604 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -206,4 +206,12 @@ void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, */ void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface); +/** + * Find a popup within this surface at the surface-local coordinates. Returns + * the popup and coordinates in the topmost surface coordinate system or NULL if + * no popup is found at that location. + */ +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); #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index 001cefe0..bef0fad4 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -98,75 +98,6 @@ bool view_initialize(struct roots_view *view) { return centered; } -static struct wlr_subsurface *subsurface_at(struct wlr_surface *surface, - double sx, double sy, double *sub_x, double *sub_y) { - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - double _sub_x = subsurface->surface->current->subsurface_position.x; - double _sub_y = subsurface->surface->current->subsurface_position.y; - struct wlr_subsurface *sub = - subsurface_at(subsurface->surface, _sub_x + sx, _sub_y + sy, - sub_x, sub_y); - if (sub) { - // TODO: This won't work for nested subsurfaces. Convert sub_x and - // sub_y to the parent coordinate system - return sub; - } - - int sub_width = subsurface->surface->current->buffer_width; - int sub_height = subsurface->surface->current->buffer_height; - if ((sx > _sub_x && sx < _sub_x + sub_width) && - (sy > _sub_y && sy < _sub_y + sub_height)) { - if (pixman_region32_contains_point( - &subsurface->surface->current->input, - sx - _sub_x, sy - _sub_y, NULL)) { - *sub_x = _sub_x; - *sub_y = _sub_y; - return subsurface; - } - } - } - - return NULL; -} - -static struct wlr_xdg_surface_v6 *xdg_v6_popup_at( - struct wlr_xdg_surface_v6 *surface, double sx, double sy, - double *popup_sx, double *popup_sy) { - // XXX: I think this is so complicated because we're mixing geometry - // coordinates with surface coordinates. Input handling should only deal - // with surface coordinates. - struct wlr_xdg_surface_v6 *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { - double _popup_sx = surface->geometry->x + popup->popup_state->geometry.x; - double _popup_sy = surface->geometry->y + popup->popup_state->geometry.y; - int popup_width = popup->popup_state->geometry.width; - int popup_height = popup->popup_state->geometry.height; - - struct wlr_xdg_surface_v6 *_popup = - xdg_v6_popup_at(popup, sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, popup_sx, popup_sy); - if (_popup) { - *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; - *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; - return _popup; - } - - if ((sx > _popup_sx && sx < _popup_sx + popup_width) && - (sy > _popup_sy && sy < _popup_sy + popup_height)) { - if (pixman_region32_contains_point(&popup->surface->current->input, - sx - _popup_sx + popup->geometry->x, - sy - _popup_sy + popup->geometry->y, NULL)) { - *popup_sx = _popup_sx - popup->geometry->x; - *popup_sy = _popup_sy - popup->geometry->y; - return popup; - } - } - } - - return NULL; -} - struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { for (int i = desktop->views->length - 1; i >= 0; --i) { @@ -196,8 +127,8 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, // TODO: test if this works with rotated views double popup_sx, popup_sy; struct wlr_xdg_surface_v6 *popup = - xdg_v6_popup_at(view->xdg_surface_v6, view_sx, view_sy, - &popup_sx, &popup_sy); + wlr_xdg_surface_v6_popup_at(view->xdg_surface_v6, + view_sx, view_sy, &popup_sx, &popup_sy); if (popup) { *sx = view_sx - popup_sx; @@ -209,7 +140,8 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, double sub_x, sub_y; struct wlr_subsurface *subsurface = - subsurface_at(view->wlr_surface, view_sx, view_sy, &sub_x, &sub_y); + wlr_surface_subsurface_at(view->wlr_surface, + view_sx, view_sy, &sub_x, &sub_y); if (subsurface) { *sx = view_sx - sub_x; *sy = view_sy - sub_y; diff --git a/types/wlr_surface.c b/types/wlr_surface.c index b4f7b30f..71a09bb5 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -844,3 +844,35 @@ struct wlr_surface *wlr_surface_get_main_surface(struct wlr_surface *surface) { return surface; } + +struct wlr_subsurface *wlr_surface_subsurface_at(struct wlr_surface *surface, + double sx, double sy, double *sub_x, double *sub_y) { + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + double _sub_x = subsurface->surface->current->subsurface_position.x; + double _sub_y = subsurface->surface->current->subsurface_position.y; + struct wlr_subsurface *sub = + wlr_surface_subsurface_at(subsurface->surface, _sub_x + sx, + _sub_y + sy, sub_x, sub_y); + if (sub) { + // TODO: This won't work for nested subsurfaces. Convert sub_x and + // sub_y to the parent coordinate system + return sub; + } + + int sub_width = subsurface->surface->current->buffer_width; + int sub_height = subsurface->surface->current->buffer_height; + if ((sx > _sub_x && sx < _sub_x + sub_width) && + (sy > _sub_y && sy < _sub_y + sub_height)) { + if (pixman_region32_contains_point( + &subsurface->surface->current->input, + sx - _sub_x, sy - _sub_y, NULL)) { + *sub_x = _sub_x; + *sub_y = _sub_y; + return subsurface; + } + } + } + + return NULL; +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 5f2554f8..a16d3319 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -1301,3 +1301,44 @@ void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface) { assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL); zxdg_toplevel_v6_send_close(surface->toplevel_state->resource); } + +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) { + // XXX: I think this is so complicated because we're mixing geometry + // coordinates with surface coordinates. Input handling should only deal + // with surface coordinates. + struct wlr_xdg_surface_v6 *popup; + wl_list_for_each(popup, &surface->popups, popup_link) { + double _popup_sx = + surface->geometry->x + popup->popup_state->geometry.x; + double _popup_sy = + surface->geometry->y + popup->popup_state->geometry.y; + int popup_width = popup->popup_state->geometry.width; + int popup_height = popup->popup_state->geometry.height; + + struct wlr_xdg_surface_v6 *_popup = + wlr_xdg_surface_v6_popup_at(popup, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, + popup_sx, popup_sy); + if (_popup) { + *popup_sx = *popup_sx + _popup_sx - popup->geometry->x; + *popup_sy = *popup_sy + _popup_sy - popup->geometry->y; + return _popup; + } + + if ((sx > _popup_sx && sx < _popup_sx + popup_width) && + (sy > _popup_sy && sy < _popup_sy + popup_height)) { + if (pixman_region32_contains_point(&popup->surface->current->input, + sx - _popup_sx + popup->geometry->x, + sy - _popup_sy + popup->geometry->y, NULL)) { + *popup_sx = _popup_sx - popup->geometry->x; + *popup_sy = _popup_sy - popup->geometry->y; + return popup; + } + } + } + + return NULL; +}