diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 527d03500..527218dc8 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 27b5dde1b..1b24e2911 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -37,9 +37,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); void destroy_layers(struct sway_output *output); diff --git a/include/sway/scene_descriptor.h b/include/sway/scene_descriptor.h index 2649d7c29..e71b5c42a 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 ae81c5bbf..69dd397f1 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; @@ -194,11 +195,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; struct wlr_xdg_popup *wlr_xdg_popup; diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 15373d5a8..e160d583b 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -620,7 +620,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 8c54d71aa..af78fa0a4 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, bool exclusive) { struct wlr_scene_node *node; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 12dc9cc7a..ce12a97cb 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -158,20 +158,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 fc0f11fd8..d478b7299 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -32,15 +32,8 @@ #include "sway/tree/workspace.h" #include "wlr-layer-shell-unstable-v1-protocol.h" -/** - * 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); @@ -51,69 +44,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); + 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_view *view = scene_descriptor_try_get(current, - SWAY_SCENE_DESC_VIEW); - if (view) { - con = view->container; - } - } + if (scene_surface) { + return scene_surface->surface; + } - if (!con) { - struct sway_popup_desc *popup = - scene_descriptor_try_get(current, SWAY_SCENE_DESC_POPUP); - if (popup && popup->view) { - con = popup->view->container; - } - } + return NULL; +} - 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 +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; } + return &con->node; + } + + // 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; + } + #if WLR_HAS_XWAYLAND - if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { - return NULL; - } -#endif - - if (!current->parent) { - break; - } - - current = ¤t->parent->node; + 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 @@ -137,6 +119,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_in_msec(); seatop_rebase(cursor->seat, time_msec); @@ -299,8 +293,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; @@ -559,7 +552,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 df8232afc..de7d837b7 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -224,7 +224,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, @@ -335,10 +335,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; @@ -380,10 +382,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) { @@ -548,16 +550,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; } @@ -605,8 +605,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); @@ -634,8 +634,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); @@ -663,7 +663,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)) { @@ -715,7 +715,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; @@ -1107,8 +1107,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) && !cursor->hidden) { diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index f64e5a4f2..dd750f571 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 c525b77a9..eca243622 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 92bdda00c..ca0003058 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); @@ -67,3 +92,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 c9ec852fc..64e9c4bcf 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -518,6 +518,7 @@ 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 eab2a5e2b..ab81d8c58 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -771,6 +771,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);