app: use gdk_seat_grab() instead of deprecated gdk_device_grab().

Additionally to fixing a deprecation, I also ensure that we don't limit
pointer source to what the system considers the "Core Pointer" on
Wayland.

It is another bug similar to #8016 and possibly what !924 was trying to
fix, even though it turned out this was not the same problem which I
initially reported. In this other variant, when you were hitting Space,
it would originate from the "Core Keyboard" which was associated to a
"Core Pointer". On a laptop, this Core Pointer could be the trackpoint
for instance (in my case) so you could pan with Space + trackpoint move.
Yet say you add a graphics tablet, which is a separate pointer: you
could not pan with Space + stylus move!

Now you can, because when we are pan-spacing, events from all pointer
sources are accepted. Only when the panning comes from a pointer source
(middle click) do we listen only events from this same pointer device.
This commit is contained in:
Jehan 2024-10-27 22:40:50 +01:00
parent 3a8825cf06
commit 0b4d104c15
3 changed files with 35 additions and 22 deletions

View File

@ -31,6 +31,7 @@
#include "gimpdisplayshell-grab.h" #include "gimpdisplayshell-grab.h"
#if 0
static GdkDevice * static GdkDevice *
get_associated_pointer (GdkDevice *device) get_associated_pointer (GdkDevice *device)
{ {
@ -58,45 +59,56 @@ get_associated_pointer (GdkDevice *device)
return device; return device;
} }
#endif
gboolean gboolean
gimp_display_shell_pointer_grab (GimpDisplayShell *shell, gimp_display_shell_pointer_grab (GimpDisplayShell *shell,
const GdkEvent *event, const GdkEvent *event,
GdkEventMask event_mask) GdkEventMask event_mask)
{ {
GdkDisplay *display;
GdkSeat *seat;
GdkDevice *device; GdkDevice *device;
GdkDevice *source_device; GdkDevice *source_device;
GdkGrabStatus status; GdkGrabStatus status;
g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE); g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
g_return_val_if_fail (event != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE);
g_return_val_if_fail (shell->grab_pointer == NULL, FALSE); g_return_val_if_fail (shell->grab_seat == NULL, FALSE);
source_device = gimp_devices_get_from_event (shell->display->gimp, source_device = gimp_devices_get_from_event (shell->display->gimp,
event, &device); event, &device);
display = gdk_device_get_display (device);
seat = gdk_display_get_default_seat (display);
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
{ {
device = get_associated_pointer (device); /* When the source grab event was a keyboard, we want to accept
* pointer events from any pointing device. This is especially
* true on Wayland where each pointing device can be really
* independant whereas on X11, they all appear as "Virtual core
* pointer".
*/
device = NULL;
source_device = NULL; source_device = NULL;
} }
status = gdk_device_grab (device, status = gdk_seat_grab (seat,
gtk_widget_get_window (shell->canvas), gtk_widget_get_window (shell->canvas),
GDK_OWNERSHIP_APPLICATION, GDK_SEAT_CAPABILITY_ALL_POINTING,
FALSE, event_mask, NULL, FALSE, NULL,
gdk_event_get_time (event)); event, NULL, NULL);
if (status == GDK_GRAB_SUCCESS) if (status == GDK_GRAB_SUCCESS)
{ {
shell->grab_seat = seat;
shell->grab_pointer = device; shell->grab_pointer = device;
shell->grab_pointer_source = source_device; shell->grab_pointer_source = source_device;
shell->grab_pointer_time = gdk_event_get_time (event);
return TRUE; return TRUE;
} }
g_printerr ("%s: gdk_device_grab(%s) failed with status %d\n", g_printerr ("%s: gdk_seat_grab(%s) failed with status %d\n",
G_STRFUNC, gdk_device_get_name (device), status); G_STRFUNC, gdk_device_get_name (device), status);
return FALSE; return FALSE;
@ -108,11 +120,11 @@ gimp_display_shell_pointer_ungrab (GimpDisplayShell *shell,
{ {
g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
g_return_if_fail (event != NULL); g_return_if_fail (event != NULL);
g_return_if_fail (shell->grab_pointer != NULL); g_return_if_fail (shell->grab_seat != NULL);
gdk_device_ungrab (shell->grab_pointer, shell->grab_pointer_time); gdk_seat_ungrab (shell->grab_seat);
shell->grab_seat = NULL;
shell->grab_pointer = NULL; shell->grab_pointer = NULL;
shell->grab_pointer_source = NULL; shell->grab_pointer_source = NULL;
shell->grab_pointer_time = 0;
} }

View File

@ -410,7 +410,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
return TRUE; return TRUE;
/* ignore enter notify while we have a grab */ /* ignore enter notify while we have a grab */
if (shell->grab_pointer) if (shell->grab_seat)
return TRUE; return TRUE;
gimp_display_shell_proximity_in (shell); gimp_display_shell_proximity_in (shell);
@ -431,7 +431,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
return TRUE; return TRUE;
/* ignore leave notify while we have a grab */ /* ignore leave notify while we have a grab */
if (shell->grab_pointer) if (shell->grab_seat)
return TRUE; return TRUE;
gimp_display_shell_proximity_out (shell); gimp_display_shell_proximity_out (shell);
@ -471,7 +471,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
g_warning ("%s: FOCUS_IN but canvas has no focus", G_STRFUNC); g_warning ("%s: FOCUS_IN but canvas has no focus", G_STRFUNC);
/* ignore focus changes while we have a grab */ /* ignore focus changes while we have a grab */
if (shell->grab_pointer) if (shell->grab_seat)
return TRUE; return TRUE;
/* press modifier keys when the canvas gets the focus */ /* press modifier keys when the canvas gets the focus */
@ -484,7 +484,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
g_warning ("%s: FOCUS_OUT but canvas has focus", G_STRFUNC); g_warning ("%s: FOCUS_OUT but canvas has focus", G_STRFUNC);
/* ignore focus changes while we have a grab */ /* ignore focus changes while we have a grab */
if (shell->grab_pointer) if (shell->grab_seat)
return TRUE; return TRUE;
/* release modifier keys when the canvas loses the focus */ /* release modifier keys when the canvas loses the focus */
@ -502,7 +502,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
/* ignore new mouse events */ /* ignore new mouse events */
if (gimp->busy || if (gimp->busy ||
shell->mod_action != GIMP_MODIFIER_ACTION_NONE || shell->mod_action != GIMP_MODIFIER_ACTION_NONE ||
shell->grab_pointer || shell->grab_seat ||
shell->button1_release_pending) shell->button1_release_pending)
return TRUE; return TRUE;
@ -703,7 +703,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
* a button press we intentionally ignored because we had * a button press we intentionally ignored because we had
* a grab on another device at the time of the press * a grab on another device at the time of the press
*/ */
if (! shell->grab_pointer || shell->mod_action != GIMP_MODIFIER_ACTION_NONE) if (! shell->grab_seat || shell->mod_action != GIMP_MODIFIER_ACTION_NONE)
return TRUE; return TRUE;
if (active_tool && if (active_tool &&
@ -1215,7 +1215,7 @@ gimp_display_shell_canvas_tool_events (GtkWidget *canvas,
/* We need to ungrab the pointer in order to catch /* We need to ungrab the pointer in order to catch
* button release events. * button release events.
*/ */
if (shell->grab_pointer) if (shell->grab_seat)
gimp_display_shell_pointer_ungrab (shell, event); gimp_display_shell_pointer_ungrab (shell, event);
} }
else else
@ -1630,7 +1630,8 @@ gimp_display_shell_check_device (GimpDisplayShell *shell,
event->type != GDK_KEY_RELEASE && event->type != GDK_KEY_RELEASE &&
event->type != GDK_FOCUS_CHANGE) event->type != GDK_FOCUS_CHANGE)
{ {
if ((shell->grab_pointer && (shell->grab_pointer != grab_device)) || if (shell->grab_seat &&
(shell->grab_pointer && shell->grab_pointer != grab_device) &&
(shell->grab_pointer_source && (shell->grab_pointer_source != device))) (shell->grab_pointer_source && (shell->grab_pointer_source != device)))
{ {
GIMP_LOG (TOOL_EVENTS, GIMP_LOG (TOOL_EVENTS,
@ -1813,7 +1814,7 @@ gimp_display_shell_stop_scrolling (GimpDisplayShell *shell,
/* We may have ungrabbed the pointer when space was released while /* We may have ungrabbed the pointer when space was released while
* mouse was down, to be able to catch a GDK_BUTTON_RELEASE event. * mouse was down, to be able to catch a GDK_BUTTON_RELEASE event.
*/ */
if (shell->grab_pointer) if (shell->grab_seat)
gimp_display_shell_pointer_ungrab (shell, event); gimp_display_shell_pointer_ungrab (shell, event);
} }

View File

@ -193,9 +193,9 @@ struct _GimpDisplayShell
gboolean size_allocate_center_image; gboolean size_allocate_center_image;
/* the state of gimp_display_shell_tool_events() */ /* the state of gimp_display_shell_tool_events() */
GdkSeat *grab_seat;
GdkDevice *grab_pointer; GdkDevice *grab_pointer;
GdkDevice *grab_pointer_source; GdkDevice *grab_pointer_source;
guint32 grab_pointer_time;
/* the state of gimp_display_shell_zoom_gesture_*() */ /* the state of gimp_display_shell_zoom_gesture_*() */
gdouble last_zoom_scale; gdouble last_zoom_scale;