diff --git a/include/labwc.h b/include/labwc.h index c5d78aad..20fe882b 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -559,6 +559,7 @@ void seat_finish(struct server *server); void seat_reconfigure(struct server *server); void seat_focus_surface(struct seat *seat, struct wlr_surface *surface); void seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer); +void seat_reset_pressed(struct seat *seat); void interactive_begin(struct view *view, enum input_mode mode, uint32_t edges); diff --git a/src/cursor.c b/src/cursor.c index 0479b656..89ea6996 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -196,6 +196,42 @@ input_inhibit_blocks_surface(struct seat *seat, struct wl_resource *resource) && inhibiting_client != wl_resource_get_client(resource); } +static void +process_cursor_motion_out_of_surface(struct server *server, uint32_t time) +{ + struct view *view = server->seat.pressed.view; + struct wlr_scene_node *node = server->seat.pressed.node; + struct wlr_surface *surface = server->seat.pressed.surface; + assert(surface); + int lx, ly; + + if (view) { + lx = view->x; + ly = view->y; + } else if (node && wlr_surface_is_layer_surface(surface)) { + wlr_scene_node_coords(node, &lx, &ly); +#if HAVE_XWAYLAND + } else if (node && node->parent == server->unmanaged_tree) { + wlr_scene_node_coords(node, &lx, &ly); +#endif + } else { + wlr_log(WLR_ERROR, "Can't detect surface for out-of-surface movement"); + return; + } + + double sx = server->seat.cursor->x - lx; + double sy = server->seat.cursor->y - ly; + /* Take into account invisible xdg-shell CSD borders */ + if (view && view->type == LAB_XDG_SHELL_VIEW && view->xdg_surface) { + struct wlr_box geo; + wlr_xdg_surface_get_geometry(view->xdg_surface, &geo); + sx += geo.x; + sy += geo.y; + } + + wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy); +} + static void process_cursor_motion(struct server *server, uint32_t time) { @@ -289,29 +325,7 @@ process_cursor_motion(struct server *server, uint32_t time) * or selecting text even if the cursor moves outside of * the surface. */ - int lx, ly; - view = server->seat.pressed.view; - if (view) { - lx = view->x; - ly = view->y; - } else if (wlr_surface_is_layer_surface(server->seat.pressed.surface)) { - wlr_scene_node_coords(server->seat.pressed.node, &lx, &ly); - } else { - wlr_log(WLR_ERROR, "Can't detect surface for out-of-surface movement"); - return; - } - sx = server->seat.cursor->x - lx; - sy = server->seat.cursor->y - ly; - - /* Take into account invisible xdg-shell CSD borders */ - if (view && view->type == LAB_XDG_SHELL_VIEW - && view->xdg_surface) { - struct wlr_box geo; - wlr_xdg_surface_get_geometry(view->xdg_surface, &geo); - sx += geo.x; - sy += geo.y; - } - wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy); + process_cursor_motion_out_of_surface(server, time); } else if (surface && !input_inhibit_blocks_surface( &server->seat, surface->resource)) { bool focus_changed = @@ -364,9 +378,7 @@ start_drag(struct wl_listener *listener, void *data) { struct seat *seat = wl_container_of(listener, seat, start_drag); struct wlr_drag *wlr_drag = data; - seat->pressed.view = NULL; - seat->pressed.node = NULL; - seat->pressed.surface = NULL; + seat_reset_pressed(seat); seat->drag_icon = wlr_drag->icon; if (!seat->drag_icon) { wlr_log(WLR_ERROR, @@ -713,19 +725,17 @@ cursor_button(struct wl_listener *listener, void *data) /* handle _release_ */ if (event->state == WLR_BUTTON_RELEASED) { - seat->pressed.view = NULL; - seat->pressed.node = NULL; - if (seat->pressed.surface && seat->pressed.surface != surface) { + struct wlr_surface *pressed_surface = seat->pressed.surface; + seat_reset_pressed(seat); + if (pressed_surface && pressed_surface != surface) { /* * Button released but originally pressed over a different surface. * Just send the release event to the still focused surface. */ wlr_seat_pointer_notify_button(seat->seat, event->time_msec, event->button, event->state); - seat->pressed.surface = NULL; return; } - seat->pressed.surface = NULL; if (server->input_mode == LAB_INPUT_STATE_MENU) { if (close_menu) { menu_close_root(server); diff --git a/src/layers.c b/src/layers.c index b9d05c2d..a6e2e4bd 100644 --- a/src/layers.c +++ b/src/layers.c @@ -146,8 +146,7 @@ unmap(struct lab_layer_surface *layer) seat_set_focus_layer(seat, NULL); } if (seat->pressed.surface == layer->scene_layer_surface->layer_surface->surface) { - seat->pressed.node = NULL; - seat->pressed.surface = NULL; + seat_reset_pressed(seat); } } diff --git a/src/seat.c b/src/seat.c index 316c503f..56edaef3 100644 --- a/src/seat.c +++ b/src/seat.c @@ -369,3 +369,11 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer) seat->focused_layer = layer; } } + +void +seat_reset_pressed(struct seat *seat) +{ + seat->pressed.view = NULL; + seat->pressed.node = NULL; + seat->pressed.surface = NULL; +} diff --git a/src/view.c b/src/view.c index 05f94432..f1766a91 100644 --- a/src/view.c +++ b/src/view.c @@ -813,8 +813,7 @@ view_destroy(struct view *view) if (server->seat.pressed.view == view) { /* Mouse was pressed on surface and is still pressed */ - server->seat.pressed.view = NULL; - server->seat.pressed.surface = NULL; + seat_reset_pressed(&server->seat); } if (server->focused_view == view) { diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index ca78722d..49d535f8 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -57,6 +57,8 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data) struct xwayland_unmanaged *unmanaged = wl_container_of(listener, unmanaged, unmap); struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; + struct seat *seat = &unmanaged->server->seat; + wl_list_remove(&unmanaged->link); wl_list_remove(&unmanaged->set_geometry.link); @@ -64,9 +66,11 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data) * Mark the node as gone so a racing configure event * won't try to reposition the node while unmapped. */ + if (unmanaged->node && seat->pressed.node == unmanaged->node) { + seat_reset_pressed(seat); + } unmanaged->node = NULL; - struct seat *seat = &unmanaged->server->seat; if (seat->seat->keyboard_state.focused_surface == xsurface->surface) { /* * Try to focus on parent surface