From 50a7e59623683c77c6be54977eda30f8917bb8b5 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 12 Nov 2020 17:31:52 +0100 Subject: [PATCH 1/2] gtk/main: Toggle active flag with touch events This went missing at some point, add the missing toggling of active state with GDK_TOUCH_BEGIN/END/CANCEL events. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3348 --- gtk/gtkmain.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index cfc74ce43e..96ff1e69ad 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1413,7 +1413,9 @@ handle_pointing_event (GdkEvent *event) case GDK_TOUCH_END: case GDK_TOUCH_CANCEL: old_target = update_pointer_focus_state (toplevel, event, NULL); - if (type == GDK_LEAVE_NOTIFY) + if (type == GDK_TOUCH_END || type == GDK_TOUCH_CANCEL) + set_widget_active_state (old_target, TRUE); + else if (type == GDK_LEAVE_NOTIFY) gtk_synthesize_crossing_events (GTK_ROOT (toplevel), GTK_CROSSING_POINTER, old_target, NULL, event, gdk_crossing_event_get_mode (event), NULL); break; @@ -1465,7 +1467,10 @@ handle_pointing_event (GdkEvent *event) gtk_drop_end_event (drop); } else if (type == GDK_TOUCH_BEGIN) - gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target); + { + gtk_window_set_pointer_focus_grab (toplevel, device, sequence, target); + set_widget_active_state (target, FALSE); + } /* Let it take the effective pointer focus anyway, as it may change due * to implicit grabs. From 80de00a248d3addb8b78483d5d610dec03f62cdc Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Fri, 13 Nov 2020 00:23:52 +0100 Subject: [PATCH 2/2] gtk/main: Stack ::active calls We may have the situation of multiple touchpoints in the same widget, or combinations with other devices. Stack those ::active states are preserved on widgets on all but the last pointer/touch going away. --- gtk/gtkmain.c | 4 ++-- gtk/gtkwidget.c | 26 ++++++++++++++++++++++++++ gtk/gtkwidgetprivate.h | 5 +++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 96ff1e69ad..72941e8620 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -1362,9 +1362,9 @@ set_widget_active_state (GtkWidget *target, while (w) { if (release) - gtk_widget_unset_state_flags (w, GTK_STATE_FLAG_ACTIVE); + gtk_widget_set_active_state (w, FALSE); else - gtk_widget_set_state_flags (w, GTK_STATE_FLAG_ACTIVE, FALSE); + gtk_widget_set_active_state (w, TRUE); w = _gtk_widget_get_parent (w); } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 861d87a0cf..b71ae1a822 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -12663,3 +12663,29 @@ gtk_widget_class_get_accessible_role (GtkWidgetClass *widget_class) priv = widget_class->priv; return priv->accessible_role; } + +void +gtk_widget_set_active_state (GtkWidget *widget, + gboolean active) +{ + GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget); + + if (active) + { + priv->n_active++; + gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_ACTIVE, FALSE); + } + else + { + if (priv->n_active == 0) + { + g_warning ("Broken accounting of active state for widget %p(%s)", + widget, G_OBJECT_TYPE_NAME (widget)); + } + else + priv->n_active--; + + if (priv->n_active == 0) + gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_ACTIVE); + } +} diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 761a190e1d..138f0137d9 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -115,6 +115,8 @@ struct _GtkWidgetPrivate guint8 verifying_invariants_count; #endif + guint8 n_active; + int width_request; int height_request; @@ -324,6 +326,9 @@ void gtk_widget_get_surface_allocation (GtkWidget *widget, GtkWidget * gtk_widget_common_ancestor (GtkWidget *widget_a, GtkWidget *widget_b); +void gtk_widget_set_active_state (GtkWidget *widget, + gboolean active); + void gtk_widget_cancel_event_sequence (GtkWidget *widget, GtkGesture *gesture, GdkEventSequence *sequence,