From b15ba64ec9b495a51307773bd71f72d6e80b2700 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 22 Apr 2019 21:31:33 +0000 Subject: [PATCH] surface: Add an autohide property This api is meant to mimic xdg-popover.grab - we show the surface, and dismiss it when we get events on other surfaces. For foreign surfaces, the compositor handles that for us; for our own, we check outselves before delivering events to GTK. --- docs/reference/gdk/gdk4-sections.txt | 1 + gdk/gdksurface.c | 88 +++++++++++++++++++++++++++- gdk/gdksurface.h | 4 +- gdk/gdksurfaceprivate.h | 1 + 4 files changed, 91 insertions(+), 3 deletions(-) diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt index e3fa979d66..6338ab03cc 100644 --- a/docs/reference/gdk/gdk4-sections.txt +++ b/docs/reference/gdk/gdk4-sections.txt @@ -186,6 +186,7 @@ gdk_surface_get_surface_type gdk_surface_get_display gdk_surface_show gdk_surface_show_unraised +gdk_surface_show_with_auto_dismissal gdk_surface_hide gdk_surface_is_destroyed gdk_surface_is_visible diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 4a977c25d1..6c516b77f2 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -85,6 +85,7 @@ enum { PROP_FRAME_CLOCK, PROP_STATE, PROP_MAPPED, + PROP_AUTOHIDE, LAST_PROP }; @@ -498,6 +499,13 @@ gdk_surface_class_init (GdkSurfaceClass *klass) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + properties[PROP_AUTOHIDE] = + g_param_spec_boolean ("autohide", + P_("Autohide"), + P_("Whether to dismiss the surface on outside clicks"), + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, LAST_PROP, properties); /** @@ -676,6 +684,10 @@ gdk_surface_set_property (GObject *object, gdk_surface_set_frame_clock (surface, GDK_FRAME_CLOCK (g_value_get_object (value))); break; + case PROP_AUTOHIDE: + surface->autohide = g_value_get_boolean (value); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -712,6 +724,10 @@ gdk_surface_get_property (GObject *object, g_value_set_boolean (value, GDK_SURFACE_IS_MAPPED (surface)); break; + case PROP_AUTOHIDE: + g_value_set_boolean (value, surface->autohide); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -797,8 +813,10 @@ gdk_surface_new_temp (GdkDisplay *display, * gdk_surface_new_popup: (constructor) * @display: the display to create the surface on * @parent: the parent surface to attach the surface to + * @autohide: whether to hide the surface on outside clicks * * Create a new popup surface. + * * The surface will be attached to @parent and can * be positioned relative to it using * gdk_surface_move_to_rect(). @@ -807,7 +825,8 @@ gdk_surface_new_temp (GdkDisplay *display, */ GdkSurface * gdk_surface_new_popup (GdkDisplay *display, - GdkSurface *parent) + GdkSurface *parent, + gboolean autohide) { GdkSurface *surface; @@ -817,6 +836,8 @@ gdk_surface_new_popup (GdkDisplay *display, surface = gdk_surface_new (display, GDK_SURFACE_POPUP, parent, 0, 0, 100, 100); + surface->autohide = autohide; + return surface; } @@ -1890,6 +1911,13 @@ gdk_surface_restack (GdkSurface *surface, GDK_SURFACE_GET_CLASS (surface)->restack_toplevel (surface, sibling, above); } +static void +grab_prepare_func (GdkSeat *seat, + GdkSurface *surface, + gpointer data) +{ + gdk_surface_show_internal (surface, TRUE); +} /** * gdk_surface_show: @@ -1908,7 +1936,19 @@ gdk_surface_restack (GdkSurface *surface, void gdk_surface_show (GdkSurface *surface) { - gdk_surface_show_internal (surface, TRUE); + if (surface->autohide) + { + gdk_seat_grab (gdk_display_get_default_seat (surface->display), + surface, + GDK_SEAT_CAPABILITY_ALL, + TRUE, + NULL, NULL, + grab_prepare_func, NULL); + } + else + { + gdk_surface_show_internal (surface, TRUE); + } } /** @@ -4080,10 +4120,54 @@ gdk_synthesize_surface_state (GdkSurface *surface, gdk_surface_set_state (surface, (surface->state | set_flags) & ~unset_flags); } +static gboolean +check_autohide (GdkEvent *event) +{ + GdkDisplay *display; + GdkDevice *device; + GdkSurface *grab_surface; + + switch ((guint) gdk_event_get_event_type (event)) + { + case GDK_BUTTON_PRESS: +#if 0 + // FIXME: we need to ignore the release that is paired + // with the press starting the grab - due to implicit + // grabs, it will be delivered to the same place as the + // press, and will cause the auto dismissal to be triggered. + case GDK_BUTTON_RELEASE: +#endif + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + case GDK_TOUCHPAD_SWIPE: + case GDK_TOUCHPAD_PINCH: + display = gdk_event_get_display (event); + device = gdk_event_get_device (event); + if (gdk_device_grab_info (display, device, &grab_surface, NULL)) + { + if (grab_surface != gdk_event_get_surface (event) && + grab_surface->autohide) + { + gdk_surface_hide (grab_surface); + return TRUE; + } + } + break; + default:; + } + + return FALSE; +} + gboolean gdk_surface_handle_event (GdkEvent *event) { gboolean handled = FALSE; + + if (check_autohide (event)) + return TRUE; + if (gdk_event_get_event_type (event) == GDK_CONFIGURE) { g_signal_emit (gdk_event_get_surface (event), signals[SIZE_CHANGED], 0, diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 938c59ba17..99f920c5f4 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -426,7 +426,8 @@ GdkSurface * gdk_surface_new_temp (GdkDisplay *display, const GdkRectangle *position); GDK_AVAILABLE_IN_ALL GdkSurface * gdk_surface_new_popup (GdkDisplay *display, - GdkSurface *parent); + GdkSurface *parent, + gboolean autohide); GDK_AVAILABLE_IN_ALL void gdk_surface_destroy (GdkSurface *surface); @@ -443,6 +444,7 @@ GDK_AVAILABLE_IN_ALL void gdk_surface_hide (GdkSurface *surface); GDK_AVAILABLE_IN_ALL void gdk_surface_show_unraised (GdkSurface *surface); + GDK_AVAILABLE_IN_ALL void gdk_surface_move (GdkSurface *surface, gint x, diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index 25319c6b38..c7933fe0f2 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -69,6 +69,7 @@ struct _GdkSurface guint viewable : 1; /* mapped and all parents mapped */ guint in_update : 1; guint frame_clock_events_paused : 1; + guint autohide : 1; guint update_and_descendants_freeze_count;