GdkDrawContext *paint_context;
cairo_region_t *opaque_region;
+
+ guint shortcuts_inhibited : 1;
+ GdkSeat *current_shortcuts_inhibited_seat;
};
struct _GdkSurfaceClass
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)
{
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",
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
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;
}
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);
+}
#error "Only <gdk/gdk.h> can be included directly."
#endif
+#include <gdk/gdkseat.h>
#include <gdk/gdksurface.h>
#include <gdk/gdktoplevellayout.h>
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__ */
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
GDK_TOPLEVEL_PROP_DECORATED,
GDK_TOPLEVEL_PROP_DELETABLE,
GDK_TOPLEVEL_PROP_FULLSCREEN_MODE,
+ GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED,
GDK_TOPLEVEL_NUM_PROPERTIES
} GdkToplevelProperties;
['testblur'],
['testtexture'],
['testwindowdrag'],
+ ['testinhibitshortcuts'],
['testtexthistory', ['../gtk/gtktexthistory.c']],
]
--- /dev/null
+/* 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;
+}