[gimp/gimp-2-10] app: avoid dropping motion events in spin-scales
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/gimp-2-10] app: avoid dropping motion events in spin-scales
- Date: Mon, 24 Aug 2020 09:34:03 +0000 (UTC)
commit 05341fada37d2a340af957475602ef01192a6060
Author: Ell <ell_se yahoo com>
Date: Mon Aug 24 12:30:57 2020 +0300
app: avoid dropping motion events in spin-scales
It looks like GDK motion hints are broken, at least on X, causing
us to drop motion events in GimpSpinScale, if the motion triggers
an operation that blocks the main thread for a significant amount
of time, such as projection invalidation.
Instead, disable motion hints for spin-scales, and use an idle to
perform ad-hoc motion compression.
app/widgets/gimpspinscale.c | 96 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 91 insertions(+), 5 deletions(-)
---
diff --git a/app/widgets/gimpspinscale.c b/app/widgets/gimpspinscale.c
index afd742df3e..7fa4039bed 100644
--- a/app/widgets/gimpspinscale.c
+++ b/app/widgets/gimpspinscale.c
@@ -87,6 +87,9 @@ struct _GimpSpinScalePrivate
gboolean pointer_warp;
gint pointer_warp_x;
gint pointer_warp_start_x;
+
+ gint change_value_idle_id;
+ gdouble change_value_idle_value;
};
#define GET_PRIVATE(obj) ((GimpSpinScalePrivate *) gimp_spin_scale_get_instance_private ((GimpSpinScale *)
(obj)))
@@ -103,6 +106,7 @@ static void gimp_spin_scale_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
+static void gimp_spin_scale_map (GtkWidget *widget);
static void gimp_spin_scale_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gimp_spin_scale_style_set (GtkWidget *widget,
@@ -155,6 +159,7 @@ gimp_spin_scale_class_init (GimpSpinScaleClass *klass)
object_class->set_property = gimp_spin_scale_set_property;
object_class->get_property = gimp_spin_scale_get_property;
+ widget_class->map = gimp_spin_scale_map;
widget_class->size_request = gimp_spin_scale_size_request;
widget_class->style_set = gimp_spin_scale_style_set;
widget_class->expose_event = gimp_spin_scale_expose;
@@ -212,6 +217,19 @@ gimp_spin_scale_dispose (GObject *object)
g_clear_object (&private->layout);
+ if (private->change_value_idle_id)
+ {
+ GtkAdjustment *adjustment;
+
+ adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (object));
+
+ g_source_remove (private->change_value_idle_id);
+
+ private->change_value_idle_id = 0;
+
+ gtk_adjustment_set_value (adjustment, private->change_value_idle_value);
+ }
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -267,6 +285,36 @@ gimp_spin_scale_get_property (GObject *object,
}
}
+static void
+gimp_spin_scale_map (GtkWidget *widget)
+{
+ GdkWindow *window;
+
+ GTK_WIDGET_CLASS (parent_class)->map (widget);
+
+ window = gtk_entry_get_text_window (GTK_ENTRY (widget));
+
+ if (window)
+ {
+ /* as per 2020, motion hints seem to be broken, at least on X: calling
+ * gdk_event_request_motions() doesn't seem to generate further motion
+ * events, causing motion events to be discarded, especially if the spin-
+ * scale is tied to some costly operation, such as projection
+ * invalidation, which blocks the main thread.
+ *
+ * to fix this, we simply avoid motion hints for the widget, and use an
+ * idle for setting the spin-scale value in response to motion events, as
+ * a form of ad-hoc motion compression.
+ *
+ * note that this isn't necessary with gtk3, which does its own motion
+ * compression.
+ */
+ gdk_window_set_events (window,
+ gdk_window_get_events (window) &
+ ~GDK_POINTER_MOTION_HINT_MASK);
+ }
+}
+
static void
gimp_spin_scale_size_request (GtkWidget *widget,
GtkRequisition *requisition)
@@ -715,10 +763,26 @@ gimp_spin_scale_get_limits (GimpSpinScale *scale,
}
}
+static gboolean
+gimp_spin_scale_change_value_idle (GimpSpinScale *scale)
+{
+ GimpSpinScalePrivate *private = GET_PRIVATE (scale);
+ GtkAdjustment *adjustment;
+
+ private->change_value_idle_id = 0;
+
+ adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (scale));
+
+ gtk_adjustment_set_value (adjustment, private->change_value_idle_value);
+
+ return G_SOURCE_REMOVE;
+}
+
static void
gimp_spin_scale_change_value (GtkWidget *widget,
gdouble x,
- guint state)
+ guint state,
+ gboolean now)
{
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget);
@@ -794,7 +858,26 @@ gimp_spin_scale_change_value (GtkWidget *widget,
if (private->constrain_drag)
value = rint (value);
- gtk_adjustment_set_value (adjustment, value);
+ if (now)
+ {
+ if (private->change_value_idle_id)
+ {
+ g_source_remove (private->change_value_idle_id);
+
+ private->change_value_idle_id = 0;
+ }
+
+ gtk_adjustment_set_value (adjustment, value);
+ }
+ else if (! private->change_value_idle_id)
+ {
+ private->change_value_idle_value = value;
+
+ private->change_value_idle_id = g_idle_add_full (
+ G_PRIORITY_DEFAULT + 1,
+ (GSourceFunc) gimp_spin_scale_change_value_idle,
+ widget, NULL);
+ }
}
static gboolean
@@ -821,7 +904,7 @@ gimp_spin_scale_button_press (GtkWidget *widget,
gtk_widget_grab_focus (widget);
- gimp_spin_scale_change_value (widget, event->x, event->state);
+ gimp_spin_scale_change_value (widget, event->x, event->state, TRUE);
return TRUE;
@@ -863,7 +946,7 @@ gimp_spin_scale_button_release (GtkWidget *widget,
* gimp_spin_scale_motion_notify().
*/
if (! private->pointer_warp)
- gimp_spin_scale_change_value (widget, event->x, event->state);
+ gimp_spin_scale_change_value (widget, event->x, event->state, TRUE);
if (private->relative_change)
{
@@ -953,7 +1036,10 @@ gimp_spin_scale_motion_notify (GtkWidget *widget,
private->start_x = private->pointer_warp_start_x;
}
- gimp_spin_scale_change_value (widget, event->x, event->state);
+ /* change the value in an idle, as a form of motion compression, since we
+ * don't use motion hints. see the comment in gimp_spin_scale_map().
+ */
+ gimp_spin_scale_change_value (widget, event->x, event->state, FALSE);
if (private->relative_change)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]