Merge branch 'issue982' into 'master'

gdk: Add gdk_toplevel_inhibit_system_shortcuts API

Closes #982

See merge request GNOME/gtk!1542
This commit is contained in:
Matthias Clasen 2020-03-30 17:41:12 +00:00
commit 96f0c26306
12 changed files with 406 additions and 28 deletions

View File

@ -1499,6 +1499,9 @@ gdk_broadway_toplevel_set_property (GObject *object,
case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
break;
case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1541,6 +1544,10 @@ gdk_broadway_toplevel_get_property (GObject *object,
case LAST_PROP + GDK_TOPLEVEL_PROP_DELETABLE:
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;

View File

@ -181,6 +181,8 @@ void gdk_surface_get_unscaled_size (GdkSurface *surface,
int *unscaled_width,
int *unscaled_height);
gboolean gdk_surface_handle_event (GdkEvent *event);
GdkSeat * gdk_surface_get_seat_from_event (GdkSurface *surface,
GdkEvent *event);
/*****************************************
* Interfaces provided by windowing code *

View File

@ -3015,3 +3015,22 @@ gdk_surface_translate_coordinates (GdkSurface *from,
return TRUE;
}
GdkSeat *
gdk_surface_get_seat_from_event (GdkSurface *surface,
GdkEvent *event)
{
if (event)
{
GdkDevice *device = gdk_event_get_device (event);
GdkSeat *seat = NULL;
device = gdk_event_get_device (event);
if (device)
seat = gdk_device_get_seat (device);
if (seat)
return seat;
}
return gdk_display_get_default_seat (surface->display);
}

View File

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

View File

@ -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);
}

View File

@ -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__ */

View File

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

View File

@ -4112,9 +4112,9 @@ gdk_wayland_surface_set_transient_for_exported (GdkSurface *surface,
static struct zwp_keyboard_shortcuts_inhibitor_v1 *
gdk_wayland_surface_get_inhibitor (GdkWaylandSurface *impl,
struct wl_seat *seat)
GdkSeat *gdk_seat)
{
return g_hash_table_lookup (impl->shortcuts_inhibitors, seat);
return g_hash_table_lookup (impl->shortcuts_inhibitors, gdk_seat);
}
void
@ -4130,14 +4130,14 @@ gdk_wayland_surface_inhibit_shortcuts (GdkSurface *surface,
if (display->keyboard_shortcuts_inhibit == NULL)
return;
if (gdk_wayland_surface_get_inhibitor (impl, seat))
return; /* Already inhibitted */
if (gdk_wayland_surface_get_inhibitor (impl, gdk_seat))
return; /* Already inhibited */
inhibitor =
zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts (
display->keyboard_shortcuts_inhibit, wl_surface, seat);
g_hash_table_insert (impl->shortcuts_inhibitors, seat, inhibitor);
g_hash_table_insert (impl->shortcuts_inhibitors, gdk_seat, inhibitor);
}
void
@ -4145,15 +4145,14 @@ gdk_wayland_surface_restore_shortcuts (GdkSurface *surface,
GdkSeat *gdk_seat)
{
GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
struct wl_seat *seat = gdk_wayland_seat_get_wl_seat (gdk_seat);
struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
inhibitor = gdk_wayland_surface_get_inhibitor (impl, seat);
inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat);
if (inhibitor == NULL)
return; /* Not inhibitted */
zwp_keyboard_shortcuts_inhibitor_v1_destroy (inhibitor);
g_hash_table_remove (impl->shortcuts_inhibitors, seat);
g_hash_table_remove (impl->shortcuts_inhibitors, gdk_seat);
}
GdkSurface *
@ -4360,6 +4359,9 @@ gdk_wayland_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;
@ -4411,6 +4413,10 @@ gdk_wayland_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;
@ -4534,6 +4540,70 @@ gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
return gdk_wayland_surface_supports_edge_constraints (GDK_SURFACE (toplevel));
}
static void
inhibitor_active (void *data,
struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
{
GdkToplevel *toplevel = GDK_TOPLEVEL (data);
GdkSurface *surface = GDK_SURFACE (toplevel);
surface->shortcuts_inhibited = TRUE;
g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
}
static void
inhibitor_inactive (void *data,
struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor)
{
GdkToplevel *toplevel = GDK_TOPLEVEL (data);
GdkSurface *surface = GDK_SURFACE (toplevel);
surface->shortcuts_inhibited = FALSE;
g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
}
static const struct zwp_keyboard_shortcuts_inhibitor_v1_listener
zwp_keyboard_shortcuts_inhibitor_listener = {
inhibitor_active,
inhibitor_inactive,
};
static void
gdk_wayland_toplevel_inhibit_system_shortcuts (GdkToplevel *toplevel,
GdkEvent *event)
{
struct zwp_keyboard_shortcuts_inhibitor_v1 *inhibitor;
GdkSurface *surface = GDK_SURFACE (toplevel);
GdkWaylandSurface *impl= GDK_WAYLAND_SURFACE (surface);
GdkSeat *gdk_seat;
if (surface->shortcuts_inhibited)
return;
gdk_seat = gdk_surface_get_seat_from_event (surface, event);
gdk_wayland_surface_inhibit_shortcuts (surface, gdk_seat);
inhibitor = gdk_wayland_surface_get_inhibitor (impl, gdk_seat);
if (!inhibitor)
return;
surface->current_shortcuts_inhibited_seat = gdk_seat;
zwp_keyboard_shortcuts_inhibitor_v1_add_listener
(inhibitor, &zwp_keyboard_shortcuts_inhibitor_listener, toplevel);
}
static void
gdk_wayland_toplevel_restore_system_shortcuts (GdkToplevel *toplevel)
{
GdkSurface *surface = GDK_SURFACE (toplevel);
gdk_wayland_surface_restore_shortcuts (surface,
surface->current_shortcuts_inhibited_seat);
surface->current_shortcuts_inhibited_seat = NULL;
surface->shortcuts_inhibited = FALSE;
g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
}
static void
gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
{
@ -4543,6 +4613,8 @@ gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
iface->focus = gdk_wayland_toplevel_focus;
iface->show_window_menu = gdk_wayland_toplevel_show_window_menu;
iface->supports_edge_constraints = gdk_wayland_toplevel_supports_edge_constraints;
iface->inhibit_system_shortcuts = gdk_wayland_toplevel_inhibit_system_shortcuts;
iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
}
typedef struct

View File

@ -4907,6 +4907,9 @@ gdk_win32_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;
@ -4953,6 +4956,10 @@ gdk_win32_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;

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))
@ -4552,10 +4560,10 @@ gdk_x11_popup_init (GdkX11Popup *popup)
}
static void
gdk_wayland_popup_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
gdk_x11_popup_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
@ -4576,10 +4584,10 @@ gdk_wayland_popup_get_property (GObject *object,
}
static void
gdk_wayland_popup_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
gdk_x11_popup_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
@ -4607,8 +4615,8 @@ gdk_x11_popup_class_init (GdkX11PopupClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->get_property = gdk_wayland_popup_get_property;
object_class->set_property = gdk_wayland_popup_set_property;
object_class->get_property = gdk_x11_popup_get_property;
object_class->set_property = gdk_x11_popup_set_property;
gdk_popup_install_properties (object_class, 1);
}
@ -4675,10 +4683,10 @@ gdk_x11_toplevel_init (GdkX11Toplevel *toplevel)
{
}
static void
gdk_wayland_toplevel_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
gdk_x11_toplevel_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
@ -4725,6 +4733,9 @@ gdk_wayland_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;
@ -4732,10 +4743,10 @@ gdk_wayland_toplevel_set_property (GObject *object,
}
static void
gdk_wayland_toplevel_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
gdk_x11_toplevel_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GdkSurface *surface = GDK_SURFACE (object);
@ -4785,6 +4796,10 @@ gdk_wayland_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;
@ -4796,8 +4811,8 @@ gdk_x11_toplevel_class_init (GdkX11ToplevelClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->get_property = gdk_wayland_toplevel_get_property;
object_class->set_property = gdk_wayland_toplevel_set_property;
object_class->get_property = gdk_x11_toplevel_get_property;
object_class->set_property = gdk_x11_toplevel_set_property;
gdk_toplevel_install_properties (object_class, LAST_PROP);
}
@ -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 {

View File

@ -125,6 +125,7 @@ gtk_tests = [
['testblur'],
['testtexture'],
['testwindowdrag'],
['testinhibitshortcuts'],
['testtexthistory', ['../gtk/gtktexthistory.c']],
]

View 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;
}