summaryrefslogtreecommitdiff
path: root/gdk/x11
diff options
context:
space:
mode:
authorOlivier Fourdan <ofourdan@redhat.com>2020-03-20 15:24:06 +0100
committerOlivier Fourdan <ofourdan@redhat.com>2020-03-30 18:25:36 +0200
commit83027c68f112eff618a36682ad90a87a76bb92ef (patch)
tree3ed5425589382a39305c3a4d82fd1653c87ab534 /gdk/x11
parent44931a66dfa8560e98501c0a0a371d9a642fb4c6 (diff)
downloadgtk+-83027c68f112eff618a36682ad90a87a76bb92ef.tar.gz
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.
Diffstat (limited to 'gdk/x11')
-rw-r--r--gdk/x11/gdksurface-x11.c74
1 files changed, 74 insertions, 0 deletions
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;
@@ -4909,6 +4924,63 @@ gdk_x11_toplevel_supports_edge_constraints (GdkToplevel *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)
{
iface->present = gdk_x11_toplevel_present;
@@ -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 {