cursor: Fix out-of-surface movement for unmanaged surfaces

This commit is contained in:
John Lindgren 2022-09-01 17:50:28 -04:00 committed by Consolatis
parent f7b1bc1de8
commit 7c6c018f43
6 changed files with 57 additions and 36 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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) {

View file

@ -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