diff --git a/include/labwc.h b/include/labwc.h index ac90a521..8dae3cf9 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -499,37 +499,41 @@ struct view *desktop_focused_view(struct server *server); void desktop_focus_topmost_mapped_view(struct server *server); bool isfocusable(struct view *view); +struct cursor_context { + struct view *view; + struct wlr_scene_node *node; + struct wlr_surface *surface; + enum ssd_part_type type; + double sx, sy; +}; + /** - * desktop_node_and_view_at - find view and scene_node at (lx, ly) + * get_cursor_context - find view and scene_node at cursor * * Behavior if node points to a surface: - * - If surface is a layer-surface, *view_area will be + * - If surface is a layer-surface, type will be * set to LAB_SSD_LAYER_SURFACE and view will be NULL. * * - If surface is a 'lost' unmanaged xsurface (one - * with a never-mapped parent view), *view_area will + * with a never-mapped parent view), type will * be set to LAB_SSD_UNMANAGED and view will be NULL. * * 'Lost' unmanaged xsurfaces are usually caused by * X11 applications opening popups without setting * the main window as parent. Example: VLC submenus. * - * - Any other surface will cause *view_area be set to + * - Any other surface will cause type to be set to * LAB_SSD_CLIENT and return the attached view. * * Behavior if node points to internal elements: - * - *view_area will be set to the appropiate enum value + * - type will be set to the appropriate enum value * and view will be NULL if the node is not part of the SSD. * * If no node is found for the given layout coordinates, - * *view_area will be set to LAB_SSD_ROOT and view will be NULL. + * type will be set to LAB_SSD_ROOT and view will be NULL. * */ -struct view *desktop_node_and_view_at(struct server *server, double lx, - double ly, struct wlr_scene_node **scene_node, double *sx, double *sy, - enum ssd_part_type *view_area); - -struct view *desktop_view_at_cursor(struct server *server); +struct cursor_context get_cursor_context(struct server *server); /** * cursor_set - set cursor icon diff --git a/src/action.c b/src/action.c index 9604c306..d6782c02 100644 --- a/src/action.c +++ b/src/action.c @@ -275,7 +275,7 @@ actions_run(struct view *activator, struct server *server, } break; case ACTION_TYPE_FOCUS: - view = desktop_view_at_cursor(server); + view = get_cursor_context(server).view; if (view) { desktop_focus_and_activate_view(&server->seat, view); } @@ -286,7 +286,7 @@ actions_run(struct view *activator, struct server *server, } break; case ACTION_TYPE_MOVE: - view = desktop_view_at_cursor(server); + view = get_cursor_context(server).view; if (view) { interactive_begin(view, LAB_INPUT_STATE_MOVE, 0); } @@ -297,7 +297,7 @@ actions_run(struct view *activator, struct server *server, } break; case ACTION_TYPE_RESIZE: - view = desktop_view_at_cursor(server); + view = get_cursor_context(server).view; if (view) { interactive_begin(view, LAB_INPUT_STATE_RESIZE, resize_edges); diff --git a/src/cursor.c b/src/cursor.c index 8b08b978..c58bd52f 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -34,17 +34,6 @@ static const struct cursor_alias { { "w-resize", "left_side" }, }; -static bool -is_surface(enum ssd_part_type view_area) -{ - return view_area == LAB_SSD_CLIENT - || view_area == LAB_SSD_LAYER_SURFACE -#if HAVE_XWAYLAND - || view_area == LAB_SSD_UNMANAGED -#endif - ; -} - static struct wlr_surface * get_toplevel(struct wlr_surface *surface) { @@ -254,8 +243,7 @@ input_inhibit_blocks_surface(struct seat *seat, struct wl_resource *resource) } static bool -update_pressed_surface(struct seat *seat, struct view *view, - struct wlr_scene_node *node, struct wlr_surface *surface) +update_pressed_surface(struct seat *seat, struct cursor_context *ctx) { /* * In most cases, we don't want to leave one surface and enter @@ -264,11 +252,11 @@ update_pressed_surface(struct seat *seat, struct view *view, * events to work properly. To cover this case, we allow * leave/enter events between XDG popups and their toplevel. */ - if (seat->pressed.surface && surface != seat->pressed.surface) { - struct wlr_surface *toplevel = get_toplevel(surface); + if (seat->pressed.surface && ctx->surface != seat->pressed.surface) { + struct wlr_surface *toplevel = get_toplevel(ctx->surface); if (toplevel && toplevel == seat->pressed.toplevel) { - seat_set_pressed(seat, view, node, - surface, toplevel); + seat_set_pressed(seat, ctx->view, ctx->node, + ctx->surface, toplevel); return true; } } @@ -315,15 +303,13 @@ process_cursor_motion_out_of_surface(struct server *server, uint32_t time) * Common logic shared by cursor_update_focus() and process_cursor_motion() */ static void -cursor_update_common(struct server *server, struct view *view, - struct wlr_scene_node *node, struct wlr_surface *surface, - double sx, double sy, enum ssd_part_type view_area, +cursor_update_common(struct server *server, struct cursor_context *ctx, uint32_t time_msec, bool cursor_has_moved) { struct seat *seat = &server->seat; struct wlr_seat *wlr_seat = seat->seat; - ssd_update_button_hover(node, &server->ssd_hover_state); + ssd_update_button_hover(ctx->node, &server->ssd_hover_state); if (server->input_mode != LAB_INPUT_STATE_PASSTHROUGH) { /* @@ -334,8 +320,8 @@ cursor_update_common(struct server *server, struct view *view, } /* TODO: verify drag_icon logic */ - if (seat->pressed.surface && surface != seat->pressed.surface - && !update_pressed_surface(seat, view, node, surface) + if (seat->pressed.surface && ctx->surface != seat->pressed.surface + && !update_pressed_surface(seat, ctx) && !seat->drag_icon) { if (cursor_has_moved) { /* @@ -350,13 +336,14 @@ cursor_update_common(struct server *server, struct view *view, return; } - if (surface && !input_inhibit_blocks_surface(seat, surface->resource)) { + if (ctx->surface && !input_inhibit_blocks_surface(seat, + ctx->surface->resource)) { /* * Cursor is over an input-enabled client surface. The * cursor image will be set by request_cursor_notify() * in response to the enter event. */ - if (surface != wlr_seat->pointer_state.focused_surface + if (ctx->surface != wlr_seat->pointer_state.focused_surface || seat->cursor_set_by_server) { /* * Enter the surface if necessary. Usually we @@ -370,13 +357,13 @@ cursor_update_common(struct server *server, struct view *view, * to trigger a cursor image update. */ wlr_seat_pointer_notify_clear_focus(wlr_seat); - wlr_seat_pointer_notify_enter(wlr_seat, surface, - sx, sy); + wlr_seat_pointer_notify_enter(wlr_seat, ctx->surface, + ctx->sx, ctx->sy); zfree(seat->cursor_set_by_server); } if (cursor_has_moved) { wlr_seat_pointer_notify_motion(wlr_seat, time_msec, - sx, sy); + ctx->sx, ctx->sy); } } else { /* @@ -385,10 +372,25 @@ cursor_update_common(struct server *server, struct view *view, * set the cursor image ourselves. */ wlr_seat_pointer_notify_clear_focus(wlr_seat); - set_server_cursor(seat, view_area); + set_server_cursor(seat, ctx->type); } } +static uint32_t +determine_resize_edges(struct wlr_cursor *cursor, struct cursor_context *ctx) +{ + uint32_t resize_edges = ssd_resize_edges(ctx->type); + if (ctx->view && !resize_edges) { + resize_edges |= + (int)cursor->x < ctx->view->x + ctx->view->w / 2 ? + WLR_EDGE_LEFT : WLR_EDGE_RIGHT; + resize_edges |= + (int)cursor->y < ctx->view->y + ctx->view->h / 2 ? + WLR_EDGE_TOP : WLR_EDGE_BOTTOM; + } + return resize_edges; +} + static void process_cursor_motion(struct server *server, uint32_t time) { @@ -402,28 +404,19 @@ process_cursor_motion(struct server *server, uint32_t time) } /* Otherwise, find view under the pointer and send the event along */ - double sx, sy; - struct wlr_scene_node *node; - enum ssd_part_type view_area = LAB_SSD_NONE; - struct view *view = desktop_node_and_view_at(server, - server->seat.cursor->x, server->seat.cursor->y, &node, - &sx, &sy, &view_area); + struct cursor_context ctx = get_cursor_context(server); + struct seat *seat = &server->seat; - struct wlr_surface *surface = NULL; - if (is_surface(view_area)) { - surface = lab_wlr_surface_from_node(node); - } - - if (view_area == LAB_SSD_MENU) { - menu_process_cursor_motion(node); - set_server_cursor(&server->seat, view_area); + if (ctx.type == LAB_SSD_MENU) { + menu_process_cursor_motion(ctx.node); + set_server_cursor(seat, ctx.type); return; } - if (view && rc.focus_follow_mouse) { - desktop_focus_and_activate_view(&server->seat, view); + if (ctx.view && rc.focus_follow_mouse) { + desktop_focus_and_activate_view(seat, ctx.view); if (rc.raise_on_focus) { - desktop_move_to_front(view); + desktop_move_to_front(ctx.view); } } @@ -432,23 +425,15 @@ process_cursor_motion(struct server *server, uint32_t time) if (mousebind->mouse_event == MOUSE_ACTION_DRAG && mousebind->pressed_in_context) { /* Find closest resize edges in case action is Resize */ - uint32_t resize_edges = ssd_resize_edges(view_area); - if (view && !resize_edges) { - resize_edges |= server->seat.cursor->x - < view->x + view->w / 2 ? WLR_EDGE_LEFT - : WLR_EDGE_RIGHT; - resize_edges |= server->seat.cursor->y - < view->y + view->h / 2 ? WLR_EDGE_TOP - : WLR_EDGE_BOTTOM; - } + uint32_t resize_edges = + determine_resize_edges(seat->cursor, &ctx); mousebind->pressed_in_context = false; actions_run(NULL, server, &mousebind->actions, resize_edges); } } - cursor_update_common(server, view, node, surface, sx, sy, view_area, - time, /*cursor_has_moved*/ true); + cursor_update_common(server, &ctx, time, /*cursor_has_moved*/ true); } static uint32_t @@ -460,25 +445,13 @@ msec(const struct timespec *t) void cursor_update_focus(struct server *server) { - double sx, sy; - struct wlr_scene_node *node = NULL; - struct wlr_surface *surface = NULL; - enum ssd_part_type view_area = LAB_SSD_NONE; - struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - struct seat *seat = &server->seat; - struct view *view = desktop_node_and_view_at(seat->server, - seat->cursor->x, seat->cursor->y, &node, &sx, &sy, &view_area); - - if (is_surface(view_area)) { - surface = lab_wlr_surface_from_node(node); - } - /* Focus surface under cursor if it isn't already focused */ - cursor_update_common(server, view, node, surface, sx, sy, view_area, - msec(&now), /*cursor_has_moved*/ false); + struct cursor_context ctx = get_cursor_context(server); + cursor_update_common(server, &ctx, msec(&now), + /*cursor_has_moved*/ false); } void @@ -802,9 +775,6 @@ cursor_button(struct wl_listener *listener, void *data) struct wlr_pointer_button_event *event = data; wlr_idle_notify_activity(seat->wlr_idle, seat->seat); - double sx, sy; - struct wlr_scene_node *node = NULL; - enum ssd_part_type view_area = LAB_SSD_NONE; uint32_t resize_edges = 0; /** @@ -818,14 +788,7 @@ cursor_button(struct wl_listener *listener, void *data) /* bindings to the Frame context swallow mouse events if activated */ bool triggered_frame_binding = false; - struct view *view = desktop_node_and_view_at(server, - server->seat.cursor->x, server->seat.cursor->y, &node, - &sx, &sy, &view_area); - - struct wlr_surface *surface = NULL; - if (is_surface(view_area)) { - surface = lab_wlr_surface_from_node(node); - } + struct cursor_context ctx = get_cursor_context(server); /* get modifiers */ struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard; @@ -835,7 +798,7 @@ cursor_button(struct wl_listener *listener, void *data) if (event->state == WLR_BUTTON_RELEASED) { struct wlr_surface *pressed_surface = seat->pressed.surface; seat_reset_pressed(seat); - if (pressed_surface && pressed_surface != surface) { + if (pressed_surface && ctx.surface != pressed_surface) { /* * Button released but originally pressed over a different surface. * Just send the release event to the still focused surface. @@ -847,8 +810,7 @@ cursor_button(struct wl_listener *listener, void *data) if (server->input_mode == LAB_INPUT_STATE_MENU) { if (close_menu) { menu_close_root(server); - cursor_update_common(server, view, node, - surface, sx, sy, view_area, + cursor_update_common(server, &ctx, event->time_msec, false); close_menu = false; } @@ -863,16 +825,16 @@ cursor_button(struct wl_listener *listener, void *data) } /* Handle _press */ - if (surface) { - seat_set_pressed(seat, view, node, surface, - get_toplevel(surface)); + if (ctx.surface) { + seat_set_pressed(seat, ctx.view, ctx.node, ctx.surface, + get_toplevel(ctx.surface)); } if (server->input_mode == LAB_INPUT_STATE_MENU) { /* We are closing the menu on RELEASE to not leak a stray release */ - if (view_area != LAB_SSD_MENU) { + if (ctx.type != LAB_SSD_MENU) { close_menu = true; - } else if (menu_call_actions(node)) { + } else if (menu_call_actions(ctx.node)) { /* Action was successfull, may fail if item just opens a submenu */ close_menu = true; } @@ -880,36 +842,28 @@ cursor_button(struct wl_listener *listener, void *data) } /* Handle _press_ on a layer surface */ - if (view_area == LAB_SSD_LAYER_SURFACE) { + if (ctx.type == LAB_SSD_LAYER_SURFACE) { struct wlr_layer_surface_v1 *layer = - wlr_layer_surface_v1_from_wlr_surface(surface); + wlr_layer_surface_v1_from_wlr_surface(ctx.surface); if (layer->current.keyboard_interactive) { - seat_set_focus_layer(&server->seat, layer); + seat_set_focus_layer(seat, layer); } } - if (view) { - /* Determine closest resize edges in case action is Resize */ - resize_edges = ssd_resize_edges(view_area); - if (!resize_edges) { - resize_edges |= server->seat.cursor->x < view->x + view->w / 2 - ? WLR_EDGE_LEFT : WLR_EDGE_RIGHT; - resize_edges |= server->seat.cursor->y < view->y + view->h / 2 - ? WLR_EDGE_TOP : WLR_EDGE_BOTTOM; - } - } + /* Determine closest resize edges in case action is Resize */ + resize_edges = determine_resize_edges(seat->cursor, &ctx); mousebindings: if (event->state == WLR_BUTTON_RELEASED) { - triggered_frame_binding |= handle_release_mousebinding(view, + triggered_frame_binding |= handle_release_mousebinding(ctx.view, server, event->button, modifiers, - view_area, resize_edges); + ctx.type, resize_edges); } else if (event->state == WLR_BUTTON_PRESSED) { - triggered_frame_binding |= handle_press_mousebinding(view, + triggered_frame_binding |= handle_press_mousebinding(ctx.view, server, event->button, modifiers, - view_area, resize_edges); + ctx.type, resize_edges); } - if (surface && !triggered_frame_binding) { + if (ctx.surface && !triggered_frame_binding) { /* Notify client with pointer focus of button press */ wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); diff --git a/src/desktop.c b/src/desktop.c index e6d09080..a867c1f0 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -293,92 +293,74 @@ desktop_focus_topmost_mapped_view(struct server *server) desktop_move_to_front(view); } -struct view * -desktop_node_and_view_at(struct server *server, double lx, double ly, - struct wlr_scene_node **scene_node, double *sx, double *sy, - enum ssd_part_type *view_area) +/* TODO: make this less big and scary */ +struct cursor_context +get_cursor_context(struct server *server) { + struct cursor_context ret = {.type = LAB_SSD_NONE}; + struct wlr_cursor *cursor = server->seat.cursor; struct wlr_scene_node *node = - wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy); + wlr_scene_node_at(&server->scene->tree.node, + cursor->x, cursor->y, &ret.sx, &ret.sy); - *scene_node = node; + ret.node = node; if (!node) { - *view_area = LAB_SSD_ROOT; - return NULL; + ret.type = LAB_SSD_ROOT; + return ret; } if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_surface *surface = lab_wlr_surface_from_node(node); if (surface && wlr_surface_is_layer_surface(surface)) { - *view_area = LAB_SSD_LAYER_SURFACE; - return NULL; + ret.type = LAB_SSD_LAYER_SURFACE; + ret.surface = surface; + return ret; } #if HAVE_XWAYLAND if (node->parent == server->unmanaged_tree) { - *view_area = LAB_SSD_UNMANAGED; - return NULL; + ret.type = LAB_SSD_UNMANAGED; + ret.surface = surface; + return ret; } #endif } while (node) { struct node_descriptor *desc = node->data; - /* TODO: convert to switch() */ if (desc) { - if (desc->type == LAB_NODE_DESC_VIEW) { - goto has_view_data; - } - if (desc->type == LAB_NODE_DESC_XDG_POPUP) { - goto has_view_data; - } - if (desc->type == LAB_NODE_DESC_SSD_BUTTON) { + switch (desc->type) { + case LAB_NODE_DESC_VIEW: + case LAB_NODE_DESC_XDG_POPUP: + ret.view = desc->data; + ret.type = ssd_get_part_type(ret.view, ret.node); + if (ret.type == LAB_SSD_CLIENT) { + ret.surface = lab_wlr_surface_from_node(ret.node); + } + return ret; + case LAB_NODE_DESC_SSD_BUTTON: { /* Always return the top scene node for SSD buttons */ struct ssd_button *button = node_ssd_button_from_node(node); - *scene_node = node; - *view_area = button->type; - return button->view; + ret.node = node; + ret.type = button->type; + ret.view = button->view; + return ret; } - if (desc->type == LAB_NODE_DESC_LAYER_SURFACE) { - /* FIXME: we shouldn't have to set *view_area */ - *view_area = LAB_SSD_CLIENT; - return NULL; - } - if (desc->type == LAB_NODE_DESC_LAYER_POPUP) { - /* FIXME: we shouldn't have to set *view_area */ - *view_area = LAB_SSD_CLIENT; - return NULL; - } - if (desc->type == LAB_NODE_DESC_MENUITEM) { + case LAB_NODE_DESC_LAYER_SURFACE: + case LAB_NODE_DESC_LAYER_POPUP: + ret.type = LAB_SSD_CLIENT; + ret.surface = lab_wlr_surface_from_node(ret.node); + return ret; + case LAB_NODE_DESC_MENUITEM: /* Always return the top scene node for menu items */ - *scene_node = node; - *view_area = LAB_SSD_MENU; - return NULL; + ret.node = node; + ret.type = LAB_SSD_MENU; + return ret; + case LAB_NODE_DESC_NODE: + case LAB_NODE_DESC_TREE: + break; } } /* node->parent is always a *wlr_scene_tree */ node = node->parent ? &node->parent->node : NULL; } - if (!node) { - wlr_log(WLR_ERROR, "Unknown node detected"); - } - *view_area = LAB_SSD_NONE; - return NULL; - -struct view *view; -struct node_descriptor *desc; -has_view_data: - desc = node->data; - view = desc->data; - *view_area = ssd_get_part_type(view, *scene_node); - return view; -} - -struct view * -desktop_view_at_cursor(struct server *server) -{ - double sx, sy; - struct wlr_scene_node *node; - enum ssd_part_type view_area = LAB_SSD_NONE; - - return desktop_node_and_view_at(server, - server->seat.cursor->x, server->seat.cursor->y, - &node, &sx, &sy, &view_area); + wlr_log(WLR_ERROR, "Unknown node detected"); + return ret; }