From 250367259f0a6ec5635cd459d4ba12493bbcca10 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Tue, 5 Jun 2018 21:48:19 +1000 Subject: [PATCH] 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) {