[gimp/gimp-2-8] libgimpwidgets: Avoid updating the rulers too often.



commit a8b596b078c637798b404c45f297138bb5c81ae6
Author: Michael Henning <drawoc darkrefraction com>
Date:   Sun Sep 6 00:05:32 2015 -0400

    libgimpwidgets: Avoid updating the rulers too often.
    
    Ever since 72617e42b, whenever the user generated a lot of mouse
    input, we would constantly queue redraws to the rulers. These redraws
    had a higher idle priority than updating the canvas, so we would
    rarely get around to canvas updates, which made certain tools
    (painting with dynamics, the blend tool) feel very unresponsive.
    
    This fixes it by only redrawing the rulers if the mouse has moved
    far from the last location, or if there are no idle handlers with
    a priority above LOW.
    
    (cherry picked from commit 3233a70bae756e8f62fb144cbce9d8f84ed25609)

 libgimpwidgets/gimpruler.c |  189 +++++++++++++++++++++++++++++++-------------
 1 files changed, 135 insertions(+), 54 deletions(-)
---
diff --git a/libgimpwidgets/gimpruler.c b/libgimpwidgets/gimpruler.c
index c412ebd..c9c1e85 100644
--- a/libgimpwidgets/gimpruler.c
+++ b/libgimpwidgets/gimpruler.c
@@ -39,8 +39,9 @@
  **/
 
 
-#define DEFAULT_RULER_FONT_SCALE  PANGO_SCALE_SMALL
-#define MINIMUM_INCR              5
+#define DEFAULT_RULER_FONT_SCALE    PANGO_SCALE_SMALL
+#define MINIMUM_INCR                5
+#define IMMEDIATE_REDRAW_THRESHOLD  20
 
 
 enum
@@ -70,6 +71,8 @@ typedef struct
   GdkWindow       *input_window;
   cairo_surface_t *backing_store;
   gboolean         backing_store_valid;
+  GdkRectangle     last_pos_rect;
+  guint            pos_redraw_idle_id;
   PangoLayout     *layout;
   gdouble          font_scale;
 
@@ -91,40 +94,43 @@ static const struct
 };
 
 
-static void          gimp_ruler_dispose       (GObject        *object);
-static void          gimp_ruler_set_property  (GObject        *object,
-                                               guint            prop_id,
-                                               const GValue   *value,
-                                               GParamSpec     *pspec);
-static void          gimp_ruler_get_property  (GObject        *object,
-                                               guint           prop_id,
-                                               GValue         *value,
-                                               GParamSpec     *pspec);
-
-static void          gimp_ruler_realize       (GtkWidget      *widget);
-static void          gimp_ruler_unrealize     (GtkWidget      *widget);
-static void          gimp_ruler_map           (GtkWidget      *widget);
-static void          gimp_ruler_unmap         (GtkWidget      *widget);
-static void          gimp_ruler_size_allocate (GtkWidget      *widget,
-                                               GtkAllocation  *allocation);
-static void          gimp_ruler_size_request  (GtkWidget      *widget,
-                                               GtkRequisition *requisition);
-static void          gimp_ruler_style_set     (GtkWidget      *widget,
-                                               GtkStyle       *prev_style);
-static gboolean      gimp_ruler_motion_notify (GtkWidget      *widget,
-                                               GdkEventMotion *event);
-static gboolean      gimp_ruler_expose        (GtkWidget      *widget,
-                                               GdkEventExpose *event);
-
-static void          gimp_ruler_draw_ticks    (GimpRuler      *ruler);
-static GdkRectangle  gimp_ruler_get_pos_rect  (GimpRuler      *ruler,
-                                               gdouble         position);
-static void          gimp_ruler_draw_pos      (GimpRuler      *ruler,
-                                               cairo_t        *cr);
-static void          gimp_ruler_make_pixmap   (GimpRuler      *ruler);
-
-static PangoLayout * gimp_ruler_get_layout    (GtkWidget      *widget,
-                                               const gchar    *text);
+static void          gimp_ruler_dispose              (GObject        *object);
+static void          gimp_ruler_finalize             (GObject        *object);
+static void          gimp_ruler_set_property         (GObject        *object,
+                                                      guint           prop_id,
+                                                      const GValue   *value,
+                                                      GParamSpec     *pspec);
+static void          gimp_ruler_get_property         (GObject        *object,
+                                                      guint           prop_id,
+                                                      GValue         *value,
+                                                      GParamSpec     *pspec);
+
+static void          gimp_ruler_realize              (GtkWidget      *widget);
+static void          gimp_ruler_unrealize            (GtkWidget      *widget);
+static void          gimp_ruler_map                  (GtkWidget      *widget);
+static void          gimp_ruler_unmap                (GtkWidget      *widget);
+static void          gimp_ruler_size_allocate        (GtkWidget      *widget,
+                                                      GtkAllocation  *allocation);
+static void          gimp_ruler_size_request         (GtkWidget      *widget,
+                                                      GtkRequisition *requisition);
+static void          gimp_ruler_style_set            (GtkWidget      *widget,
+                                                      GtkStyle       *prev_style);
+static gboolean      gimp_ruler_motion_notify        (GtkWidget      *widget,
+                                                      GdkEventMotion *event);
+static gboolean      gimp_ruler_expose               (GtkWidget      *widget,
+                                                      GdkEventExpose *event);
+
+static void          gimp_ruler_draw_ticks            (GimpRuler     *ruler);
+static GdkRectangle  gimp_ruler_get_pos_rect          (GimpRuler     *ruler,
+                                                       gdouble        position);
+static gboolean      gimp_ruler_idle_queue_pos_redraw (gpointer       data);
+static void          gimp_ruler_queue_pos_redraw      (GimpRuler     *ruler);
+static void          gimp_ruler_draw_pos              (GimpRuler     *ruler,
+                                                       cairo_t       *cr);
+static void          gimp_ruler_make_pixmap           (GimpRuler     *ruler);
+
+static PangoLayout * gimp_ruler_get_layout            (GtkWidget     *widget,
+                                                       const gchar   *text);
 
 
 G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET)
