x11: update inhibit shortcuts on grab broken
authorOlivier Fourdan <ofourdan@redhat.com>
Tue, 31 Mar 2020 12:38:08 +0000 (14:38 +0200)
committerOlivier Fourdan <ofourdan@redhat.com>
Tue, 19 May 2020 12:51:25 +0000 (14:51 +0200)
On X11, shortcuts inhibition is emulated using a grab on the keyboard.

So if another widget ungrabs the keyboard behind our back (for example
when a popup window is dismissed) that effectively disables the effects
of the shortcut inhibition on the surface and we need to update the
shortcut inhibition status accordingly.

Check for "grab-broken" events on the surface and clear existing
shortcuts inhibition for the matching seat, so that the client can be
notified and may decide to re-enable shortcut inhibition if desired.

gdk/x11/gdksurface-x11.c

index 75a931f16c936e913d62b3686ee5c6fed0600c0d..30eb411d62381b1fb8002a4918d0828312e32e70 100644 (file)
@@ -106,6 +106,8 @@ static void     set_wm_name                       (GdkDisplay  *display,
                                                   const gchar *name);
 static void     move_to_current_desktop           (GdkSurface *surface);
 static void     gdk_x11_toplevel_state_callback   (GdkSurface *surface);
+static gboolean gdk_x11_toplevel_event_callback   (GdkSurface *surface,
+                                                   GdkEvent   *gdk_event);
 
 /* Return whether time1 is considered later than time2 as far as xserver
  * time is concerned.  Accounts for wraparound.
@@ -149,6 +151,9 @@ _gdk_x11_surface_get_toplevel (GdkSurface *surface)
       g_signal_connect (surface, "notify::state",
                         G_CALLBACK (gdk_x11_toplevel_state_callback),
                         NULL);
+      g_signal_connect (surface, "event",
+                        G_CALLBACK (gdk_x11_toplevel_event_callback),
+                        NULL);
     }
 
   return impl->toplevel;
@@ -449,6 +454,9 @@ gdk_x11_surface_finalize (GObject *object)
   g_signal_handlers_disconnect_by_func (GDK_SURFACE (impl),
                                         gdk_x11_toplevel_state_callback,
                                         NULL);
+  g_signal_handlers_disconnect_by_func (GDK_SURFACE (impl),
+                                        gdk_x11_toplevel_event_callback,
+                                        NULL);
 
   _gdk_x11_surface_grab_check_destroy (GDK_SURFACE (impl));
 
@@ -5033,6 +5041,29 @@ gdk_x11_toplevel_state_callback (GdkSurface *surface)
     gdk_x11_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface));
 }
 
+static gboolean
+gdk_x11_toplevel_event_callback (GdkSurface *surface,
+                                 GdkEvent   *gdk_event)
+{
+  GdkSeat *gdk_seat;
+
+  if (!surface->shortcuts_inhibited)
+    return FALSE;
+
+  if (gdk_event_get_event_type (gdk_event) != GDK_GRAB_BROKEN)
+    return FALSE;
+
+  gdk_seat = gdk_surface_get_seat_from_event (surface, gdk_event);
+  if (gdk_seat != surface->current_shortcuts_inhibited_seat)
+    return FALSE;
+
+  surface->current_shortcuts_inhibited_seat = NULL;
+  surface->shortcuts_inhibited = FALSE;
+  g_object_notify (G_OBJECT (surface), "shortcuts-inhibited");
+
+  return FALSE;
+}
+
 static void
 gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
 {