diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index 380e5e03..62f03e37 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -93,9 +93,13 @@ struct wlr_surface { // wlr_subsurface::parent_pending_link struct wl_list subsurface_pending_list; + void *data; }; +typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface, + int sx, int sy, void *data); + struct wlr_renderer; struct wlr_surface *wlr_surface_create(struct wl_resource *res, struct wlr_renderer *renderer); @@ -160,4 +164,12 @@ void wlr_surface_set_role_committed(struct wlr_surface *surface, struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource); +/** + * Call `iterator` on each surface in the surface tree, with the surface's + * positon relative to the root surface. The function is called from root to + * leaves (in rendering order). + */ +void wlr_surface_for_each_surface(struct wlr_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + #endif diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index 89e950c9..1b38b2e3 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -155,4 +155,12 @@ bool wlr_surface_is_wl_shell_surface(struct wlr_surface *surface); struct wlr_wl_surface *wlr_wl_shell_surface_from_wlr_surface( struct wlr_surface *surface); +/** + * Call `iterator` on each surface in the shell surface tree, with the surface's + * positon relative to the root xdg-surface. The function is called from root to + * leaves (in rendering order). + */ +void wlr_wl_shell_surface_for_each_surface(struct wlr_wl_shell_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + #endif diff --git a/include/wlr/types/wlr_xdg_shell.h b/include/wlr/types/wlr_xdg_shell.h index 29b54dba..faf398a7 100644 --- a/include/wlr/types/wlr_xdg_shell.h +++ b/include/wlr/types/wlr_xdg_shell.h @@ -234,4 +234,12 @@ bool wlr_surface_is_xdg_surface(struct wlr_surface *surface); struct wlr_xdg_surface *wlr_xdg_surface_from_wlr_surface( struct wlr_surface *surface); +/** + * Call `iterator` on each surface in the xdg-surface tree, with the surface's + * positon relative to the root xdg-surface. The function is called from root to + * leaves (in rendering order). + */ +void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + #endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index b646f3fe..337d96ab 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -294,4 +294,12 @@ bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface); struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface( struct wlr_surface *surface); +/** + * Call `iterator` on each surface in the xdg-surface tree, with the surface's + * positon relative to the root xdg-surface. The function is called from root to + * leaves (in rendering order). + */ +void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, + wlr_surface_iterator_func_t iterator, void *user_data); + #endif diff --git a/rootston/output.c b/rootston/output.c index bf2bbdc2..bed4a38b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -38,132 +38,70 @@ static void rotate_child_position(double *sx, double *sy, double sw, double sh, } } +struct surface_iterator_data { + surface_iterator_func_t user_iterator; + void *user_data; + double x, y; + int width, height; + float rotation; +}; + +static void surface_iterator(struct wlr_surface *surface, int _sx, int _sy, + void *data) { + struct surface_iterator_data *iter_data = data; + + double sx = _sx, sy = _sy; + rotate_child_position(&sx, &sy, surface->current->width, + surface->current->height, iter_data->width, iter_data->height, + iter_data->rotation); + + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->rotation, iter_data->user_data); +} + static void surface_for_each_surface(struct wlr_surface *surface, double lx, double ly, float rotation, surface_iterator_func_t iterator, void *user_data) { - iterator(surface, lx, ly, rotation, user_data); + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = lx, .y = ly, + .width = surface->current->width, + .height = surface->current->height, + .rotation = rotation, + }; - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - struct wlr_surface_state *state = subsurface->surface->current; - double sx = state->subsurface_position.x; - double sy = state->subsurface_position.y; - rotate_child_position(&sx, &sy, state->width, state->height, - surface->current->width, surface->current->height, rotation); - - surface_for_each_surface(subsurface->surface, lx + sx, ly + sy, - rotation, iterator, user_data); - } -} - -static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, - double base_x, double base_y, float rotation, - surface_iterator_func_t iterator, void *user_data) { - double width = surface->surface->current->width; - double height = surface->surface->current->height; - - struct wlr_xdg_popup_v6 *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface_v6 *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_width = popup->surface->current->width; - double popup_height = popup->surface->current->height; - - double popup_sx, popup_sy; - wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); - rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, - width, height, rotation); - - surface_for_each_surface(popup->surface, base_x + popup_sx, - base_y + popup_sy, rotation, iterator, user_data); - xdg_surface_v6_for_each_surface(popup, base_x + popup_sx, - base_y + popup_sy, rotation, iterator, user_data); - } -} - -static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, - double base_x, double base_y, float rotation, - surface_iterator_func_t iterator, void *user_data) { - double width = surface->surface->current->width; - double height = surface->surface->current->height; - - struct wlr_xdg_popup *popup_state; - wl_list_for_each(popup_state, &surface->popups, link) { - struct wlr_xdg_surface *popup = popup_state->base; - if (!popup->configured) { - continue; - } - - double popup_width = popup->surface->current->width; - double popup_height = popup->surface->current->height; - - double popup_sx, popup_sy; - wlr_xdg_surface_popup_get_position(popup, &popup_sx, &popup_sy); - rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, - width, height, rotation); - - surface_for_each_surface(popup->surface, base_x + popup_sx, - base_y + popup_sy, rotation, iterator, user_data); - xdg_surface_for_each_surface(popup, base_x + popup_sx, - base_y + popup_sy, rotation, iterator, user_data); - } -} - -static void wl_shell_surface_for_each_surface( - struct wlr_wl_shell_surface *surface, double lx, double ly, - float rotation, bool is_child, surface_iterator_func_t iterator, - void *user_data) { - if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { - surface_for_each_surface(surface->surface, lx, ly, rotation, iterator, - user_data); - - double width = surface->surface->current->width; - double height = surface->surface->current->height; - - struct wlr_wl_shell_surface *popup; - wl_list_for_each(popup, &surface->popups, popup_link) { - double popup_width = popup->surface->current->width; - double popup_height = popup->surface->current->height; - - double popup_x = popup->transient_state->x; - double popup_y = popup->transient_state->y; - rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, - width, height, rotation); - - wl_shell_surface_for_each_surface(popup, lx + popup_x, ly + popup_y, - rotation, true, iterator, user_data); - } - } + wlr_surface_for_each_surface(surface, surface_iterator, &data); } static void view_for_each_surface(struct roots_view *view, surface_iterator_func_t iterator, void *user_data) { + struct surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = view->x, .y = view->y, + .width = view->wlr_surface->current->width, + .height = view->wlr_surface->current->height, + .rotation = view->rotation, + }; + switch (view->type) { case ROOTS_XDG_SHELL_V6_VIEW: - surface_for_each_surface(view->wlr_surface, view->x, view->y, - view->rotation, iterator, user_data); - xdg_surface_v6_for_each_surface(view->xdg_surface_v6, view->x, view->y, - view->rotation, iterator, user_data); + wlr_xdg_surface_v6_for_each_surface(view->xdg_surface_v6, + surface_iterator, &data); break; case ROOTS_XDG_SHELL_VIEW: - surface_for_each_surface(view->wlr_surface, view->x, view->y, - view->rotation, iterator, user_data); - xdg_surface_for_each_surface(view->xdg_surface, view->x, view->y, - view->rotation, iterator, user_data); + wlr_xdg_surface_for_each_surface(view->xdg_surface, surface_iterator, + &data); break; case ROOTS_WL_SHELL_VIEW: - wl_shell_surface_for_each_surface(view->wl_shell_surface, view->x, - view->y, view->rotation, false, iterator, user_data); + wlr_wl_shell_surface_for_each_surface(view->wl_shell_surface, + surface_iterator, &data); break; #ifdef WLR_HAS_XWAYLAND case ROOTS_XWAYLAND_VIEW: - if (view->wlr_surface != NULL) { - surface_for_each_surface(view->wlr_surface, view->x, view->y, - view->rotation, iterator, user_data); - } + wlr_surface_for_each_surface(view->wlr_surface, surface_iterator, + &data); break; #endif } @@ -175,7 +113,7 @@ static void xwayland_children_for_each_surface( surface_iterator_func_t iterator, void *user_data) { struct wlr_xwayland_surface *child; wl_list_for_each(child, &surface->children, parent_link) { - if (child->surface != NULL && child->added) { + if (child->mapped) { surface_for_each_surface(child->surface, child->x, child->y, 0, iterator, user_data); } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 4d2a20e7..320e2421 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -951,3 +951,23 @@ void wlr_surface_set_role_committed(struct wlr_surface *surface, surface->role_committed = role_committed; surface->role_data = role_data; } + +static void surface_for_each_surface(struct wlr_surface *surface, int x, int y, + wlr_surface_iterator_func_t iterator, void *user_data) { + iterator(surface, x, y, user_data); + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { + struct wlr_surface_state *state = subsurface->surface->current; + int sx = state->subsurface_position.x; + int sy = state->subsurface_position.y; + + surface_for_each_surface(subsurface->surface, x + sx, y + sy, + iterator, user_data); + } +} + +void wlr_surface_for_each_surface(struct wlr_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + surface_for_each_surface(surface, 0, 0, iterator, user_data); +} diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index 2cbdaf3a..45a80221 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -678,3 +678,42 @@ struct wlr_surface *wlr_wl_shell_surface_surface_at( return wlr_surface_surface_at(surface->surface, sx, sy, sub_sx, sub_sy); } + +struct wl_shell_surface_iterator_data { + wlr_surface_iterator_func_t user_iterator; + void *user_data; + int x, y; +}; + +static void wl_shell_surface_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct wl_shell_surface_iterator_data *iter_data = data; + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->user_data); +} + +static void wl_shell_surface_for_each_surface( + struct wlr_wl_shell_surface *surface, int x, int y, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct wl_shell_surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface(surface->surface, wl_shell_surface_iterator, + &data); + + struct wlr_wl_shell_surface *popup; + wl_list_for_each(popup, &surface->popups, popup_link) { + double popup_x = popup->transient_state->x; + double popup_y = popup->transient_state->y; + + wl_shell_surface_for_each_surface(popup, x + popup_x, y + popup_y, + iterator, user_data); + } +} + +void wlr_wl_shell_surface_for_each_surface(struct wlr_wl_shell_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + wl_shell_surface_for_each_surface(surface, 0, 0, iterator, user_data); +} diff --git a/types/wlr_xdg_shell.c b/types/wlr_xdg_shell.c index f85c6acf..43ccd5aa 100644 --- a/types/wlr_xdg_shell.c +++ b/types/wlr_xdg_shell.c @@ -1659,3 +1659,49 @@ struct wlr_surface *wlr_xdg_surface_surface_at( return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y); } + + +struct xdg_surface_iterator_data { + wlr_surface_iterator_func_t user_iterator; + void *user_data; + int x, y; +}; + +static void xdg_surface_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct xdg_surface_iterator_data *iter_data = data; + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->user_data); +} + +static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { + struct xdg_surface_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface(surface->surface, xdg_surface_iterator, + &data); + + struct wlr_xdg_popup *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_sx, popup_sy; + wlr_xdg_surface_popup_get_position(popup, &popup_sx, &popup_sy); + + xdg_surface_for_each_surface(popup, + x + popup_sx, + y + popup_sy, + iterator, user_data); + } +} + +void wlr_xdg_surface_for_each_surface(struct wlr_xdg_surface *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + xdg_surface_for_each_surface(surface, 0, 0, iterator, user_data); +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index fa5523fc..e7a35f97 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -1884,3 +1884,48 @@ void wlr_positioner_v6_invert_y( positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP; } } + +struct xdg_surface_v6_iterator_data { + wlr_surface_iterator_func_t user_iterator; + void *user_data; + int x, y; +}; + +static void xdg_surface_v6_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct xdg_surface_v6_iterator_data *iter_data = data; + iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy, + iter_data->user_data); +} + +static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, + int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) { + struct xdg_surface_v6_iterator_data data = { + .user_iterator = iterator, + .user_data = user_data, + .x = x, .y = y, + }; + wlr_surface_for_each_surface(surface->surface, xdg_surface_v6_iterator, + &data); + + struct wlr_xdg_popup_v6 *popup_state; + wl_list_for_each(popup_state, &surface->popups, link) { + struct wlr_xdg_surface_v6 *popup = popup_state->base; + if (!popup->configured) { + continue; + } + + double popup_sx, popup_sy; + wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); + + xdg_surface_v6_for_each_surface(popup, + x + popup_sx, + y + popup_sy, + iterator, user_data); + } +} + +void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface, + wlr_surface_iterator_func_t iterator, void *user_data) { + xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data); +}