mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	cursor: Fix out-of-surface movement for unmanaged surfaces
This commit is contained in:
		
							parent
							
								
									f7b1bc1de8
								
							
						
					
					
						commit
						7c6c018f43
					
				
					 6 changed files with 57 additions and 36 deletions
				
			
		| 
						 | 
					@ -559,6 +559,7 @@ void seat_finish(struct server *server);
 | 
				
			||||||
void seat_reconfigure(struct server *server);
 | 
					void seat_reconfigure(struct server *server);
 | 
				
			||||||
void seat_focus_surface(struct seat *seat, struct wlr_surface *surface);
 | 
					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_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,
 | 
					void interactive_begin(struct view *view, enum input_mode mode,
 | 
				
			||||||
		      uint32_t edges);
 | 
							      uint32_t edges);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										72
									
								
								src/cursor.c
									
										
									
									
									
								
							
							
						
						
									
										72
									
								
								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);
 | 
							&& 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
 | 
					static void
 | 
				
			||||||
process_cursor_motion(struct server *server, uint32_t time)
 | 
					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
 | 
							 * or selecting text even if the cursor moves outside of
 | 
				
			||||||
		 * the surface.
 | 
							 * the surface.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		int lx, ly;
 | 
							process_cursor_motion_out_of_surface(server, time);
 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
	} else if (surface && !input_inhibit_blocks_surface(
 | 
						} else if (surface && !input_inhibit_blocks_surface(
 | 
				
			||||||
			&server->seat, surface->resource)) {
 | 
								&server->seat, surface->resource)) {
 | 
				
			||||||
		bool focus_changed =
 | 
							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 seat *seat = wl_container_of(listener, seat, start_drag);
 | 
				
			||||||
	struct wlr_drag *wlr_drag = data;
 | 
						struct wlr_drag *wlr_drag = data;
 | 
				
			||||||
	seat->pressed.view = NULL;
 | 
						seat_reset_pressed(seat);
 | 
				
			||||||
	seat->pressed.node = NULL;
 | 
					 | 
				
			||||||
	seat->pressed.surface = NULL;
 | 
					 | 
				
			||||||
	seat->drag_icon = wlr_drag->icon;
 | 
						seat->drag_icon = wlr_drag->icon;
 | 
				
			||||||
	if (!seat->drag_icon) {
 | 
						if (!seat->drag_icon) {
 | 
				
			||||||
		wlr_log(WLR_ERROR,
 | 
							wlr_log(WLR_ERROR,
 | 
				
			||||||
| 
						 | 
					@ -713,19 +725,17 @@ cursor_button(struct wl_listener *listener, void *data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* handle _release_ */
 | 
						/* handle _release_ */
 | 
				
			||||||
	if (event->state == WLR_BUTTON_RELEASED) {
 | 
						if (event->state == WLR_BUTTON_RELEASED) {
 | 
				
			||||||
		seat->pressed.view = NULL;
 | 
							struct wlr_surface *pressed_surface = seat->pressed.surface;
 | 
				
			||||||
		seat->pressed.node = NULL;
 | 
							seat_reset_pressed(seat);
 | 
				
			||||||
		if (seat->pressed.surface && seat->pressed.surface != surface) {
 | 
							if (pressed_surface && pressed_surface != surface) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Button released but originally pressed over a different surface.
 | 
								 * Button released but originally pressed over a different surface.
 | 
				
			||||||
			 * Just send the release event to the still focused surface.
 | 
								 * Just send the release event to the still focused surface.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
 | 
								wlr_seat_pointer_notify_button(seat->seat, event->time_msec,
 | 
				
			||||||
				event->button, event->state);
 | 
									event->button, event->state);
 | 
				
			||||||
			seat->pressed.surface = NULL;
 | 
					 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		seat->pressed.surface = NULL;
 | 
					 | 
				
			||||||
		if (server->input_mode == LAB_INPUT_STATE_MENU) {
 | 
							if (server->input_mode == LAB_INPUT_STATE_MENU) {
 | 
				
			||||||
			if (close_menu) {
 | 
								if (close_menu) {
 | 
				
			||||||
				menu_close_root(server);
 | 
									menu_close_root(server);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -146,8 +146,7 @@ unmap(struct lab_layer_surface *layer)
 | 
				
			||||||
		seat_set_focus_layer(seat, NULL);
 | 
							seat_set_focus_layer(seat, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (seat->pressed.surface == layer->scene_layer_surface->layer_surface->surface) {
 | 
						if (seat->pressed.surface == layer->scene_layer_surface->layer_surface->surface) {
 | 
				
			||||||
		seat->pressed.node = NULL;
 | 
							seat_reset_pressed(seat);
 | 
				
			||||||
		seat->pressed.surface = NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -369,3 +369,11 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
 | 
				
			||||||
		seat->focused_layer = layer;
 | 
							seat->focused_layer = layer;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					seat_reset_pressed(struct seat *seat)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						seat->pressed.view = NULL;
 | 
				
			||||||
 | 
						seat->pressed.node = NULL;
 | 
				
			||||||
 | 
						seat->pressed.surface = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -813,8 +813,7 @@ view_destroy(struct view *view)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (server->seat.pressed.view == view) {
 | 
						if (server->seat.pressed.view == view) {
 | 
				
			||||||
		/* Mouse was pressed on surface and is still pressed */
 | 
							/* Mouse was pressed on surface and is still pressed */
 | 
				
			||||||
		server->seat.pressed.view = NULL;
 | 
							seat_reset_pressed(&server->seat);
 | 
				
			||||||
		server->seat.pressed.surface = NULL;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (server->focused_view == view) {
 | 
						if (server->focused_view == view) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,8 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data)
 | 
				
			||||||
	struct xwayland_unmanaged *unmanaged =
 | 
						struct xwayland_unmanaged *unmanaged =
 | 
				
			||||||
		wl_container_of(listener, unmanaged, unmap);
 | 
							wl_container_of(listener, unmanaged, unmap);
 | 
				
			||||||
	struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
 | 
						struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface;
 | 
				
			||||||
 | 
						struct seat *seat = &unmanaged->server->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_list_remove(&unmanaged->link);
 | 
						wl_list_remove(&unmanaged->link);
 | 
				
			||||||
	wl_list_remove(&unmanaged->set_geometry.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
 | 
						 * Mark the node as gone so a racing configure event
 | 
				
			||||||
	 * won't try to reposition the node while unmapped.
 | 
						 * won't try to reposition the node while unmapped.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (unmanaged->node && seat->pressed.node == unmanaged->node) {
 | 
				
			||||||
 | 
							seat_reset_pressed(seat);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	unmanaged->node = NULL;
 | 
						unmanaged->node = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct seat *seat = &unmanaged->server->seat;
 | 
					 | 
				
			||||||
	if (seat->seat->keyboard_state.focused_surface == xsurface->surface) {
 | 
						if (seat->seat->keyboard_state.focused_surface == xsurface->surface) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Try to focus on parent surface
 | 
							 * Try to focus on parent surface
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue