diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 7ed6aab1a..f37bbd793 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -169,16 +169,16 @@ struct sway_container *container_parent(struct sway_container *container, * surface-local coordinates of the given layout coordinates if the container * is a view and the view contains a surface at those coordinates. */ -struct sway_container *container_at(struct sway_container *container, - double ox, double oy, struct wlr_surface **surface, +struct sway_container *container_at(struct sway_container *workspace, + double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); /** - * Same as container_at, but only checks floating views and expects coordinates - * to be layout coordinates, as that's what floating views use. + * Same as container_at, but only checks for popups only. */ -struct sway_container *floating_container_at(double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy); +struct sway_container *popup_at(struct sway_container *workspace, + double lx, double ly, struct wlr_surface **surface, + double *sx, double *sy); /** * Apply the function for each descendant of the container breadth first. diff --git a/sway/desktop/output.c b/sway/desktop/output.c index acc9caaec..09e5424f4 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -70,6 +70,7 @@ struct render_data { struct sway_output *output; pixman_region32_t *damage; float alpha; + bool render_popups; }; static bool get_surface_box(struct root_geometry *geo, @@ -217,9 +218,32 @@ damage_finish: pixman_region32_fini(&damage); } +static bool surface_is_popup(struct wlr_surface *surface) { + if (wlr_surface_is_xwayland_surface(surface)) { + struct wlr_xwayland_surface *xsurface = + wlr_xwayland_surface_from_wlr_surface(surface); + return wlr_xwayland_surface_is_unmanaged(xsurface); + } + if (wlr_surface_is_xdg_surface(surface)) { + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(surface); + return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP; + } + if (wlr_surface_is_xdg_surface_v6(surface)) { + struct wlr_xdg_surface_v6 *xdg_surface_v6 = + wlr_xdg_surface_v6_from_wlr_surface(surface); + return xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_POPUP; + } + // Layer surface + return false; +} + static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *_data) { struct render_data *data = _data; + if (surface_is_popup(surface) != data->render_popups) { + return; + } struct wlr_output *wlr_output = data->output->wlr_output; float rotation = data->root_geo.rotation; pixman_region32_t *output_damage = data->damage; @@ -311,11 +335,13 @@ static void premultiply_alpha(float color[4], float opacity) { } static void render_view_surfaces(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { + struct sway_output *output, pixman_region32_t *damage, + float alpha, bool popups) { struct render_data data = { .output = output, .damage = damage, .alpha = alpha, + .render_popups = popups, }; output_view_for_each_surface( view, &data.root_geo, render_surface_iterator, &data); @@ -327,7 +353,7 @@ static void render_view_surfaces(struct sway_view *view, static void render_view(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, struct border_colors *colors) { struct sway_view *view = con->sway_view; - render_view_surfaces(view, output, damage, view->swayc->alpha); + render_view_surfaces(view, output, damage, view->swayc->alpha, false); struct wlr_box box; float output_scale = output->wlr_output->scale; @@ -833,6 +859,26 @@ static struct sway_container *output_get_active_workspace( return workspace; } +static void render_popups(struct sway_output *output, pixman_region32_t *damage, + struct sway_container *container) { + if (container->type == C_VIEW) { + render_view_surfaces(container->sway_view, output, damage, 1.0, true); + return; + } + if (container->layout == L_TABBED || container->layout == L_STACKED) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *child = seat_get_active_child(seat, container); + if (child) { + render_popups(output, damage, child); + } + } else { + for (int i = 0; i < container->children->length; ++i) { + struct sway_container *child = container->children->items[i]; + render_popups(output, damage, child); + } + } +} + static void render_output(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -877,8 +923,10 @@ static void render_output(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces( - workspace->sway_workspace->fullscreen, output, damage, 1.0f); + render_view_surfaces(workspace->sway_workspace->fullscreen, + output, damage, 1.0f, false); + render_view_surfaces(workspace->sway_workspace->fullscreen, + output, damage, 1.0f, true); if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, @@ -902,7 +950,9 @@ static void render_output(struct sway_output *output, struct timespec *when, struct sway_seat *seat = input_manager_current_seat(input_manager); struct sway_container *focus = seat_get_focus(seat); render_container(output, damage, workspace, focus == workspace); + render_popups(output, damage, workspace); render_floating(output, damage); + render_popups(output, damage, workspace->sway_workspace->floating); render_unmanaged(output, damage, &root_container.sway_root->xwayland_unmanaged); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index d6e17ae14..1ca1bd171 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -108,7 +108,7 @@ static struct sway_container *container_at_coords( } struct sway_container *c; - if ((c = floating_container_at(lx, ly, surface, sx, sy))) { + if ((c = popup_at(ws, lx, ly, surface, sx, sy))) { return c; } if ((c = container_at(ws, lx, ly, surface, sx, sy))) { diff --git a/sway/tree/container.c b/sway/tree/container.c index d0d266317..fdeae2b56 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -474,9 +474,9 @@ struct sway_container *container_parent(struct sway_container *container, return container; } -static struct sway_container *container_at_view(struct sway_container *swayc, - double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy) { +static struct sway_container *surface_at_view(struct sway_container *swayc, + double lx, double ly, struct wlr_surface **surface, + double *sx, double *sy, bool only_popups) { if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { return NULL; } @@ -490,6 +490,13 @@ static struct sway_container *container_at_view(struct sway_container *swayc, case SWAY_VIEW_XWAYLAND: _surface = wlr_surface_surface_at(sview->surface, view_sx, view_sy, &_sx, &_sy); + if (_surface && only_popups) { + struct wlr_xwayland_surface *xsurface = + wlr_xwayland_surface_from_wlr_surface(_surface); + if (!wlr_xwayland_surface_is_unmanaged(xsurface)) { + return NULL; + } + } break; case SWAY_VIEW_XDG_SHELL_V6: // the top left corner of the sway container is the @@ -500,6 +507,13 @@ static struct sway_container *container_at_view(struct sway_container *swayc, _surface = wlr_xdg_surface_v6_surface_at( sview->wlr_xdg_surface_v6, view_sx, view_sy, &_sx, &_sy); + if (_surface && only_popups) { + struct wlr_xdg_surface_v6 *xdg_surface_v6 = + wlr_xdg_surface_v6_from_wlr_surface(_surface); + if (xdg_surface_v6->role != WLR_XDG_SURFACE_V6_ROLE_POPUP) { + return NULL; + } + } break; case SWAY_VIEW_XDG_SHELL: // the top left corner of the sway container is the @@ -510,6 +524,13 @@ static struct sway_container *container_at_view(struct sway_container *swayc, _surface = wlr_xdg_surface_surface_at( sview->wlr_xdg_surface, view_sx, view_sy, &_sx, &_sy); + if (_surface && only_popups) { + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(_surface); + if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_POPUP) { + return NULL; + } + } break; } if (_surface) { @@ -517,9 +538,16 @@ static struct sway_container *container_at_view(struct sway_container *swayc, *sy = _sy; *surface = _surface; } + if (only_popups && !_surface) { + return NULL; + } return swayc; } +static struct sway_container *container_at_container( + struct sway_container *parent, double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy); + /** * container_at for a container with layout L_TABBED. */ @@ -546,7 +574,7 @@ static struct sway_container *container_at_tabbed(struct sway_container *parent, // Surfaces struct sway_container *current = seat_get_active_child(seat, parent); - return container_at(current, lx, ly, surface, sx, sy); + return container_at_container(current, lx, ly, surface, sx, sy); } /** @@ -571,7 +599,7 @@ static struct sway_container *container_at_stacked( // Surfaces struct sway_container *current = seat_get_active_child(seat, parent); - return container_at(current, lx, ly, surface, sx, sy); + return container_at_container(current, lx, ly, surface, sx, sy); } /** @@ -589,21 +617,17 @@ static struct sway_container *container_at_linear(struct sway_container *parent, .height = child->height, }; if (wlr_box_contains_point(&box, lx, ly)) { - return container_at(child, lx, ly, surface, sx, sy); + return container_at_container(child, lx, ly, surface, sx, sy); } } return NULL; } -struct sway_container *container_at(struct sway_container *parent, - double lx, double ly, +static struct sway_container *container_at_container( + struct sway_container *parent, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (!sway_assert(parent->type >= C_WORKSPACE, - "Expected workspace or deeper")) { - return NULL; - } if (parent->type == C_VIEW) { - return container_at_view(parent, lx, ly, surface, sx, sy); + return surface_at_view(parent, lx, ly, surface, sx, sy, false); } if (!parent->children->length) { return NULL; @@ -623,38 +647,77 @@ struct sway_container *container_at(struct sway_container *parent, case L_NONE: return NULL; } - return NULL; } -struct sway_container *floating_container_at(double lx, double ly, +struct sway_container *container_at(struct sway_container *workspace, + double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - for (int i = 0; i < root_container.children->length; ++i) { - struct sway_container *output = root_container.children->items[i]; - for (int j = 0; j < output->children->length; ++j) { - struct sway_container *workspace = output->children->items[j]; - struct sway_workspace *ws = workspace->sway_workspace; - if (!workspace_is_visible(workspace)) { - continue; - } - for (int k = 0; k < ws->floating->children->length; ++k) { - struct sway_container *floater = - ws->floating->children->items[k]; - struct wlr_box box = { - .x = floater->x, - .y = floater->y, - .width = floater->width, - .height = floater->height, - }; - if (wlr_box_contains_point(&box, lx, ly)) { - return container_at(floater, lx, ly, surface, sx, sy); - } + if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { + return NULL; + } + struct sway_container *floating = workspace->sway_workspace->floating; + struct sway_container *c; + // Floating + for (int i = 0; i < floating->children->length; ++i) { + struct sway_container *floater = floating->children->items[i]; + if ((c = container_at_container(floater, lx, ly, surface, sx, sy))) { + return c; + } + } + // Tiling + if ((c = container_at_container(workspace, lx, ly, surface, sx, sy))) { + return c; + } + return NULL; +} + +static struct sway_container *popup_at_container(struct sway_container *parent, + double lx, double ly, struct wlr_surface **surface, + double *sx, double *sy) { + if (parent->type == C_VIEW) { + return surface_at_view(parent, lx, ly, surface, sx, sy, true); + } + if (parent->layout == L_TABBED || parent->layout == L_STACKED) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *child = seat_get_active_child(seat, parent); + struct sway_container *c = + popup_at_container(child, lx, ly, surface, sx, sy); + if (c) { + return c; + } + } else { + for (int i = 0; i < parent->children->length; ++i) { + struct sway_container *child = parent->children->items[i]; + struct sway_container *c = + popup_at_container(child, lx, ly, surface, sx, sy); + if (c) { + return c; } } } return NULL; } +struct sway_container *popup_at(struct sway_container *workspace, + double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy) { + if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { + return NULL; + } + struct sway_container *c; + // Floating popups + if ((c = popup_at_container(workspace->sway_workspace->floating, lx, ly, + surface, sx, sy))) { + return c; + } + // Tiling poups + if ((c = popup_at_container(workspace, lx, ly, surface, sx, sy))) { + return c; + } + return NULL; +} + void container_for_each_descendant_dfs(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) {