diff --git a/include/sway/scene_descriptor.h b/include/sway/scene_descriptor.h index 970adaa5b..43991f771 100644 --- a/include/sway/scene_descriptor.h +++ b/include/sway/scene_descriptor.h @@ -16,6 +16,7 @@ enum sway_scene_descriptor_type { SWAY_SCENE_DESC_CONTAINER, SWAY_SCENE_DESC_VIEW, SWAY_SCENE_DESC_LAYER_SHELL, + SWAY_SCENE_DESC_POPUP, SWAY_SCENE_DESC_DRAG_ICON, }; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 4aaed9e3e..467d912f9 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -123,8 +123,6 @@ struct sway_view { struct wl_signal unmap; } events; - struct wl_listener surface_new_subsurface; - int max_render_time; // In milliseconds enum seat_config_shortcuts_inhibit shortcuts_inhibit; @@ -191,43 +189,12 @@ struct sway_xwayland_unmanaged { struct wl_listener override_redirect; }; #endif -struct sway_view_child; - -struct sway_view_child_impl { - void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy); - void (*destroy)(struct sway_view_child *child); -}; - -/** - * A view child is a surface in the view tree, such as a subsurface or a popup. - */ -struct sway_view_child { - const struct sway_view_child_impl *impl; - struct wl_list link; - - struct sway_view *view; - struct sway_view_child *parent; - struct wl_list children; // sway_view_child::link - struct wlr_surface *surface; - bool mapped; - - struct wl_listener surface_commit; - struct wl_listener surface_new_subsurface; - struct wl_listener surface_map; - struct wl_listener surface_unmap; - struct wl_listener surface_destroy; - struct wl_listener view_unmap; -}; - -struct sway_subsurface { - struct sway_view_child child; - - struct wl_listener destroy; -}; struct sway_xdg_popup { - struct sway_view_child child; + struct sway_view *view; + struct wlr_scene_tree *scene_tree; + struct wlr_scene_tree *xdg_surface_tree; struct wlr_xdg_popup *wlr_xdg_popup; struct wl_listener surface_commit; @@ -339,13 +306,6 @@ void view_unmap(struct sway_view *view); void view_update_size(struct sway_view *view); void view_center_surface(struct sway_view *view); -void view_child_init(struct sway_view_child *child, - const struct sway_view_child_impl *impl, struct sway_view *view, - struct wlr_surface *surface); - -void view_child_destroy(struct sway_view_child *child); - - struct sway_view *view_from_wlr_xdg_surface( struct wlr_xdg_surface *xdg_surface); #if HAVE_XWAYLAND diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 942bc780b..a51844847 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -289,8 +289,14 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, } struct wlr_scene_node *current = &buffer->node; - while (true) { + struct sway_view *view = scene_descriptor_try_get(current, + SWAY_SCENE_DESC_VIEW); + if (view) { + view_max_render_time = view->max_render_time; + break; + } + if (!current->parent) { break; } diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 11c112bee..fed820cf6 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -7,7 +7,7 @@ #include #include "log.h" #include "sway/decoration.h" -#include "sway/desktop.h" +#include "sway/scene_descriptor.h" #include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/input/input-manager.h" @@ -19,41 +19,29 @@ #include "sway/tree/workspace.h" #include "sway/xdg_decoration.h" -static const struct sway_view_child_impl popup_impl; +static struct sway_xdg_popup *popup_create( + struct wlr_xdg_popup *wlr_popup, struct sway_view *view, + struct wlr_scene_tree *parent); -static void popup_get_view_coords(struct sway_view_child *child, - int *sx, int *sy) { - struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; - struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; - - wlr_xdg_popup_get_toplevel_coords(wlr_popup, - wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x, - wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y, - sx, sy); +static void popup_handle_new_popup(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = + wl_container_of(listener, popup, new_popup); + struct wlr_xdg_popup *wlr_popup = data; + popup_create(wlr_popup, popup->view, popup->xdg_surface_tree); } -static void popup_destroy(struct sway_view_child *child) { - if (!sway_assert(child->impl == &popup_impl, - "Expected an xdg_shell popup")) { - return; - } - struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; - wl_list_remove(&popup->surface_commit.link); +static void popup_handle_destroy(struct wl_listener *listener, void *data) { + struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); + wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->surface_commit.link); + wlr_scene_node_destroy(&popup->scene_tree->node); free(popup); } -static const struct sway_view_child_impl popup_impl = { - .get_view_coords = popup_get_view_coords, - .destroy = popup_destroy, -}; - -static struct sway_xdg_popup *popup_create( - struct wlr_xdg_popup *wlr_popup, struct sway_view *view); - static void popup_unconstrain(struct sway_xdg_popup *popup) { - struct sway_view *view = popup->child.view; + struct sway_view *view = popup->view; struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup; struct sway_workspace *workspace = view->container->pending.workspace; @@ -83,29 +71,44 @@ static void popup_handle_surface_commit(struct wl_listener *listener, void *data } } -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, popup->child.view); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy); - view_child_destroy(&popup->child); -} - -static struct sway_xdg_popup *popup_create( - struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { +static struct sway_xdg_popup *popup_create(struct wlr_xdg_popup *wlr_popup, + struct sway_view *view, struct wlr_scene_tree *parent) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; - struct sway_xdg_popup *popup = - calloc(1, sizeof(struct sway_xdg_popup)); - if (popup == NULL) { + struct sway_xdg_popup *popup = calloc(1, sizeof(struct sway_xdg_popup)); + if (!popup) { return NULL; } - view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + popup->wlr_xdg_popup = wlr_popup; + popup->view = view; + + popup->scene_tree = wlr_scene_tree_create(parent); + if (!popup->scene_tree) { + free(popup); + return NULL; + } + + popup->xdg_surface_tree = wlr_scene_xdg_surface_create( + popup->scene_tree, xdg_surface); + if (!popup->xdg_surface_tree) { + wlr_scene_node_destroy(&popup->scene_tree->node); + free(popup); + return NULL; + } + + if (!scene_descriptor_assign(&popup->scene_tree->node, + SWAY_SCENE_DESC_POPUP, popup)) { + sway_log(SWAY_ERROR, "Failed to allocate a popup scene descriptor"); + wlr_scene_node_destroy(&popup->scene_tree->node); + free(popup); + return NULL; + } + + popup->wlr_xdg_popup = xdg_surface->popup; + struct sway_xdg_shell_view *shell_view = + wl_container_of(view, shell_view, view); + xdg_surface->data = shell_view; wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit); popup->surface_commit.notify = popup_handle_surface_commit; @@ -114,9 +117,6 @@ static struct sway_xdg_popup *popup_create( wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map); - wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap); - return popup; } @@ -317,7 +317,6 @@ static void handle_commit(struct wl_listener *listener, void *data) { // The client changed its surface size in this commit. For floating // containers, we resize the container to match. For tiling containers, // we only recenter the surface. - desktop_damage_view(view); memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); if (container_is_floating(view->container)) { view_update_size(view); @@ -330,15 +329,12 @@ static void handle_commit(struct wl_listener *listener, void *data) { } else { view_center_surface(view); } - desktop_damage_view(view); } if (view->container->node.instruction) { transaction_notify_view_ready_by_serial(view, xdg_surface->current.configure_serial); } - - view_damage_from(view); } static void handle_set_title(struct wl_listener *listener, void *data) { @@ -360,7 +356,16 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { struct sway_xdg_shell_view *xdg_shell_view = wl_container_of(listener, xdg_shell_view, new_popup); struct wlr_xdg_popup *wlr_popup = data; - popup_create(wlr_popup, &xdg_shell_view->view); + + struct sway_xdg_popup *popup = popup_create(wlr_popup, + &xdg_shell_view->view, root->layers.popup); + if (!popup) { + return; + } + + int lx, ly; + wlr_scene_node_coords(&popup->view->content_tree->node, &lx, &ly); + wlr_scene_node_set_position(&popup->scene_tree->node, lx, ly); } static void handle_request_maximize(struct wl_listener *listener, void *data) { @@ -567,5 +572,7 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { xdg_shell_view->destroy.notify = handle_destroy; wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy); + wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); + xdg_toplevel->base->data = xdg_shell_view; } diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 30df76f45..fd8f50d45 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -80,6 +80,7 @@ struct sway_node *node_at_coords( while (true) { struct sway_container *con = scene_descriptor_try_get(current, SWAY_SCENE_DESC_CONTAINER); + if (!con) { struct sway_view *view = scene_descriptor_try_get(current, SWAY_SCENE_DESC_VIEW); @@ -88,12 +89,18 @@ struct sway_node *node_at_coords( } } - if (con) { - if (!con->view || con->view->surface) { - return &con->node; + if (!con) { + struct sway_xdg_popup *popup = + scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); + if (popup) { + con = popup->view->container; } } + if (con && (!con->view || con->view->surface)) { + return &con->node; + } + if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) { // We don't want to feed through the current workspace on // layer shells diff --git a/sway/tree/view.c b/sway/tree/view.c index 7af2fd3f7..ee25faf1e 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -488,24 +488,6 @@ void view_for_each_popup_surface(struct sway_view *view, view->impl->for_each_popup_surface(view, iterator, user_data); } } - -static void view_subsurface_create(struct sway_view *view, - struct wlr_subsurface *subsurface); - -static void view_init_subsurfaces(struct sway_view *view, - struct wlr_surface *surface); - -static void view_child_init_subsurfaces(struct sway_view_child *view_child, - struct wlr_surface *surface); - -static void view_handle_surface_new_subsurface(struct wl_listener *listener, - void *data) { - struct sway_view *view = - wl_container_of(listener, view, surface_new_subsurface); - struct wlr_subsurface *subsurface = data; - view_subsurface_create(view, subsurface); -} - static bool view_has_executed_criteria(struct sway_view *view, struct criteria *criteria) { for (int i = 0; i < view->executed_criteria->length; ++i) { @@ -826,11 +808,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, } ipc_event_window(view->container, "new"); - view_init_subsurfaces(view, wlr_surface); - wl_signal_add(&wlr_surface->events.new_subsurface, - &view->surface_new_subsurface); - view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; - if (decoration) { view_update_csd_from_client(view, decoration); } @@ -897,8 +874,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, void view_unmap(struct sway_view *view) { wl_signal_emit_mutable(&view->events.unmap, view); - wl_list_remove(&view->surface_new_subsurface.link); - view->executed_criteria->length = 0; if (view->urgent_timer) { @@ -962,253 +937,6 @@ void view_center_surface(struct sway_view *view) { (con->current.content_height - view->geometry.height) / 2); } -static const struct sway_view_child_impl subsurface_impl; - -static void subsurface_get_view_coords(struct sway_view_child *child, - int *sx, int *sy) { - struct wlr_surface *surface = child->surface; - if (child->parent && child->parent->impl && - child->parent->impl->get_view_coords) { - child->parent->impl->get_view_coords(child->parent, sx, sy); - } else { - *sx = *sy = 0; - } - struct wlr_subsurface *subsurface = - wlr_subsurface_try_from_wlr_surface(surface); - *sx += subsurface->current.x; - *sy += subsurface->current.y; -} - -static void subsurface_destroy(struct sway_view_child *child) { - if (!sway_assert(child->impl == &subsurface_impl, - "Expected a subsurface")) { - return; - } - struct sway_subsurface *subsurface = (struct sway_subsurface *)child; - wl_list_remove(&subsurface->destroy.link); - free(subsurface); -} - -static const struct sway_view_child_impl subsurface_impl = { - .get_view_coords = subsurface_get_view_coords, - .destroy = subsurface_destroy, -}; - -static void subsurface_handle_destroy(struct wl_listener *listener, - void *data) { - struct sway_subsurface *subsurface = - wl_container_of(listener, subsurface, destroy); - struct sway_view_child *child = &subsurface->child; - view_child_destroy(child); -} - -static void view_child_damage(struct sway_view_child *child, bool whole); - -static void view_subsurface_create(struct sway_view *view, - struct wlr_subsurface *wlr_subsurface) { - struct sway_subsurface *subsurface = - calloc(1, sizeof(struct sway_subsurface)); - if (subsurface == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return; - } - view_child_init(&subsurface->child, &subsurface_impl, view, - wlr_subsurface->surface); - - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - subsurface->destroy.notify = subsurface_handle_destroy; - - subsurface->child.mapped = true; - - view_child_damage(&subsurface->child, true); -} - -static void view_child_subsurface_create(struct sway_view_child *child, - struct wlr_subsurface *wlr_subsurface) { - struct sway_subsurface *subsurface = - calloc(1, sizeof(struct sway_subsurface)); - if (subsurface == NULL) { - sway_log(SWAY_ERROR, "Allocation failed"); - return; - } - subsurface->child.parent = child; - wl_list_insert(&child->children, &subsurface->child.link); - view_child_init(&subsurface->child, &subsurface_impl, child->view, - wlr_subsurface->surface); - - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - subsurface->destroy.notify = subsurface_handle_destroy; - - subsurface->child.mapped = true; - - view_child_damage(&subsurface->child, true); -} - -static bool view_child_is_mapped(struct sway_view_child *child) { - while (child) { - if (!child->mapped) { - return false; - } - child = child->parent; - } - return true; -} - -static void view_child_damage(struct sway_view_child *child, bool whole) { - if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) { - return; - } - int sx, sy; - child->impl->get_view_coords(child, &sx, &sy); - desktop_damage_surface(child->surface, - child->view->container->pending.content_x - - child->view->geometry.x + sx, - child->view->container->pending.content_y - - child->view->geometry.y + sy, whole); -} - -static void view_child_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, surface_commit); - view_child_damage(child, false); -} - -static void view_child_handle_surface_new_subsurface( - struct wl_listener *listener, void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, surface_new_subsurface); - struct wlr_subsurface *subsurface = data; - view_child_subsurface_create(child, subsurface); -} - -static void view_child_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, surface_destroy); - view_child_destroy(child); -} - -static void view_init_subsurfaces(struct sway_view *view, - struct wlr_surface *surface) { - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->current.subsurfaces_below, - current.link) { - view_subsurface_create(view, subsurface); - } - wl_list_for_each(subsurface, &surface->current.subsurfaces_above, - current.link) { - view_subsurface_create(view, subsurface); - } -} - -static void view_child_init_subsurfaces(struct sway_view_child *view_child, - struct wlr_surface *surface) { - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &surface->current.subsurfaces_below, - current.link) { - view_child_subsurface_create(view_child, subsurface); - } - wl_list_for_each(subsurface, &surface->current.subsurfaces_above, - current.link) { - view_child_subsurface_create(view_child, subsurface); - } -} - -static void view_child_handle_surface_map(struct wl_listener *listener, - void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, surface_map); - child->mapped = true; - view_child_damage(child, true); -} - -static void view_child_handle_surface_unmap(struct wl_listener *listener, - void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, surface_unmap); - view_child_damage(child, true); - child->mapped = false; -} - -static void view_child_handle_view_unmap(struct wl_listener *listener, - void *data) { - struct sway_view_child *child = - wl_container_of(listener, child, view_unmap); - view_child_damage(child, true); - child->mapped = false; -} - -void view_child_init(struct sway_view_child *child, - const struct sway_view_child_impl *impl, struct sway_view *view, - struct wlr_surface *surface) { - child->impl = impl; - child->view = view; - child->surface = surface; - wl_list_init(&child->children); - - wl_signal_add(&surface->events.commit, &child->surface_commit); - child->surface_commit.notify = view_child_handle_surface_commit; - wl_signal_add(&surface->events.new_subsurface, - &child->surface_new_subsurface); - child->surface_new_subsurface.notify = - view_child_handle_surface_new_subsurface; - wl_signal_add(&surface->events.destroy, &child->surface_destroy); - child->surface_destroy.notify = view_child_handle_surface_destroy; - - // Not all child views have a map/unmap event - child->surface_map.notify = view_child_handle_surface_map; - wl_list_init(&child->surface_map.link); - child->surface_unmap.notify = view_child_handle_surface_unmap; - wl_list_init(&child->surface_unmap.link); - - wl_signal_add(&view->events.unmap, &child->view_unmap); - child->view_unmap.notify = view_child_handle_view_unmap; - - struct sway_container *container = child->view->container; - if (container != NULL) { - struct sway_workspace *workspace = container->pending.workspace; - if (workspace) { - surface_enter_output(child->surface, workspace->output); - } - } - - view_child_init_subsurfaces(child, surface); -} - -void view_child_destroy(struct sway_view_child *child) { - if (view_child_is_mapped(child) && child->view->container != NULL) { - view_child_damage(child, true); - } - - if (child->parent != NULL) { - wl_list_remove(&child->link); - child->parent = NULL; - } - - struct sway_view_child *subchild, *tmpchild; - wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { - wl_list_remove(&subchild->link); - subchild->parent = NULL; - // The subchild lost its parent link, so it cannot see that the parent - // is unmapped. Unmap it directly. - subchild->mapped = false; - } - - wl_list_remove(&child->surface_commit.link); - wl_list_remove(&child->surface_destroy.link); - wl_list_remove(&child->surface_map.link); - wl_list_remove(&child->surface_unmap.link); - wl_list_remove(&child->view_unmap.link); - wl_list_remove(&child->surface_new_subsurface.link); - - if (child->impl && child->impl->destroy) { - child->impl->destroy(child); - } else { - free(child); - } -} - struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { struct wlr_xdg_surface *xdg_surface; if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) {