mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	data-device: fix dnd handling during popup interactions
When a popup appears during dnd operations in wlroots-based compositors, several issues occur: 1.Drag data is lost 2.Keyboard focus changes unexpectedly 3.Other windows cannot receive drag enter events 4.The compositor may crash in some cases 5.Event propagation is interrupted Forwarding pointer/keyboard events from popup grab to drag grab when drag is active, preventing data loss and maintaining proper event propagation during popup interactions.
This commit is contained in:
		
							parent
							
								
									b97106ddcb
								
							
						
					
					
						commit
						2e53932337
					
				
					 2 changed files with 67 additions and 2 deletions
				
			
		| 
						 | 
					@ -4,6 +4,7 @@
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/types/wlr_compositor.h>
 | 
					#include <wlr/types/wlr_compositor.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_data_device.h>
 | 
				
			||||||
#include <wlr/util/log.h>
 | 
					#include <wlr/util/log.h>
 | 
				
			||||||
#include "types/wlr_seat.h"
 | 
					#include "types/wlr_seat.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -416,6 +417,11 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,
 | 
				
			||||||
	grab->seat = wlr_seat;
 | 
						grab->seat = wlr_seat;
 | 
				
			||||||
	wlr_seat->pointer_state.grab = grab;
 | 
						wlr_seat->pointer_state.grab = grab;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Preserve drag grab priority
 | 
				
			||||||
 | 
					    if (wlr_seat->drag && grab != &wlr_seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_emit_mutable(&wlr_seat->events.pointer_grab_begin, grab);
 | 
						wl_signal_emit_mutable(&wlr_seat->events.pointer_grab_begin, grab);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_data_device.h>
 | 
				
			||||||
#include "types/wlr_xdg_shell.h"
 | 
					#include "types/wlr_xdg_shell.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void handle_xdg_popup_ack_configure(
 | 
					void handle_xdg_popup_ack_configure(
 | 
				
			||||||
| 
						 | 
					@ -52,6 +53,18 @@ static void xdg_popup_grab_end(struct wlr_xdg_popup_grab *popup_grab) {
 | 
				
			||||||
static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab,
 | 
					static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab,
 | 
				
			||||||
		struct wlr_surface *surface, double sx, double sy) {
 | 
							struct wlr_surface *surface, double sx, double sy) {
 | 
				
			||||||
	struct wlr_xdg_popup_grab *popup_grab = grab->data;
 | 
						struct wlr_xdg_popup_grab *popup_grab = grab->data;
 | 
				
			||||||
 | 
						struct wlr_seat *seat = grab->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Forward to drag grab if active
 | 
				
			||||||
 | 
					    if (seat->drag && seat->drag->pointer_grab.interface &&
 | 
				
			||||||
 | 
					        seat->drag->pointer_grab.interface->enter) {
 | 
				
			||||||
 | 
					        if (grab != &seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
					            seat->drag->pointer_grab.interface->enter(&seat->drag->pointer_grab,
 | 
				
			||||||
 | 
					                surface, sx, sy);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (wl_resource_get_client(surface->resource) == popup_grab->client) {
 | 
						if (wl_resource_get_client(surface->resource) == popup_grab->client) {
 | 
				
			||||||
		wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
 | 
							wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -65,13 +78,33 @@ static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab,
 | 
					static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab,
 | 
				
			||||||
		uint32_t time, double sx, double sy) {
 | 
							uint32_t time, double sx, double sy) {
 | 
				
			||||||
 | 
						struct wlr_seat *seat = grab->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seat->drag && seat->drag->pointer_grab.interface &&
 | 
				
			||||||
 | 
							seat->drag->pointer_grab.interface->motion) {
 | 
				
			||||||
 | 
							if (grab != &seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
								seat->drag->pointer_grab.interface->motion(&seat->drag->pointer_grab,
 | 
				
			||||||
 | 
									time, sx, sy);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
 | 
						wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab,
 | 
					static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab,
 | 
				
			||||||
		uint32_t time, uint32_t button, uint32_t state) {
 | 
							uint32_t time, uint32_t button, uint32_t state) {
 | 
				
			||||||
	uint32_t serial =
 | 
						struct wlr_seat *seat = grab->seat;
 | 
				
			||||||
		wlr_seat_pointer_send_button(grab->seat, time, button, state);
 | 
					
 | 
				
			||||||
 | 
						if (seat->drag && seat->drag->pointer_grab.interface &&
 | 
				
			||||||
 | 
							seat->drag->pointer_grab.interface->button) {
 | 
				
			||||||
 | 
							if (grab != &seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
								return seat->drag->pointer_grab.interface->button(&seat->drag->pointer_grab,
 | 
				
			||||||
 | 
									time, button, state);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t serial = wlr_seat_pointer_send_button(grab->seat, time, button, state);
 | 
				
			||||||
	if (serial) {
 | 
						if (serial) {
 | 
				
			||||||
		return serial;
 | 
							return serial;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -84,11 +117,32 @@ static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab,
 | 
				
			||||||
		uint32_t time, enum wl_pointer_axis orientation, double value,
 | 
							uint32_t time, enum wl_pointer_axis orientation, double value,
 | 
				
			||||||
		int32_t value_discrete, enum wl_pointer_axis_source source,
 | 
							int32_t value_discrete, enum wl_pointer_axis_source source,
 | 
				
			||||||
		enum wl_pointer_axis_relative_direction relative_direction) {
 | 
							enum wl_pointer_axis_relative_direction relative_direction) {
 | 
				
			||||||
 | 
						struct wlr_seat *seat = grab->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seat->drag && seat->drag->pointer_grab.interface &&
 | 
				
			||||||
 | 
							seat->drag->pointer_grab.interface->axis) {
 | 
				
			||||||
 | 
							if (grab != &seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
								seat->drag->pointer_grab.interface->axis(&seat->drag->pointer_grab,
 | 
				
			||||||
 | 
									time, orientation, value, value_discrete, source, relative_direction);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
 | 
						wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
 | 
				
			||||||
		value_discrete, source, relative_direction);
 | 
							value_discrete, source, relative_direction);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) {
 | 
					static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) {
 | 
				
			||||||
 | 
						struct wlr_seat *seat = grab->seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (seat->drag && seat->drag->pointer_grab.interface &&
 | 
				
			||||||
 | 
							seat->drag->pointer_grab.interface->frame) {
 | 
				
			||||||
 | 
							if (grab != &seat->drag->pointer_grab) {
 | 
				
			||||||
 | 
								seat->drag->pointer_grab.interface->frame(&seat->drag->pointer_grab);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_seat_pointer_send_frame(grab->seat);
 | 
						wlr_seat_pointer_send_frame(grab->seat);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,6 +164,11 @@ static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab,
 | 
				
			||||||
		struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
 | 
							struct wlr_surface *surface, const uint32_t keycodes[], size_t num_keycodes,
 | 
				
			||||||
		const struct wlr_keyboard_modifiers *modifiers) {
 | 
							const struct wlr_keyboard_modifiers *modifiers) {
 | 
				
			||||||
	// keyboard focus should remain on the popup
 | 
						// keyboard focus should remain on the popup
 | 
				
			||||||
 | 
						if (grab->seat->drag) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wlr_seat_keyboard_enter(grab->seat, surface, keycodes, num_keycodes, modifiers);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) {
 | 
					static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue