From e84166a734c5c05b5b473520ffe82360aa95e1e2 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 2 Jun 2018 12:58:24 +1000 Subject: [PATCH 1/5] Fix popup rendering order and popup container_at issues This adds proper support for popups overhanging their swayc bounds. For locating a surface at a given coordinate, it iterates all the floating popups first, then floating toplevels and decorations, then tiled popups, then tiled toplevels and decorations. For rendering popups, it renders all toplevels and decorations first, then popups afterwards. --- include/sway/tree/container.h | 12 +-- sway/desktop/output.c | 58 ++++++++++++++- sway/input/cursor.c | 2 +- sway/tree/container.c | 133 +++++++++++++++++++++++++--------- 4 files changed, 159 insertions(+), 46 deletions(-) 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) { From 476dcc5bd9c7040fabb928dedc3d171db0cbd59b Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 3 Jun 2018 22:48:51 +1000 Subject: [PATCH 2/5] Handle empty tabbed/stacked containers when looking for popups --- sway/tree/container.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index fdeae2b56..37d6f8d39 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -681,10 +681,12 @@ static struct sway_container *popup_at_container(struct sway_container *parent, 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; + if (child) { + 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) { From b4ed80eabf99ec0d8ce8cbae77f0b4ba7fc6d4a7 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sun, 3 Jun 2018 22:58:26 +1000 Subject: [PATCH 3/5] Fix xwayland popups not rendering --- sway/desktop/output.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 09e5424f4..fdeec5f1a 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -219,11 +219,6 @@ damage_finish: } 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); @@ -234,7 +229,10 @@ static bool surface_is_popup(struct wlr_surface *surface) { wlr_xdg_surface_v6_from_wlr_surface(surface); return xdg_surface_v6->role == WLR_XDG_SURFACE_V6_ROLE_POPUP; } - // Layer surface + // Anything else will either be a layer surface, an xwayland managed surface + // or an xwayland unmanaged surface. Xwayland unmanaged surfaces are + // rendered specially and expect the surface to NOT identify as a popup. + // The other two are not popups. return false; } From 250367259f0a6ec5635cd459d4ba12493bbcca10 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 5 Jun 2018 21:48:19 +1000 Subject: [PATCH 4/5] Only check popups for focused views --- include/sway/tree/container.h | 7 -- sway/desktop/output.c | 93 ++++++++++-------------- sway/input/cursor.c | 3 - sway/tree/container.c | 130 +++++++++++++--------------------- 4 files changed, 84 insertions(+), 149 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index f37bbd793..a1e721d6e 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -173,13 +173,6 @@ 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 for popups only. - */ -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 fdeec5f1a..bea801d48 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -69,8 +69,9 @@ struct render_data { struct root_geometry root_geo; struct sway_output *output; pixman_region32_t *damage; + struct sway_view *view; + bool only_popups; float alpha; - bool render_popups; }; static bool get_surface_box(struct root_geometry *geo, @@ -218,28 +219,10 @@ damage_finish: pixman_region32_fini(&damage); } -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; - } - // Anything else will either be a layer surface, an xwayland managed surface - // or an xwayland unmanaged surface. Xwayland unmanaged surfaces are - // rendered specially and expect the surface to NOT identify as a popup. - // The other two are not popups. - return false; -} - -static void render_surface_iterator(struct wlr_surface *surface, int sx, int sy, +static void render_surface(struct wlr_surface *surface, int sx, int sy, void *_data) { struct render_data *data = _data; - if (surface_is_popup(surface) != data->render_popups) { + if (data->only_popups && surface == data->view->surface) { return; } struct wlr_output *wlr_output = data->output->wlr_output; @@ -278,7 +261,7 @@ static void render_layer(struct sway_output *output, .alpha = 1.0f, }; layer_for_each_surface(layer_surfaces, &data.root_geo, - render_surface_iterator, &data); + render_surface, &data); } static void render_unmanaged(struct sway_output *output, @@ -289,7 +272,7 @@ static void render_unmanaged(struct sway_output *output, .alpha = 1.0f, }; unmanaged_for_each_surface(unmanaged, output, &data.root_geo, - render_surface_iterator, &data); + render_surface, &data); } static void render_rect(struct wlr_output *wlr_output, @@ -332,17 +315,16 @@ static void premultiply_alpha(float color[4], float opacity) { color[2] *= color[3]; } -static void render_view_surfaces(struct sway_view *view, - struct sway_output *output, pixman_region32_t *damage, - float alpha, bool popups) { +static void render_view_popups(struct sway_view *view, + struct sway_output *output, pixman_region32_t *damage, float alpha) { struct render_data data = { .output = output, .damage = damage, .alpha = alpha, - .render_popups = popups, + .view = view, + .only_popups = true, }; - output_view_for_each_surface( - view, &data.root_geo, render_surface_iterator, &data); + output_view_for_each_surface(view, &data.root_geo, render_surface, &data); } /** @@ -351,7 +333,17 @@ 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, false); + + // 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); struct wlr_box box; float output_scale = output->wlr_output->scale; @@ -857,26 +849,6 @@ 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; @@ -921,12 +893,16 @@ 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, false); - render_view_surfaces(workspace->sway_workspace->fullscreen, - output, damage, 1.0f, true); + 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); - if (workspace->sway_workspace->fullscreen->type == SWAY_VIEW_XWAYLAND) { + if (view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, &root_container.sway_root->xwayland_unmanaged); } @@ -948,9 +924,12 @@ 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); + + 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_unmanaged(output, damage, &root_container.sway_root->xwayland_unmanaged); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 1ca1bd171..954014569 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -108,9 +108,6 @@ static struct sway_container *container_at_coords( } struct sway_container *c; - if ((c = popup_at(ws, lx, ly, surface, sx, sy))) { - return c; - } if ((c = container_at(ws, lx, ly, surface, sx, sy))) { return c; } diff --git a/sway/tree/container.c b/sway/tree/container.c index 37d6f8d39..e3e98df36 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -476,7 +476,7 @@ struct sway_container *container_parent(struct sway_container *container, 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) { + double *sx, double *sy) { if (!sway_assert(swayc->type == C_VIEW, "Expected a view")) { return NULL; } @@ -490,13 +490,6 @@ static struct sway_container *surface_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 @@ -507,13 +500,6 @@ static struct sway_container *surface_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 @@ -524,24 +510,15 @@ static struct sway_container *surface_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) { *sx = _sx; *sy = _sy; *surface = _surface; + return swayc; } - if (only_popups && !_surface) { - return NULL; - } - return swayc; + return NULL; } static struct sway_container *container_at_container( @@ -603,7 +580,10 @@ static struct sway_container *container_at_stacked( } /** - * container_at for a container with layout L_HORIZ or L_VERT. + * container_at for a container with layout L_HORIZ, L_VERT or L_FLOATING. + * + * Iterates the children, does a box check and descends into the child if it + * passes. */ static struct sway_container *container_at_linear(struct sway_container *parent, double lx, double ly, @@ -627,7 +607,8 @@ static struct sway_container *container_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, false); + surface_at_view(parent, lx, ly, surface, sx, sy); + return parent; } if (!parent->children->length) { return NULL; @@ -643,28 +624,61 @@ static struct sway_container *container_at_container( return container_at_stacked(parent, lx, ly, surface, sx, sy); case L_FLOATING: sway_assert(false, "Didn't expect to see floating here"); - return NULL; + // We can recover from this situation + return container_at_linear(parent, lx, ly, surface, sx, sy); case L_NONE: return NULL; } return NULL; } +/** + * Iterate all visible workspaces and run container_at for each floating + * container. + */ +static struct sway_container *floating_container_at(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 *ws = output->children->items[j]; + if (!workspace_is_visible(ws)) { + continue; + } + struct sway_container *c = container_at_linear( + ws->sway_workspace->floating, lx, ly, surface, sx, sy); + if (c) { + return c; + } + } + } + return NULL; +} + struct sway_container *container_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 *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))) { + // Focused view's popups + struct sway_seat *seat = input_manager_current_seat(input_manager); + struct sway_container *focus = + 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 + *surface = NULL; + } else if (c) { return c; } } + // Floating + if ((c = floating_container_at(lx, ly, surface, sx, sy))) { + return c; + } // Tiling if ((c = container_at_container(workspace, lx, ly, surface, sx, sy))) { return c; @@ -672,54 +686,6 @@ struct sway_container *container_at(struct sway_container *workspace, 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); - if (child) { - 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) { From dad4e099f151a96370ab0697dd71224fe7108906 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 5 Jun 2018 23:19:01 +1000 Subject: [PATCH 5/5] Differentiate popups from subsurfaces for rendering and container_at --- sway/desktop/output.c | 58 +++++++++++++++++++++---------------------- sway/tree/container.c | 17 +++++++++++-- 2 files changed, 44 insertions(+), 31 deletions(-) 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;