@@ -139,6 +145,7 @@ gimp_ruler_class_init (GimpRulerClass *klass)
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
   object_class->dispose             = gimp_ruler_dispose;
+  object_class->finalize            = gimp_ruler_finalize;
   object_class->set_property        = gimp_ruler_set_property;
   object_class->get_property        = gimp_ruler_get_property;
 
@@ -234,8 +241,16 @@ gimp_ruler_init (GimpRuler *ruler)
   priv->upper               = 0;
   priv->position            = 0;
   priv->max_size            = 0;
+
   priv->backing_store       = NULL;
   priv->backing_store_valid = FALSE;
+
+  priv->last_pos_rect.x      = 0;
+  priv->last_pos_rect.y      = 0;
+  priv->last_pos_rect.width  = 0;
+  priv->last_pos_rect.height = 0;
+  priv->pos_redraw_idle_id   = 0;
+
   priv->font_scale          = DEFAULT_RULER_FONT_SCALE;
 }
 
@@ -252,6 +267,21 @@ gimp_ruler_dispose (GObject *object)
 }
 
 static void
+gimp_ruler_finalize (GObject *object)
+{
+  GimpRuler        *ruler = GIMP_RULER (object);
+  GimpRulerPrivate *priv  = GIMP_RULER_GET_PRIVATE (ruler);
+
+  if (priv->pos_redraw_idle_id)
+    {
+      g_source_remove (priv->pos_redraw_idle_id);
+      priv->pos_redraw_idle_id = 0;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
 gimp_ruler_set_property (GObject      *object,
                          guint         prop_id,
                          const GValue *value,
@@ -616,28 +646,38 @@ gimp_ruler_set_position (GimpRuler *ruler,
 
   if (priv->position != position)
     {
-      gdouble old_pos = priv->position;
+      GdkRectangle rect;
+      gint xdiff, ydiff;
 
       priv->position = position;
       g_object_notify (G_OBJECT (ruler), "position");
 
-      {
-        GdkRectangle rect;
-
-        rect = gimp_ruler_get_pos_rect (ruler, old_pos);
-        gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
-                                    rect.x,
-                                    rect.y,
-                                    rect.width,
-                                    rect.height);
-
-        rect = gimp_ruler_get_pos_rect (ruler, position);
-        gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
-                                    rect.x,
-                                    rect.y,
-                                    rect.width,
-                                    rect.height);
-      }
+      rect = gimp_ruler_get_pos_rect (ruler, priv->position);
+
+      xdiff = rect.x - priv->last_pos_rect.x;
+      ydiff = rect.y - priv->last_pos_rect.y;
+
+      /*
+       * If the position has changed far enough, queue a redraw immediately.
+       * Otherwise, we only queue a redraw in a low priority idle handler, to
+       * allow for other things (like updating the canvas) to run.
+       *
+       * TODO: This might not be necessary any more in GTK3 with the frame
+       *       clock. Investigate this more after the port to GTK3.
+       */
+      if (priv->last_pos_rect.width  != 0 &&
+          priv->last_pos_rect.height != 0 &&
+          (ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
+           ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
+        {
+          gimp_ruler_queue_pos_redraw (ruler);
+        }
+      else if (! priv->pos_redraw_idle_id)
+        {
+          priv->pos_redraw_idle_id = g_idle_add_full (G_PRIORITY_LOW,
+                                                      gimp_ruler_idle_queue_pos_redraw,
+                                                      ruler, NULL);
+        }
     }
 }
 
@@ -1232,6 +1272,45 @@ gimp_ruler_get_pos_rect (GimpRuler *ruler, gdouble position)
   return rect;
 }
 
+static gboolean
+gimp_ruler_idle_queue_pos_redraw (gpointer data)
+{
+  GimpRuler        *ruler = data;
+  GimpRulerPrivate *priv  = GIMP_RULER_GET_PRIVATE (ruler);
+
+  gimp_ruler_queue_pos_redraw (ruler);
+
+  priv->pos_redraw_idle_id = 0;
+  return G_SOURCE_REMOVE;
+}
+
+static void
+gimp_ruler_queue_pos_redraw (GimpRuler *ruler)
+{
+  GimpRulerPrivate  *priv = GIMP_RULER_GET_PRIVATE (ruler);
+  const GdkRectangle rect = gimp_ruler_get_pos_rect (ruler, priv->position);
+
+  gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+                              rect.x,
+                              rect.y,
+                              rect.width,
+                              rect.height);
+
+  if (priv->last_pos_rect.width != 0 || priv->last_pos_rect.height != 0)
+    {
+      gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+                                  priv->last_pos_rect.x,
+                                  priv->last_pos_rect.y,
+                                  priv->last_pos_rect.width,
+                                  priv->last_pos_rect.height);
+
+      priv->last_pos_rect.x      = 0;
+      priv->last_pos_rect.y      = 0;
+      priv->last_pos_rect.width  = 0;
+      priv->last_pos_rect.height = 0;
+    }
+}
+
 static void
 gimp_ruler_draw_pos (GimpRuler *ruler, cairo_t *cr)
 {
@@ -1269,6 +1348,8 @@ gimp_ruler_draw_pos (GimpRuler *ruler, cairo_t *cr)
 
       cairo_fill (cr);
     }
+
+  priv->last_pos_rect = pos_rect;
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]