summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdk/gdksurfaceprivate.h3
-rw-r--r--gdk/gdktoplevel.c73
-rw-r--r--gdk/gdktoplevel.h9
-rw-r--r--gdk/gdktoplevelprivate.h4
-rw-r--r--tests/meson.build1
-rw-r--r--tests/testinhibitshortcuts.c107
6 files changed, 197 insertions, 0 deletions
diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h
index 0c94b5a80f..cbc6e53094 100644
--- a/gdk/gdksurfaceprivate.h
+++ b/gdk/gdksurfaceprivate.h
@@ -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
diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c
index 35ea7f52f6..96e4982627 100644
--- a/gdk/gdktoplevel.c
+++ b/gdk/gdktoplevel.c
@@ -74,6 +74,17 @@ gdk_toplevel_default_supports_edge_constraints (GdkToplevel *toplevel)
}
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)
{
iface->present = gdk_toplevel_default_present;
@@ -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);
+}
diff --git a/gdk/gdktoplevel.h b/gdk/gdktoplevel.h
index 720d0dea72..863c26f3e8 100644
--- a/gdk/gdktoplevel.h
+++ b/gdk/gdktoplevel.h
@@ -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__ */
diff --git a/gdk/gdktoplevelprivate.h b/gdk/gdktoplevelprivate.h
index ac3c5a4ab3..c54d0ac503 100644
--- a/gdk/gdktoplevelprivate.h
+++ b/gdk/gdktoplevelprivate.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;
diff --git a/tests/meson.build b/tests/meson.build
index abf681fcc3..6d57a63c9f 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -125,6 +125,7 @@ gtk_tests = [
['testblur'],
['testtexture'],
['testwindowdrag'],
+ ['testinhibitshortcuts'],
['testtexthistory', ['../gtk/gtktexthistory.c']],
]
diff --git a/tests/testinhibitshortcuts.c b/tests/testinhibitshortcuts.c
new file mode 100644
index 0000000000..fa746ed3e4
--- /dev/null
+++ b/tests/testinhibitshortcuts.c
@@ -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;
+}