diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 527d03500c..527218dc89 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -84,9 +84,16 @@ struct sway_cursor { struct sway_node; +struct wlr_scene_node *scene_node_at_coords( + double lx, double ly, double *sx, double *sy); + +struct wlr_surface *surface_try_from_scene_node(struct wlr_scene_node *node); + +struct sway_node *sway_node_try_from_scene_node(struct wlr_scene_node *node, + double lx, double ly); + struct sway_node *node_at_coords( - struct sway_seat *seat, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy); + double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); void sway_cursor_destroy(struct sway_cursor *cursor); struct sway_cursor *sway_cursor_create(struct sway_seat *seat); diff --git a/include/sway/layers.h b/include/sway/layers.h index fd6384e0ee..7627c9091e 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -36,9 +36,6 @@ struct sway_layer_popup { struct sway_output; -struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( - struct wlr_surface *surface); - void arrange_layers(struct sway_output *output); #endif diff --git a/include/sway/scene_descriptor.h b/include/sway/scene_descriptor.h index 2649d7c296..e71b5c42a8 100644 --- a/include/sway/scene_descriptor.h +++ b/include/sway/scene_descriptor.h @@ -10,6 +10,14 @@ #define _SWAY_SCENE_DESCRIPTOR_H #include +struct sway_view; + +// used for SWAY_SCENE_DESC_POPUP +struct sway_popup_desc { + struct wlr_scene_node *relative; + struct sway_view *view; +}; + enum sway_scene_descriptor_type { SWAY_SCENE_DESC_BUFFER_TIMER, SWAY_SCENE_DESC_NON_INTERACTIVE, @@ -24,10 +32,23 @@ enum sway_scene_descriptor_type { bool scene_descriptor_assign(struct wlr_scene_node *node, enum sway_scene_descriptor_type type, void *data); +bool scene_descriptor_reassign(struct wlr_scene_node *node, + enum sway_scene_descriptor_type type, void *data); + void *scene_descriptor_try_get(struct wlr_scene_node *node, enum sway_scene_descriptor_type type); void scene_descriptor_destroy(struct wlr_scene_node *node, enum sway_scene_descriptor_type type); +/* + * Searches the scene node and all its parents for this scene descriptor. + * + * Note that while searching, SWAY_SCENE_DESC_POPUP types will start tracking + * its relative node. With popups, they are part of a seperate layer in the scene + * graph, but that's irrelavent to users of this function. + */ +void *scene_descriptor_find(struct wlr_scene_node *node, + enum sway_scene_descriptor_type type); + #endif diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 14aad1a183..22efbfc640 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -11,6 +11,7 @@ #endif #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/scene_descriptor.h" struct sway_container; struct sway_xdg_decoration; @@ -187,11 +188,6 @@ struct sway_xwayland_unmanaged { }; #endif -struct sway_popup_desc { - struct wlr_scene_node *relative; - struct sway_view *view; -}; - struct sway_xdg_popup { struct sway_view *view; diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 268f285537..8361a06f6b 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -621,7 +621,7 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) || binding->type == BINDING_MOUSECODE) { struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, + struct sway_node *node = node_at_coords( seat->cursor->cursor->x, seat->cursor->cursor->y, &surface, &sx, &sy); if (node && node->type == N_CONTAINER) { diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index b136a24e7b..f52db2e418 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -20,39 +20,6 @@ #include "sway/tree/arrange.h" #include "sway/tree/workspace.h" -struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface( - struct wlr_surface *surface) { - struct wlr_layer_surface_v1 *layer; - do { - if (!surface) { - return NULL; - } - // Topmost layer surface - if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) { - return layer; - } - // Layer subsurface - if (wlr_subsurface_try_from_wlr_surface(surface)) { - surface = wlr_surface_get_root_surface(surface); - continue; - } - - // Layer surface popup - struct wlr_xdg_surface *xdg_surface = NULL; - if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface)) && - xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL) { - if (!xdg_surface->popup->parent) { - return NULL; - } - surface = wlr_surface_get_root_surface(xdg_surface->popup->parent); - continue; - } - - // Return early if the surface is not a layer/xdg_popup/sub surface - return NULL; - } while (true); -} - static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area, struct wlr_box *usable_area, struct wlr_scene_tree *tree) { struct wlr_scene_node *node; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index a71430fe52..ae49b649ba 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -151,20 +151,9 @@ static void send_frame_done_iterator(struct wlr_scene_buffer *buffer, return; } - 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; - } - - current = ¤t->parent->node; + struct sway_view *view = scene_descriptor_find(&buffer->node, SWAY_SCENE_DESC_VIEW); + if (view) { + view_max_render_time = view->max_render_time; } int delay = data->msec_until_refresh - output->max_render_time diff --git a/sway/input/cursor.c b/sway/input/cursor.c index bbd16717ff..068390f9f3 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -38,15 +38,8 @@ static uint32_t get_current_time_msec(void) { return now.tv_sec * 1000 + now.tv_nsec / 1000000; } -/** - * Returns the node at the cursor's position. If there is a surface at that - * location, it is stored in **surface (it may not be a view). - */ -struct sway_node *node_at_coords( - struct sway_seat *seat, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy) { - struct wlr_scene_node *scene_node = NULL; - +struct wlr_scene_node *scene_node_at_coords( + double lx, double ly, double *sx, double *sy) { struct wlr_scene_node *node; wl_list_for_each_reverse(node, &root->layer_tree->children, link) { struct wlr_scene_tree *layer = wlr_scene_tree_from_node(node); @@ -57,69 +50,58 @@ struct sway_node *node_at_coords( continue; } - scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy); - if (scene_node) { - break; + struct wlr_scene_node *node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy); + if (node) { + return node; } } - if (scene_node) { - // determine what wlr_surface we clicked on - if (scene_node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *scene_buffer = - wlr_scene_buffer_from_node(scene_node); - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_try_from_buffer(scene_buffer); + return NULL; +} - if (scene_surface) { - *surface = scene_surface->surface; - } - } +struct wlr_surface *surface_try_from_scene_node(struct wlr_scene_node *node) { + if (!node || node->type != WLR_SCENE_NODE_BUFFER) { + return NULL; + } - // determine what container we clicked on - struct wlr_scene_node *current = scene_node; - 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); - if (view) { - con = view->container; - } - } + struct wlr_scene_buffer *scene_buffer = + wlr_scene_buffer_from_node(node); + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_try_from_buffer(scene_buffer); - if (!con) { - struct sway_popup_desc *popup = - scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); - if (popup && popup->view) { - con = popup->view->container; - } - } + if (scene_surface) { + return scene_surface->surface; + } - if (con && (!con->view || con->view->surface)) { - return &con->node; - } + return NULL; +} - if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_LAYER_SHELL)) { - // We don't want to feed through the current workspace on - // layer shells +struct sway_node *sway_node_try_from_scene_node(struct wlr_scene_node *node, + double lx, double ly) { + if (node) { + struct sway_container *con = + scene_descriptor_find(node, SWAY_SCENE_DESC_CONTAINER); + if (con) { + // If this condition succeeds, the container is currently in the + // process of being destroyed. In this case, ignore the container + if (con->view && !con->view->surface) { return NULL; } -#if WLR_HAS_XWAYLAND - if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { - return NULL; - } -#endif + return &con->node; + } - if (!current->parent) { - break; - } + // if we clicked on a layer shell or unmanaged xwayland we don't + // want to return the workspace node. + if (scene_descriptor_find(node, SWAY_SCENE_DESC_LAYER_SHELL)) { + return NULL; + } - current = ¤t->parent->node; +#if WLR_HAS_XWAYLAND + if (scene_descriptor_find(node, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { + return NULL; } +#endif } // if we aren't on a container, determine what workspace we are on @@ -143,6 +125,18 @@ struct sway_node *node_at_coords( return &ws->node; } +/** + * Returns the node at the cursor's position. If there is a surface at that + * location, it is stored in **surface (it may not be a view). + */ +struct sway_node *node_at_coords(double lx, double ly, + struct wlr_surface **surface, double *sx, double *sy) { + struct wlr_scene_node *scene_node = scene_node_at_coords(lx, ly, sx, sy); + *surface = surface_try_from_scene_node(scene_node); + + return sway_node_try_from_scene_node(scene_node, lx, ly); +} + void cursor_rebase(struct sway_cursor *cursor) { uint32_t time_msec = get_current_time_msec(); seatop_rebase(cursor->seat, time_msec); @@ -305,8 +299,7 @@ void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, if (cursor->active_constraint && device->type == WLR_INPUT_DEVICE_POINTER) { struct wlr_surface *surface = NULL; double sx, sy; - node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + node_at_coords(cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (cursor->active_constraint->surface != surface) { return; @@ -565,7 +558,7 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor, double sx, sy; struct wlr_surface *surface = NULL; struct sway_seat *seat = cursor->seat; - node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + node_at_coords(cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); // The logic for whether we should send a tablet event or an emulated pointer // event is tricky. It comes down to: @@ -655,8 +648,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { double sx, sy; struct wlr_surface *surface = NULL; - node_at_coords(seat, cursor->cursor->x, cursor->cursor->y, - &surface, &sx, &sy); + node_at_coords(cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (cursor->simulating_pointer_from_tool_tip && event->state == WLR_TABLET_TOOL_TIP_UP) { @@ -740,8 +732,7 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { double sx, sy; struct wlr_surface *surface = NULL; - node_at_coords(cursor->seat, cursor->cursor->x, cursor->cursor->y, - &surface, &sx, &sy); + node_at_coords(cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); // TODO: floating resize should support graphics tablet events struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index 42ce333b86..fb58db8afe 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -223,7 +223,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, struct sway_cursor *cursor = seat->cursor; struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, + struct sway_node *node = node_at_coords( cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (!sway_assert(surface, @@ -334,10 +334,12 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, struct sway_cursor *cursor = seat->cursor; // Determine what's under the cursor - struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct wlr_scene_node *scene_node = + scene_node_at_coords(cursor->cursor->x, cursor->cursor->y, &sx, &sy); + struct wlr_surface *surface = scene_node ? surface_try_from_scene_node(scene_node) : NULL; + struct sway_node *node = sway_node_try_from_scene_node(scene_node, + cursor->cursor->x, cursor->cursor->y); struct sway_container *cont = node && node->type == N_CONTAINER ? node->sway_container : NULL; @@ -372,10 +374,10 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, } // Handle clicking a layer surface and its popups/subsurfaces - struct wlr_layer_surface_v1 *layer = NULL; - if ((layer = toplevel_layer_surface_from_surface(surface))) { - if (layer->current.keyboard_interactive) { - seat_set_focus_layer(seat, layer); + struct sway_layer_surface *layer = NULL; + if ((layer = scene_descriptor_find(scene_node, SWAY_SCENE_DESC_LAYER_SHELL))) { + if (layer->layer_surface->current.keyboard_interactive) { + seat_set_focus_layer(seat, layer->layer_surface); transaction_commit_dirty(); } if (state == WL_POINTER_BUTTON_STATE_PRESSED) { @@ -550,16 +552,14 @@ static void check_focus_follows_mouse(struct sway_seat *seat, return; } - struct wlr_surface *surface = NULL; - double sx, sy; - node_at_coords(seat, seat->cursor->cursor->x, seat->cursor->cursor->y, - &surface, &sx, &sy); + struct wlr_scene_node *node = scene_node_at_coords( + seat->cursor->cursor->x, seat->cursor->cursor->y, NULL, NULL); // Focus topmost layer surface - struct wlr_layer_surface_v1 *layer = NULL; - if ((layer = toplevel_layer_surface_from_surface(surface)) && - layer->current.keyboard_interactive) { - seat_set_focus_layer(seat, layer); + struct sway_layer_surface *layer = NULL; + if ((layer = scene_descriptor_find(node, SWAY_SCENE_DESC_LAYER_SHELL)) && + layer->layer_surface->current.keyboard_interactive) { + seat_set_focus_layer(seat, layer->layer_surface); transaction_commit_dirty(); return; } @@ -607,8 +607,8 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct sway_node *node = node_at_coords( + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (config->focus_follows_mouse != FOLLOWS_NO) { check_focus_follows_mouse(seat, e, node); @@ -636,8 +636,8 @@ static void handle_tablet_tool_motion(struct sway_seat *seat, struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct sway_node *node = node_at_coords( + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (config->focus_follows_mouse != FOLLOWS_NO) { check_focus_follows_mouse(seat, e, node); @@ -665,7 +665,7 @@ static void handle_touch_down(struct sway_seat *seat, struct wlr_seat *wlr_seat = seat->wlr_seat; struct sway_cursor *cursor = seat->cursor; double sx, sy; - node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy); + node_at_coords(seat->touch_x, seat->touch_y, &surface, &sx, &sy); if (surface && wlr_surface_accepts_touch(surface, wlr_seat)) { if (seat_is_input_allowed(seat, surface)) { @@ -717,7 +717,7 @@ static void handle_pointer_axis(struct sway_seat *seat, // Determine what's under the cursor struct wlr_surface *surface = NULL; double sx, sy; - struct sway_node *node = node_at_coords(seat, + struct sway_node *node = node_at_coords( cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); struct sway_container *cont = node && node->type == N_CONTAINER ? node->sway_container : NULL; @@ -1109,8 +1109,8 @@ static void handle_rebase(struct sway_seat *seat, uint32_t time_msec) { struct sway_cursor *cursor = seat->cursor; struct wlr_surface *surface = NULL; double sx = 0.0, sy = 0.0; - e->previous_node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + e->previous_node = node_at_coords( + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (surface) { if (seat_is_input_allowed(seat, surface)) { diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 340e334bfd..b79888de11 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -75,7 +75,7 @@ static void handle_touch_down(struct sway_seat *seat, struct seatop_down_event *e = seat->seatop_data; double sx, sy; struct wlr_surface *surface = NULL; - struct sway_node *focused_node = node_at_coords(seat, seat->touch_x, + struct sway_node *focused_node = node_at_coords(seat->touch_x, seat->touch_y, &surface, &sx, &sy); if (!surface || surface != e->surface) { // Must start from the initial surface diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index c525b77a9e..eca2436221 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -163,8 +163,8 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { struct wlr_surface *surface = NULL; double sx, sy; struct sway_cursor *cursor = seat->cursor; - struct sway_node *node = node_at_coords(seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + struct sway_node *node = node_at_coords( + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); if (!node) { // Eg. hovered over a layer surface such as swaybar diff --git a/sway/scene_descriptor.c b/sway/scene_descriptor.c index a30d466466..2f03fc59c8 100644 --- a/sway/scene_descriptor.c +++ b/sway/scene_descriptor.c @@ -36,6 +36,31 @@ void *scene_descriptor_try_get(struct wlr_scene_node *node, return desc->data; } +void *scene_descriptor_find(struct wlr_scene_node *node, + enum sway_scene_descriptor_type type) { + while (node) { + struct scene_descriptor *desc = scene_node_get_descriptor(node, type); + if (desc) { + return desc->data; + } + + struct sway_popup_desc *popup = + scene_descriptor_try_get(node, SWAY_SCENE_DESC_POPUP); + if (popup) { + node = popup->relative; + continue; + } + + if (!node->parent) { + break; + } + + node = &node->parent->node; + } + + return NULL; +} + void scene_descriptor_destroy(struct wlr_scene_node *node, enum sway_scene_descriptor_type type) { struct scene_descriptor *desc = scene_node_get_descriptor(node, type); @@ -64,3 +89,14 @@ bool scene_descriptor_assign(struct wlr_scene_node *node, desc->data = data; return true; } + +bool scene_descriptor_reassign(struct wlr_scene_node *node, + enum sway_scene_descriptor_type type, void *data) { + struct scene_descriptor *desc = scene_node_get_descriptor(node, type); + if (desc) { + desc->data = data; + return true; + } + + return scene_descriptor_assign(node, type, data); +} diff --git a/sway/tree/container.c b/sway/tree/container.c index 46c388b3ee..8f1607217d 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -506,6 +506,8 @@ void container_destroy(struct sway_container *con) { if (con->view && con->view->container == con) { con->view->container = NULL; + scene_descriptor_destroy(&con->view->scene_tree->node, SWAY_SCENE_DESC_CONTAINER); + wlr_scene_node_destroy(&con->output_handler->node); if (con->view->destroying) { view_destroy(con->view); diff --git a/sway/tree/view.c b/sway/tree/view.c index d25a09c2a2..a287e81c44 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -723,6 +723,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, view->surface = wlr_surface; view_populate_pid(view); view->container = container_create(view); + scene_descriptor_assign(&view->scene_tree->node, + SWAY_SCENE_DESC_CONTAINER, view->container); if (view->ctx == NULL) { struct launcher_ctx *ctx = launcher_ctx_find_pid(view->pid);