diff --git a/sway/desktop/output.c b/sway/desktop/output.c index bea801d48..3105a14f2 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -69,8 +69,7 @@ struct render_data { struct root_geometry root_geo; struct sway_output *output; pixman_region32_t *damage; - struct sway_view *view; - bool only_popups; + bool popups; float alpha; }; @@ -219,10 +218,24 @@ damage_finish: pixman_region32_fini(&damage); } -static void render_surface(struct wlr_surface *surface, int sx, int sy, +static bool surface_is_popup(struct wlr_surface *surface) { + 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; + } + return false; +} + +static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, void *_data) { struct render_data *data = _data; - if (data->only_popups && surface == data->view->surface) { + if (data->popups != surface_is_popup(surface)) { return; } struct wlr_output *wlr_output = data->output->wlr_output; @@ -261,7 +274,7 @@ static void render_layer(struct sway_output *output, .alpha = 1.0f, }; layer_for_each_surface(layer_surfaces, &data.root_geo, - render_surface, &data); + render_surface_iterator, &data); } static void render_unmanaged(struct sway_output *output, @@ -272,7 +285,7 @@ static void render_unmanaged(struct sway_output *output, .alpha = 1.0f, }; unmanaged_for_each_surface(unmanaged, output, &data.root_geo, - render_surface, &data); + render_surface_iterator, &data); } static void render_rect(struct wlr_output *wlr_output, @@ -315,16 +328,17 @@ static void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_popups(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, float alpha) { +static void render_view_surfaces(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha, + bool popups) { struct render_data data = { .output = output, .damage = damage, .alpha = alpha, - .view = view, - .only_popups = true, + .popups = popups, }; - output_view_for_each_surface(view, &data.root_geo, render_surface, &data); + output_view_for_each_surface(view, &data.root_geo, + render_surface_iterator, &data); } /** @@ -334,16 +348,7 @@ 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; - // We'll only render the view's primary surface here. - // Popups need to be rendered too, but only for the focused view, and they - // need to render on top of everything else so we do them separately. - struct render_data data = { - .output = output, - .damage = damage, - .alpha = view->swayc->alpha, - }; - render_surface(view->surface, view->x - output->swayc->x, - view->y - output->swayc->y, &data); + render_view_surfaces(view, output, damage, con->alpha, false); struct wlr_box box; float output_scale = output->wlr_output->scale; @@ -894,13 +899,8 @@ static void render_output(struct sway_output *output, struct timespec *when, // TODO: handle views smaller than the output struct sway_view *view = workspace->sway_workspace->fullscreen; - struct render_data data = { - .output = output, - .damage = damage, - .alpha = 1.0f, - }; - output_view_for_each_surface( - view, &data.root_geo, render_surface, &data); + render_view_surfaces(view, output, damage, 1.0f, false); + render_view_surfaces(view, output, damage, 1.0f, true); if (view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, @@ -928,7 +928,7 @@ static void render_output(struct sway_output *output, struct timespec *when, focus = seat_get_focus_inactive(seat, &root_container); if (focus && focus->type == C_VIEW) { - render_view_popups(focus->sway_view, output, damage, 1.0f); + render_view_surfaces(focus->sway_view, output, damage, 1.0f, true); } render_unmanaged(output, damage, diff --git a/sway/tree/container.c b/sway/tree/container.c index e3e98df36..e7a062d26 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -655,6 +655,20 @@ static struct sway_container *floating_container_at(double lx, double ly, return NULL; } +static bool surface_is_popup(struct wlr_surface *surface) { + 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; + } + return false; +} + struct sway_container *container_at(struct sway_container *workspace, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { @@ -668,8 +682,7 @@ struct sway_container *container_at(struct sway_container *workspace, seat_get_focus_inactive(seat, &root_container); if (focus && focus->type == C_VIEW) { c = surface_at_view(focus, lx, ly, surface, sx, sy); - if (*surface && *surface == focus->sway_view->surface) { - // Not a popup + if (*surface && !surface_is_popup(*surface)) { *surface = NULL; } else if (c) { return c;