forked from AuroraMiddleware/gtk
gdk: Add gdk_toplevel_inhibit_system_shortcuts API
With the removal of grabs from the public API, we need a replacement API to let applications bypass system keyboard shortcuts. A typical use case for this API is remote desktop or virtual machine viewers which need to inhibit the default system keyboard shortcuts so that the remote session or virtual host gets those instead of the local environment. Close: https://gitlab.gnome.org/GNOME/gtk/issues/982
This commit is contained in:
parent
da47ccaf3c
commit
3e1f59af61
@ -102,6 +102,9 @@ struct _GdkSurface
|
||||
GdkDrawContext *paint_context;
|
||||
|
||||
cairo_region_t *opaque_region;
|
||||
|
||||
guint shortcuts_inhibited : 1;
|
||||
GdkSeat *current_shortcuts_inhibited_seat;
|
||||
};
|
||||
|
||||
struct _GdkSurfaceClass
|
||||
|
@ -73,6 +73,17 @@ gdk_toplevel_default_supports_edge_constraints (GdkToplevel *toplevel)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_toplevel_default_inhibit_system_shortcuts (GdkToplevel *toplevel,
|
||||
GdkEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_toplevel_default_restore_system_shortcuts (GdkToplevel *toplevel)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_toplevel_default_init (GdkToplevelInterface *iface)
|
||||
{
|
||||
@ -82,6 +93,8 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface)
|
||||
iface->focus = gdk_toplevel_default_focus;
|
||||
iface->show_window_menu = gdk_toplevel_default_show_window_menu;
|
||||
iface->supports_edge_constraints = gdk_toplevel_default_supports_edge_constraints;
|
||||
iface->inhibit_system_shortcuts = gdk_toplevel_default_inhibit_system_shortcuts;
|
||||
iface->restore_system_shortcuts = gdk_toplevel_default_restore_system_shortcuts;
|
||||
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_flags ("state",
|
||||
@ -137,6 +150,12 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface)
|
||||
GDK_TYPE_FULLSCREEN_MODE,
|
||||
GDK_FULLSCREEN_ON_CURRENT_MONITOR,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY));
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_boolean ("shortcuts-inhibited",
|
||||
"Shortcuts inhibited",
|
||||
"Whether keyboard shortcuts are inhibited",
|
||||
FALSE,
|
||||
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY));
|
||||
}
|
||||
|
||||
guint
|
||||
@ -152,6 +171,7 @@ gdk_toplevel_install_properties (GObjectClass *object_class,
|
||||
g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_DECORATED, "decorated");
|
||||
g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_DELETABLE, "deletable");
|
||||
g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_FULLSCREEN_MODE, "fullscreen-mode");
|
||||
g_object_class_override_property (object_class, first_prop + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED, "shortcuts-inhibited");
|
||||
|
||||
return GDK_TOPLEVEL_NUM_PROPERTIES;
|
||||
}
|
||||
@ -439,3 +459,56 @@ gdk_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
|
||||
|
||||
return GDK_TOPLEVEL_GET_IFACE (toplevel)->supports_edge_constraints (toplevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_toplevel_inhibit_system_shortcuts:
|
||||
* @toplevel: the #GdkToplevel requesting system keyboard shortcuts
|
||||
* @event: (nullable): the #GdkEvent that is triggering the inhibit
|
||||
* request, or %NULL if none is available.
|
||||
*
|
||||
* Requests that the @toplevel inhibit the system shortcuts, asking the
|
||||
* desktop environment/windowing system to let all keyboard events reach
|
||||
* the surface, as long as it is focused, instead of triggering system
|
||||
* actions.
|
||||
*
|
||||
* If granted, the rerouting remains active until the default shortcuts
|
||||
* processing is restored with gdk_toplevel_restore_system_shortcuts(),
|
||||
* or the request is revoked by the desktop enviroment, windowing system
|
||||
* or the user.
|
||||
*
|
||||
* A typical use case for this API is remote desktop or virtual machine
|
||||
* viewers which need to inhibit the default system keyboard shortcuts
|
||||
* so that the remote session or virtual host gets those instead of the
|
||||
* local environment.
|
||||
*
|
||||
* The windowing system or desktop environment may ask the user to grant
|
||||
* or deny the request or even choose to ignore the request entirely.
|
||||
*
|
||||
* The caller can be notified whenever the request is granted or revoked
|
||||
* by listening to the GdkToplevel::shortcuts-inhibited property.
|
||||
*
|
||||
*/
|
||||
void
|
||||
gdk_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
|
||||
GdkEvent *event)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
|
||||
|
||||
GDK_TOPLEVEL_GET_IFACE (toplevel)->inhibit_system_shortcuts (toplevel,
|
||||
event);
|
||||
}
|
||||
|
||||
/**
|
||||
* gdk_toplevel_restore_system_shortcuts:
|
||||
* @toplevel: a #GdkToplevel
|
||||
*
|
||||
* Restore default system keyboard shortcuts which were previously
|
||||
* requested to be inhibited by gdk_toplevel_inhibit_system_shortcuts().
|
||||
*/
|
||||
void
|
||||
gdk_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
|
||||
{
|
||||
g_return_if_fail (GDK_IS_TOPLEVEL (toplevel));
|
||||
|
||||
GDK_TOPLEVEL_GET_IFACE (toplevel)->restore_system_shortcuts (toplevel);
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#error "Only <gdk/gdk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gdk/gdkseat.h>
|
||||
#include <gdk/gdksurface.h>
|
||||
#include <gdk/gdktoplevellayout.h>
|
||||
|
||||
@ -87,6 +88,14 @@ void gdk_toplevel_set_deletable (GdkToplevel *toplevel,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gdk_toplevel_supports_edge_constraints (GdkToplevel *toplevel);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
|
||||
GdkEvent *event);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gdk_toplevel_restore_system_shortcuts (GdkToplevel *toplevel);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_TOPLEVEL_H__ */
|
||||
|
@ -21,6 +21,9 @@ struct _GdkToplevelInterface
|
||||
gboolean (* show_window_menu) (GdkToplevel *toplevel,
|
||||
GdkEvent *event);
|
||||
gboolean (* supports_edge_constraints) (GdkToplevel *toplevel);
|
||||
void (* inhibit_system_shortcuts) (GdkToplevel *toplevel,
|
||||
GdkEvent *event);
|
||||
void (* restore_system_shortcuts) (GdkToplevel *toplevel);
|
||||
};
|
||||
|
||||
typedef enum
|
||||
@ -34,6 +37,7 @@ typedef enum
|
||||
GDK_TOPLEVEL_PROP_DECORATED,
|
||||
GDK_TOPLEVEL_PROP_DELETABLE,
|
||||
GDK_TOPLEVEL_PROP_FULLSCREEN_MODE,
|
||||
GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED,
|
||||
GDK_TOPLEVEL_NUM_PROPERTIES
|
||||
} GdkToplevelProperties;
|
||||
|
||||
|
@ -125,6 +125,7 @@ gtk_tests = [
|
||||
['testblur'],
|
||||
['testtexture'],
|
||||
['testwindowdrag'],
|
||||
['testinhibitshortcuts'],
|
||||
['testtexthistory', ['../gtk/gtktexthistory.c']],
|
||||
]
|
||||
|
||||
|
107
tests/testinhibitshortcuts.c
Normal file
107
tests/testinhibitshortcuts.c
Normal file
@ -0,0 +1,107 @@
|
||||
/* testinhibitshortcuts.c
|
||||
|
||||
Copyright (C) 2017 Red Hat
|
||||
Author: Olivier Fourdan <ofourdan@redhat.com>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void
|
||||
on_shortcuts_inhibit_change (GdkSurface *surface, GParamSpec *pspec, gpointer data)
|
||||
{
|
||||
GtkWidget *button = GTK_WIDGET (data);
|
||||
gboolean button_active;
|
||||
gboolean shortcuts_inhibited;
|
||||
|
||||
g_object_get (GDK_TOPLEVEL (surface), "shortcuts-inhibited", &shortcuts_inhibited, NULL);
|
||||
|
||||
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), FALSE);
|
||||
|
||||
button_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
|
||||
|
||||
if (button_active != shortcuts_inhibited)
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), shortcuts_inhibited);
|
||||
}
|
||||
|
||||
static void
|
||||
on_button_toggle (GtkWidget *button, gpointer data)
|
||||
{
|
||||
GdkSurface *surface = GDK_SURFACE (data);
|
||||
GdkEvent *event;
|
||||
|
||||
if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
|
||||
{
|
||||
gdk_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface));
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_check_button_set_inconsistent (GTK_CHECK_BUTTON (button), TRUE);
|
||||
event = gtk_get_current_event ();
|
||||
gdk_toplevel_inhibit_system_shortcuts (GDK_TOPLEVEL (surface), event);
|
||||
}
|
||||
|
||||
static void
|
||||
quit_cb (GtkWidget *widget,
|
||||
gpointer user_data)
|
||||
{
|
||||
gboolean *done = user_data;
|
||||
|
||||
*done = TRUE;
|
||||
|
||||
g_main_context_wakeup (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GdkSurface *surface;
|
||||
GtkWidget *window;
|
||||
GtkWidget *button;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *text_view;
|
||||
gboolean done = FALSE;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
window = gtk_window_new ();
|
||||
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
||||
gtk_widget_realize (window);
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (window));
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||||
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||||
|
||||
text_view = gtk_text_view_new ();
|
||||
gtk_widget_set_hexpand (text_view, TRUE);
|
||||
gtk_widget_set_vexpand (text_view, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (vbox), text_view);
|
||||
|
||||
button = gtk_check_button_new_with_label ("Inhibit system keyboard shorcuts");
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (vbox), button);
|
||||
g_signal_connect (G_OBJECT (button), "toggled",
|
||||
G_CALLBACK (on_button_toggle), surface);
|
||||
|
||||
g_signal_connect (G_OBJECT (surface), "notify::shortcuts-inhibited",
|
||||
G_CALLBACK (on_shortcuts_inhibit_change), button);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
while (!done)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user