[gtk: 6/9] x11: Implement inhibit_system_shortcuts API



commit 83027c68f112eff618a36682ad90a87a76bb92ef
Author: Olivier Fourdan <ofourdan redhat com>
Date:   Fri Mar 20 15:24:06 2020 +0100

    x11: Implement inhibit_system_shortcuts API
    
    On X11, there is no such equivalent to the inhibit shortcut protocol
    found on Wayland.
    
    To implement the inhibit_system_shortcuts API on X11, we emulate the
    same behavior using grabs on the keyboard.
    
    To avoid keeping active grabs on the keyboard that would affect other
    X11 applications even when the surface isn't focused, the X11
    implementation takes care of releasing the grabs as soon as the toplevel
    loses focus.

 gdk/x11/gdksurface-x11.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)
---
diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c
index d4348a4e18..3607629819 100644
--- a/gdk/x11/gdksurface-x11.c
+++ b/gdk/x11/gdksurface-x11.c
@@ -109,6 +109,7 @@ static void     set_wm_name                       (GdkDisplay  *display,
                                                   Window       xwindow,
                                                   const gchar *name);
 static void     move_to_current_desktop           (GdkSurface *surface);
+static void     gdk_x11_toplevel_state_callback   (GdkSurface *surface);
 
 /* Return whether time1 is considered later than time2 as far as xserver
  * time is concerned.  Accounts for wraparound.
@@ -148,6 +149,9 @@ _gdk_x11_surface_get_toplevel (GdkSurface *surface)
     {
       impl->toplevel = g_new0 (GdkToplevelX11, 1);
       impl->toplevel->have_focused = FALSE;
+      g_signal_connect (surface, "notify::state",
+                        G_CALLBACK (gdk_x11_toplevel_state_callback),
+                        NULL);
     }
 
   return impl->toplevel;
@@ -445,6 +449,10 @@ gdk_x11_surface_finalize (GObject *object)
   if (impl->toplevel->in_frame)
     unhook_surface_changed (GDK_SURFACE (impl));
 
+  g_signal_handlers_disconnect_by_func (GDK_SURFACE (impl),
+                                        gdk_x11_toplevel_state_callback,
+                                        NULL);
+
   _gdk_x11_surface_grab_check_destroy (GDK_SURFACE (impl));
 
   if (!GDK_SURFACE_DESTROYED (impl))
@@ -4725,6 +4733,9 @@ gdk_x11_toplevel_set_property (GObject      *object,
       g_object_notify_by_pspec (G_OBJECT (surface), pspec);
       break;
 
+    case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4785,6 +4796,10 @@ gdk_x11_toplevel_get_property (GObject    *object,
       g_value_set_enum (value, surface->fullscreen_mode);
       break;
 
+    case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
+      g_value_set_boolean (value, surface->shortcuts_inhibited);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4908,6 +4923,63 @@ gdk_x11_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
   return gdk_x11_surface_supports_edge_constraints (GDK_SURFACE (toplevel));
 }
 
+static void
+gdk_x11_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
+                                           GdkEvent    *gdk_event)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+  GdkSeat *gdk_seat;
+  GdkGrabStatus status;
+
+  if (surface->shortcuts_inhibited)
+    return; /* Already inhibited */
+
+  if (!(surface->state & GDK_SURFACE_STATE_FOCUSED))
+    return;
+
+  gdk_seat = gdk_surface_get_seat_from_event (surface, gdk_event);
+
+  if (!(gdk_seat_get_capabilities (gdk_seat) & GDK_SEAT_CAPABILITY_KEYBOARD))
+    return;
+
+  status = gdk_seat_grab (gdk_seat, surface, GDK_SEAT_CAPABILITY_KEYBOARD,
+                          TRUE, NULL, gdk_event, NULL, NULL);
+
+  if (status != GDK_GRAB_SUCCESS)
+    return;
+
+  surface->shortcuts_inhibited = TRUE;
+  surface->current_shortcuts_inhibited_seat = gdk_seat;
+  g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+}
+
+static void
+gdk_x11_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
+{
+  GdkSurface *surface = GDK_SURFACE (toplevel);
+  GdkSeat *gdk_seat;
+
+  if (!surface->shortcuts_inhibited)
+    return; /* Not inhibited */
+
+  gdk_seat = surface->current_shortcuts_inhibited_seat;
+  gdk_seat_ungrab (gdk_seat);
+  surface->current_shortcuts_inhibited_seat = NULL;
+
+  surface->shortcuts_inhibited = FALSE;
+  g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
+}
+
+static void
+gdk_x11_toplevel_state_callback (GdkSurface *surface)
+{
+  if (surface->state & GDK_SURFACE_STATE_FOCUSED)
+    return;
+
+  if (surface->shortcuts_inhibited)
+    gdk_x11_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface));
+}
+
 static void
 gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
 {
@@ -4917,6 +4989,8 @@ gdk_x11_toplevel_iface_init (GdkToplevelInterface *iface)
   iface->focus = gdk_x11_toplevel_focus;
   iface->show_window_menu = gdk_x11_toplevel_show_window_menu;
   iface->supports_edge_constraints = gdk_x11_toplevel_supports_edge_constraints;
+  iface->inhibit_system_shortcuts = gdk_x11_toplevel_inhibit_system_shortcuts;
+  iface->restore_system_shortcuts = gdk_x11_toplevel_restore_system_shortcuts;
 }
 
 typedef struct {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]