/**
* pressed view/surface/node will usually be NULL and is only set on
- * button press while the mouse is over a surface and reset to NULL on
- * button release.
+ * button press while the mouse is over a view or surface, and reset
+ * to NULL on button release.
* It is used to send cursor motion events to a surface even though
* the cursor has left the surface in the meantime.
*
* This allows to keep dragging a scrollbar or selecting text even
* when moving outside of the window.
+ *
+ * Both (view && !surface) and (surface && !view) are possible.
*/
struct {
struct view *view;
struct wlr_scene_node *node;
struct wlr_surface *surface;
struct wlr_surface *toplevel;
+ uint32_t resize_edges;
} pressed;
struct wl_client *active_client_while_inhibited;
void seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer);
void seat_set_pressed(struct seat *seat, struct view *view,
struct wlr_scene_node *node, struct wlr_surface *surface,
- struct wlr_surface *toplevel);
+ struct wlr_surface *toplevel, uint32_t resize_edges);
void seat_reset_pressed(struct seat *seat);
void interactive_begin(struct view *view, enum input_mode mode,
}
static struct view *
-activator_or_focused_view(struct view *activator, struct server *server)
+view_for_action(struct view *activator, struct server *server,
+ struct action *action)
{
- return activator ? activator : desktop_focused_view(server);
+ /* View is explicitly specified for mousebinds */
+ if (activator) {
+ return activator;
+ }
+
+ /* Select view based on action type for keybinds */
+ switch (action->type) {
+ case ACTION_TYPE_FOCUS:
+ case ACTION_TYPE_MOVE:
+ case ACTION_TYPE_RESIZE:
+ return get_cursor_context(server).view;
+ default:
+ return desktop_focused_view(server);
+ }
}
void
* Refetch view because it may have been changed due to the
* previous action
*/
- view = activator_or_focused_view(activator, server);
+ view = view_for_action(activator, server, action);
switch (action->type) {
case ACTION_TYPE_CLOSE:
}
break;
case ACTION_TYPE_FOCUS:
- view = get_cursor_context(server).view;
if (view) {
desktop_focus_and_activate_view(&server->seat, view);
}
}
break;
case ACTION_TYPE_MOVE:
- view = get_cursor_context(server).view;
if (view) {
interactive_begin(view, LAB_INPUT_STATE_MOVE, 0);
}
}
break;
case ACTION_TYPE_RESIZE:
- view = get_cursor_context(server).view;
if (view) {
interactive_begin(view, LAB_INPUT_STATE_RESIZE,
resize_edges);
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, ctx->view, ctx->node,
- ctx->surface, toplevel);
+ /* No need to recompute resize edges here */
+ seat_set_pressed(seat, ctx->view,
+ ctx->node, ctx->surface, toplevel,
+ seat->pressed.resize_edges);
return true;
}
}
wl_list_for_each(mousebind, &rc.mousebinds, link) {
if (mousebind->mouse_event == MOUSE_ACTION_DRAG
&& mousebind->pressed_in_context) {
- /* Find closest resize edges in case action is Resize */
- uint32_t resize_edges =
- determine_resize_edges(seat->cursor, &ctx);
-
+ /*
+ * Use view and resize edges from the press
+ * event (not the motion event) to prevent
+ * moving/resizing the wrong view
+ */
mousebind->pressed_in_context = false;
- actions_run(NULL, server, &mousebind->actions, resize_edges);
+ actions_run(seat->pressed.view,
+ server, &mousebind->actions,
+ seat->pressed.resize_edges);
}
}
}
/* Handle _press */
- if (ctx.surface) {
+ /* Determine closest resize edges in case action is Resize */
+ resize_edges = determine_resize_edges(seat->cursor, &ctx);
+
+ if (ctx.view || ctx.surface) {
+ /* Store resize edges for later action processing */
seat_set_pressed(seat, ctx.view, ctx.node, ctx.surface,
- get_toplevel(ctx.surface));
+ get_toplevel(ctx.surface), resize_edges);
}
if (server->input_mode == LAB_INPUT_STATE_MENU) {
}
}
- /* 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(ctx.view,
void
seat_set_pressed(struct seat *seat, struct view *view,
struct wlr_scene_node *node, struct wlr_surface *surface,
- struct wlr_surface *toplevel)
+ struct wlr_surface *toplevel, uint32_t resize_edges)
{
- assert(surface);
+ assert(view || surface);
seat_reset_pressed(seat);
seat->pressed.view = view;
seat->pressed.node = node;
seat->pressed.surface = surface;
seat->pressed.toplevel = toplevel;
- seat->pressed_surface_destroy.notify = pressed_surface_destroy;
- wl_signal_add(&surface->events.destroy, &seat->pressed_surface_destroy);
+ seat->pressed.resize_edges = resize_edges;
+
+ if (surface) {
+ seat->pressed_surface_destroy.notify = pressed_surface_destroy;
+ wl_signal_add(&surface->events.destroy,
+ &seat->pressed_surface_destroy);
+ }
}
void
seat_reset_pressed(struct seat *seat)
{
if (seat->pressed.surface) {
- seat->pressed.view = NULL;
- seat->pressed.node = NULL;
- seat->pressed.surface = NULL;
- seat->pressed.toplevel = NULL;
wl_list_remove(&seat->pressed_surface_destroy.link);
}
+
+ seat->pressed.view = NULL;
+ seat->pressed.node = NULL;
+ seat->pressed.surface = NULL;
+ seat->pressed.toplevel = NULL;
+ seat->pressed.resize_edges = 0;
}
need_cursor_update = true;
}
+ if (server->seat.pressed.view == view) {
+ seat_reset_pressed(&server->seat);
+ }
+
osd_on_view_destroy(view);
if (view->scene_tree) {