wayland: Ensure device grabs generate crossing/focus events
On X11 this is something the windowing system does for us, which the wayland backend should emulate, being grabs completely client-side. So, if the grab and current focus windows differ, make sure we emit focus/crossing events as it corresponds to the grab device.
This commit is contained in:
		| @ -353,6 +353,85 @@ gdk_wayland_device_query_state (GdkDevice        *device, | ||||
|   get_coordinates (wd, win_x, win_y, root_x, root_y); | ||||
| } | ||||
|  | ||||
| static void | ||||
| emulate_crossing (GdkWindow       *window, | ||||
|                   GdkWindow       *subwindow, | ||||
|                   GdkDevice       *device, | ||||
|                   GdkEventType     type, | ||||
|                   GdkCrossingMode  mode, | ||||
|                   guint32          time_) | ||||
| { | ||||
|   GdkEvent *event; | ||||
|  | ||||
|   event = gdk_event_new (type); | ||||
|   event->crossing.window = window ? g_object_ref (window) : NULL; | ||||
|   event->crossing.subwindow = subwindow ? g_object_ref (subwindow) : NULL; | ||||
|   event->crossing.time = time_; | ||||
|   event->crossing.mode = mode; | ||||
|   event->crossing.detail = GDK_NOTIFY_NONLINEAR; | ||||
|   gdk_event_set_device (event, device); | ||||
|   gdk_event_set_source_device (event, device); | ||||
|  | ||||
|   gdk_window_get_device_position_double (window, device, | ||||
|                                          &event->crossing.x, &event->crossing.y, | ||||
|                                          &event->crossing.state); | ||||
|   event->crossing.x_root = event->crossing.x; | ||||
|   event->crossing.y_root = event->crossing.y; | ||||
|  | ||||
|   _gdk_wayland_display_deliver_event (gdk_window_get_display (window), event); | ||||
| } | ||||
|  | ||||
| static void | ||||
| emulate_focus (GdkWindow *window, | ||||
|                GdkDevice *device, | ||||
|                gboolean   focus_in, | ||||
|                guint32    time_) | ||||
| { | ||||
|   GdkEvent *event; | ||||
|  | ||||
|   event = gdk_event_new (GDK_FOCUS_CHANGE); | ||||
|   event->focus_change.window = g_object_ref (window); | ||||
|   event->focus_change.in = focus_in; | ||||
|   gdk_event_set_device (event, device); | ||||
|   gdk_event_set_source_device (event, device); | ||||
|  | ||||
|   _gdk_wayland_display_deliver_event (gdk_window_get_display (window), event); | ||||
| } | ||||
|  | ||||
| static void | ||||
| device_emit_grab_crossing (GdkDevice       *device, | ||||
|                            GdkWindow       *from, | ||||
|                            GdkWindow       *to, | ||||
|                            GdkCrossingMode  mode, | ||||
|                            guint32          time_) | ||||
| { | ||||
|   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) | ||||
|     { | ||||
|       if (from) | ||||
|         emulate_focus (from, device, FALSE, time_); | ||||
|       if (to) | ||||
|         emulate_focus (to, device, TRUE, time_); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       if (from) | ||||
|         emulate_crossing (from, to, device, GDK_LEAVE_NOTIFY, mode, time_); | ||||
|       if (to) | ||||
|         emulate_crossing (to, from, device, GDK_ENTER_NOTIFY, mode, time_); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static GdkWindow * | ||||
| gdk_wayland_device_get_focus (GdkDevice *device) | ||||
| { | ||||
|   GdkWaylandDeviceData *wayland_device = GDK_WAYLAND_DEVICE (device)->device; | ||||
|  | ||||
|   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) | ||||
|     return wayland_device->keyboard_focus; | ||||
|   else | ||||
|     return wayland_device->pointer_focus; | ||||
| } | ||||
|  | ||||
| static GdkGrabStatus | ||||
| gdk_wayland_device_grab (GdkDevice    *device, | ||||
|                          GdkWindow    *window, | ||||
| @ -363,6 +442,10 @@ gdk_wayland_device_grab (GdkDevice    *device, | ||||
|                          guint32       time_) | ||||
| { | ||||
|   GdkWaylandDeviceData *wayland_device = GDK_WAYLAND_DEVICE (device)->device; | ||||
|   GdkWindow *prev_focus = gdk_wayland_device_get_focus (device); | ||||
|  | ||||
|   if (prev_focus != window) | ||||
|     device_emit_grab_crossing (device, prev_focus, window, GDK_CROSSING_GRAB, time_); | ||||
|  | ||||
|   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) | ||||
|     { | ||||
| @ -412,13 +495,22 @@ gdk_wayland_device_ungrab (GdkDevice *device, | ||||
|   GdkWaylandDeviceData *wayland_device = GDK_WAYLAND_DEVICE (device)->device; | ||||
|   GdkDisplay *display; | ||||
|   GdkDeviceGrabInfo *grab; | ||||
|   GdkWindow *focus, *prev_focus = NULL; | ||||
|  | ||||
|   display = gdk_device_get_display (device); | ||||
|  | ||||
|   grab = _gdk_display_get_last_device_grab (display, device); | ||||
|  | ||||
|   if (grab) | ||||
|     grab->serial_end = grab->serial_start; | ||||
|     { | ||||
|       grab->serial_end = grab->serial_start; | ||||
|       prev_focus = grab->window; | ||||
|     } | ||||
|  | ||||
|   focus = gdk_wayland_device_get_focus (device); | ||||
|  | ||||
|   if (focus != prev_focus) | ||||
|     device_emit_grab_crossing (device, prev_focus, focus, GDK_CROSSING_UNGRAB, time_); | ||||
|  | ||||
|   if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) | ||||
|     { | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Carlos Garnacho
					Carlos Garnacho