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.
This commit is contained in:
Olivier Fourdan 2020-03-20 15:24:06 +01:00
parent 44931a66df
commit 83027c68f1

View File

@ -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 {