mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
gdk-win32: implement basic inhibit-system-shortcuts
This is largely adapted from commit 83027c68f1
("11: Implement
inhibit_system_shortcuts API"), with similar rationale:
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.
Note that Windows has low-level keyboard hooks that could help achieve
the expected behaviour. This is implemented by spice-gtk & gtk-vnc for
example, but correctness isn't obvious. I left a TODO comment.
This patch helps implementing remote desktop widgets with GTK4, since
currently on win32 backend Alt-Tab and such are always left to the
system unless there is keyboard grab (which can't be requested by the
client API anymore, afaict).
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
parent
a92aea4c0e
commit
cf04a3c99d
@ -60,6 +60,7 @@ static void compute_toplevel_size (GdkSurface *surface,
|
||||
gboolean update_geometry,
|
||||
int *width,
|
||||
int *height);
|
||||
static void gdk_win32_toplevel_state_callback (GdkSurface *surface);
|
||||
|
||||
static gpointer parent_class = NULL;
|
||||
static GSList *modal_window_stack = NULL;
|
||||
@ -211,6 +212,10 @@ gdk_surface_win32_finalize (GObject *object)
|
||||
g_assert (surface->transient_owner == NULL);
|
||||
g_assert (surface->transient_children == NULL);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (GDK_SURFACE (object),
|
||||
gdk_win32_toplevel_state_callback,
|
||||
NULL);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -662,6 +667,13 @@ _gdk_win32_display_create_surface (GdkDisplay *display,
|
||||
impl->hdc = GetDC (impl->handle);
|
||||
impl->inhibit_configure = TRUE;
|
||||
|
||||
if (surface_type == GDK_SURFACE_TOPLEVEL)
|
||||
{
|
||||
g_signal_connect (surface, "notify::state",
|
||||
G_CALLBACK (gdk_win32_toplevel_state_callback),
|
||||
NULL);
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
@ -4704,6 +4716,10 @@ gdk_win32_popup_get_property (GObject *object,
|
||||
g_value_set_boolean (value, surface->autohide);
|
||||
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;
|
||||
@ -4730,6 +4746,9 @@ gdk_win32_popup_set_property (GObject *object,
|
||||
surface->autohide = g_value_get_boolean (value);
|
||||
break;
|
||||
|
||||
case LAST_PROP + GDK_TOPLEVEL_PROP_SHORTCUTS_INHIBITED:
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -5006,6 +5025,65 @@ gdk_win32_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_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_TOPLEVEL_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;
|
||||
|
||||
// TODO: install a WH_KEYBOARD_LL hook to take alt-tab/win etc.
|
||||
|
||||
surface->shortcuts_inhibited = TRUE;
|
||||
surface->current_shortcuts_inhibited_seat = gdk_seat;
|
||||
g_object_notify (G_OBJECT (toplevel), "shortcuts-inhibited");
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_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_win32_toplevel_state_callback (GdkSurface *surface)
|
||||
{
|
||||
if (surface->state & GDK_TOPLEVEL_STATE_FOCUSED)
|
||||
return;
|
||||
|
||||
if (surface->shortcuts_inhibited)
|
||||
gdk_win32_toplevel_restore_system_shortcuts (GDK_TOPLEVEL (surface));
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_win32_toplevel_iface_init (GdkToplevelInterface *iface)
|
||||
{
|
||||
@ -5015,6 +5093,8 @@ gdk_win32_toplevel_iface_init (GdkToplevelInterface *iface)
|
||||
iface->focus = gdk_win32_toplevel_focus;
|
||||
iface->show_window_menu = gdk_win32_toplevel_show_window_menu;
|
||||
iface->supports_edge_constraints = gdk_win32_toplevel_supports_edge_constraints;
|
||||
iface->inhibit_system_shortcuts = gdk_win32_toplevel_inhibit_system_shortcuts;
|
||||
iface->restore_system_shortcuts = gdk_win32_toplevel_restore_system_shortcuts;
|
||||
iface->begin_resize = gdk_win32_toplevel_begin_resize;
|
||||
iface->begin_move = gdk_win32_toplevel_begin_move;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user