[gimp] app: add an "update" signal to GimpCanvasItem



commit d9cd9f8a0725cb9514dc44af9de61a9a493e6e69
Author: Michael Natterer <mitch gimp org>
Date:   Fri Oct 1 17:13:00 2010 +0200

    app: add an "update" signal to GimpCanvasItem
    
    which gets emitted when the item wants to be redrawn:
    
    - Emit "update" it when any item property changes
    - Groups connect to their children and forward "update" for them
    - The shell connects to its group of canvas items and exposed
      the affected area
    - Remove gimp_display_shell_expose_item()
    - Move all the shell's item group code into gimpdisplayshell-items.c

 app/display/gimpcanvasgroup.c           |   41 ++++++++++++++++
 app/display/gimpcanvasitem.c            |   79 +++++++++++++++++++++++++++----
 app/display/gimpcanvasitem.h            |    5 ++
 app/display/gimpdisplayshell-expose.c   |   51 +++++++-------------
 app/display/gimpdisplayshell-expose.h   |    4 +-
 app/display/gimpdisplayshell-handlers.c |   25 +---------
 app/display/gimpdisplayshell-items.c    |   65 +++++++++++++++++++++++--
 app/display/gimpdisplayshell-items.h    |    3 +
 app/display/gimpdisplayshell.c          |   22 +-------
 9 files changed, 202 insertions(+), 93 deletions(-)
---
diff --git a/app/display/gimpcanvasgroup.c b/app/display/gimpcanvasgroup.c
index 641d6f4..ad123e6 100644
--- a/app/display/gimpcanvasgroup.c
+++ b/app/display/gimpcanvasgroup.c
@@ -72,6 +72,9 @@ static void        gimp_canvas_group_draw         (GimpCanvasItem   *item,
                                                    cairo_t          *cr);
 static GdkRegion * gimp_canvas_group_get_extents  (GimpCanvasItem   *item,
                                                    GimpDisplayShell *shell);
+static void        gimp_canvas_group_child_update (GimpCanvasItem   *item,
+                                                   GdkRegion        *region,
+                                                   GimpCanvasGroup  *group);
 
 
 G_DEFINE_TYPE (GimpCanvasGroup, gimp_canvas_group, GIMP_TYPE_CANVAS_ITEM)
@@ -222,6 +225,17 @@ gimp_canvas_group_get_extents (GimpCanvasItem   *item,
   return region;
 }
 
+static void
+gimp_canvas_group_child_update (GimpCanvasItem  *item,
+                                GdkRegion       *region,
+                                GimpCanvasGroup *group)
+{
+  g_signal_emit_by_name (group, "update", region);
+}
+
+
+/*  public functions  */
+
 GimpCanvasItem *
 gimp_canvas_group_new (GimpDisplayShell *shell)
 {
@@ -237,6 +251,7 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group,
                             GimpCanvasItem  *item)
 {
   GimpCanvasGroupPrivate *private;
+  GdkRegion              *region;
 
   g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
@@ -251,6 +266,18 @@ gimp_canvas_group_add_item (GimpCanvasGroup *group,
     gimp_canvas_item_suspend_filling (item);
 
   private->items = g_list_append (private->items, g_object_ref (item));
+
+  region = gimp_canvas_item_get_extents (item);
+
+  if (region)
+    {
+      g_signal_emit_by_name (group, "update", region);
+      gdk_region_destroy (region);
+    }
+
+  g_signal_connect (item, "update",
+                    G_CALLBACK (gimp_canvas_group_child_update),
+                    group);
 }
 
 void
@@ -258,6 +285,7 @@ gimp_canvas_group_remove_item (GimpCanvasGroup *group,
                                GimpCanvasItem  *item)
 {
   GimpCanvasGroupPrivate *private;
+  GdkRegion              *region;
 
   g_return_if_fail (GIMP_IS_CANVAS_GROUP (group));
   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
@@ -267,6 +295,19 @@ gimp_canvas_group_remove_item (GimpCanvasGroup *group,
   g_return_if_fail (g_list_find (private->items, item));
 
   private->items = g_list_remove (private->items, item);
+
+  region = gimp_canvas_item_get_extents (item);
+
+  if (region)
+    {
+      g_signal_emit_by_name (group, "update", region);
+      gdk_region_destroy (region);
+    }
+
+  g_signal_handlers_disconnect_by_func (item,
+                                        gimp_canvas_group_child_update,
+                                        group);
+
   g_object_unref (item);
 }
 
diff --git a/app/display/gimpcanvasitem.c b/app/display/gimpcanvasitem.c
index b58bcb9..e493955 100644
--- a/app/display/gimpcanvasitem.c
+++ b/app/display/gimpcanvasitem.c
@@ -23,9 +23,11 @@
 #include <gegl.h>
 #include <gtk/gtk.h>
 
+#include "libgimpmath/gimpmath.h"
+
 #include "display-types.h"
 
-#include "libgimpmath/gimpmath.h"
+#include "core/gimpmarshal.h"
 
 #include "gimpcanvasitem.h"
 #include "gimpdisplayshell.h"
@@ -40,6 +42,12 @@ enum
   PROP_HIGHLIGHT
 };
 
+enum
+{
+  UPDATE,
+  LAST_SIGNAL
+};
+
 
 typedef struct _GimpCanvasItemPrivate GimpCanvasItemPrivate;
 
@@ -69,6 +77,10 @@ static void        gimp_canvas_item_get_property     (GObject          *object,
                                                       guint             property_id,
                                                       GValue           *value,
                                                       GParamSpec       *pspec);
+static void
+        gimp_canvas_item_dispatch_properties_changed (GObject          *object,
+                                                      guint             n_pspecs,
+                                                      GParamSpec      **pspecs);
 
 static void        gimp_canvas_item_real_draw        (GimpCanvasItem   *item,
                                                       GimpDisplayShell *shell,
@@ -88,20 +100,34 @@ G_DEFINE_TYPE (GimpCanvasItem, gimp_canvas_item,
 
 #define parent_class gimp_canvas_item_parent_class
 
+static guint item_signals[LAST_SIGNAL] = { 0 };
+
 
 static void
 gimp_canvas_item_class_init (GimpCanvasItemClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-  object_class->constructed  = gimp_canvas_item_constructed;
-  object_class->set_property = gimp_canvas_item_set_property;
-  object_class->get_property = gimp_canvas_item_get_property;
-
-  klass->draw                = gimp_canvas_item_real_draw;
-  klass->get_extents         = gimp_canvas_item_real_get_extents;
-  klass->stroke              = gimp_canvas_item_real_stroke;
-  klass->fill                = gimp_canvas_item_real_fill;
+  object_class->constructed                 = gimp_canvas_item_constructed;
+  object_class->set_property                = gimp_canvas_item_set_property;
+  object_class->get_property                = gimp_canvas_item_get_property;
+  object_class->dispatch_properties_changed = gimp_canvas_item_dispatch_properties_changed;
+
+  klass->update                             = NULL;
+  klass->draw                               = gimp_canvas_item_real_draw;
+  klass->get_extents                        = gimp_canvas_item_real_get_extents;
+  klass->stroke                             = gimp_canvas_item_real_stroke;
+  klass->fill                               = gimp_canvas_item_real_fill;
+
+  item_signals[UPDATE] =
+    g_signal_new ("update",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  G_STRUCT_OFFSET (GimpCanvasItemClass, update),
+                  NULL, NULL,
+                  gimp_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_POINTER);
 
   g_object_class_install_property (object_class, PROP_SHELL,
                                    g_param_spec_object ("shell",
@@ -203,6 +229,41 @@ gimp_canvas_item_get_property (GObject    *object,
 }
 
 static void
+gimp_canvas_item_dispatch_properties_changed (GObject     *object,
+                                              guint        n_pspecs,
+                                              GParamSpec **pspecs)
+{
+  GimpCanvasItem *item = GIMP_CANVAS_ITEM (object);
+  GdkRegion      *before;
+  GdkRegion      *region;
+
+  before = gimp_canvas_item_get_extents (item);
+
+  G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object,
+                                                              n_pspecs,
+                                                              pspecs);
+
+  region = gimp_canvas_item_get_extents (item);
+
+  if (! region)
+    {
+      region = before;
+    }
+  else if (before)
+    {
+      gdk_region_union (region, before);
+      gdk_region_destroy (before);
+    }
+
+  if (region)
+    {
+      g_signal_emit (object, item_signals[UPDATE], 0,
+                     region);
+      gdk_region_destroy (region);
+    }
+}
+
+static void
 gimp_canvas_item_real_draw (GimpCanvasItem   *item,
                             GimpDisplayShell *shell,
                             cairo_t          *cr)
diff --git a/app/display/gimpcanvasitem.h b/app/display/gimpcanvasitem.h
index f878550..61867d4 100644
--- a/app/display/gimpcanvasitem.h
+++ b/app/display/gimpcanvasitem.h
@@ -44,6 +44,11 @@ struct _GimpCanvasItemClass
 {
   GimpObjectClass  parent_class;
 
+  /*  signals  */
+  void        (* update)      (GimpCanvasItem   *item,
+                               GdkRegion        *region);
+
+  /*  virtual functions  */
   void        (* draw)        (GimpCanvasItem   *item,
                                GimpDisplayShell *shell,
                                cairo_t          *cr);
diff --git a/app/display/gimpdisplayshell-expose.c b/app/display/gimpdisplayshell-expose.c
index eb959b0..b8361db 100644
--- a/app/display/gimpdisplayshell-expose.c
+++ b/app/display/gimpdisplayshell-expose.c
@@ -44,43 +44,15 @@ gimp_display_shell_expose_area (GimpDisplayShell *shell,
   gtk_widget_queue_draw_area (shell->canvas, x, y, w, h);
 }
 
-static void
-gimp_display_shell_expose_region (GimpDisplayShell *shell,
-                                  gdouble           x1,
-                                  gdouble           y1,
-                                  gdouble           x2,
-                                  gdouble           y2,
-                                  gint              border)
-{
-  const gint x = floor (x1);
-  const gint y = floor (y1);
-  const gint w = ceil (x2) - x;
-  const gint h = ceil (y2) - y;
-
-  gimp_display_shell_expose_area (shell,
-                                  x - border,
-                                  y - border,
-                                  w + 2 * border,
-                                  h + 2 * border);
-}
-
 void
-gimp_display_shell_expose_item (GimpDisplayShell *shell,
-                                GimpCanvasItem   *item)
+gimp_display_shell_expose_region (GimpDisplayShell *shell,
+                                  GdkRegion        *region)
 {
-  GdkRegion *region;
-
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
-  g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
+  g_return_if_fail (region != NULL);
 
-  region = gimp_canvas_item_get_extents (item);
-
-  if (region)
-    {
-      gdk_window_invalidate_region (gtk_widget_get_window (shell->canvas),
-                                    region, TRUE);
-      gdk_region_destroy (region);
-    }
+  gdk_window_invalidate_region (gtk_widget_get_window (shell->canvas),
+                                region, TRUE);
 }
 
 void
@@ -95,10 +67,21 @@ gimp_display_shell_expose_vectors (GimpDisplayShell *shell,
 
   if (gimp_vectors_bounds (vectors, &x1, &y1, &x2, &y2))
     {
+      gint x, y, w, h;
+
       gimp_display_shell_transform_xy_f (shell, x1, y1, &x1, &y1);
       gimp_display_shell_transform_xy_f (shell, x2, y2, &x2, &y2);
 
-      gimp_display_shell_expose_region (shell, x1, y1, x2, y2, 2);
+      x = floor (x1);
+      y = floor (y1);
+      w = ceil (x2) - x;
+      h = ceil (y2) - y;
+
+      gimp_display_shell_expose_area (shell,
+                                      x - 2,
+                                      y - 2,
+                                      w + 4,
+                                      h + 4);
     }
 }
 
diff --git a/app/display/gimpdisplayshell-expose.h b/app/display/gimpdisplayshell-expose.h
index 58ea2fb..96a59cb 100644
--- a/app/display/gimpdisplayshell-expose.h
+++ b/app/display/gimpdisplayshell-expose.h
@@ -24,8 +24,8 @@ void   gimp_display_shell_expose_area    (GimpDisplayShell   *shell,
                                           gint                y,
                                           gint                w,
                                           gint                h);
-void   gimp_display_shell_expose_item    (GimpDisplayShell   *shell,
-                                          GimpCanvasItem     *item);
+void   gimp_display_shell_expose_region  (GimpDisplayShell   *shell,
+                                          GdkRegion          *region);
 void   gimp_display_shell_expose_vectors (GimpDisplayShell   *shell,
                                           GimpVectors        *vectors);
 void   gimp_display_shell_expose_full    (GimpDisplayShell   *shell);
diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c
index 6b53a1f..6838caa 100644
--- a/app/display/gimpdisplayshell-handlers.c
+++ b/app/display/gimpdisplayshell-handlers.c
@@ -550,8 +550,6 @@ gimp_display_shell_guide_add_handler (GimpImage        *image,
 
   gimp_canvas_proxy_group_add_item (group, guide, item);
   g_object_unref (item);
-
-  gimp_display_shell_expose_item (shell, item);
 }
 
 static void
@@ -560,11 +558,6 @@ gimp_display_shell_guide_remove_handler (GimpImage        *image,
                                          GimpDisplayShell *shell)
 {
   GimpCanvasProxyGroup *group = GIMP_CANVAS_PROXY_GROUP (shell->guides);
-  GimpCanvasItem       *item;
-
-  item = gimp_canvas_proxy_group_get_item (group, guide);
-
-  gimp_display_shell_expose_item (shell, item);
 
   gimp_canvas_proxy_group_remove_item (group, guide);
 }
@@ -579,14 +572,10 @@ gimp_display_shell_guide_move_handler (GimpImage        *image,
 
   item = gimp_canvas_proxy_group_get_item (group, guide);
 
-  gimp_display_shell_expose_item (shell, item);
-
   g_object_set (item,
                 "orientation", gimp_guide_get_orientation (guide),
                 "position",    gimp_guide_get_position (guide),
                 NULL);
-
-  gimp_display_shell_expose_item (shell, item);
 }
 
 static void
@@ -619,8 +608,6 @@ gimp_display_shell_sample_point_add_handler (GimpImage        *image,
       g_object_set (item,
                     "index", i,
                     NULL);
-
-      gimp_display_shell_expose_item (shell, item);
     }
 }
 
@@ -630,14 +617,9 @@ gimp_display_shell_sample_point_remove_handler (GimpImage        *image,
                                                 GimpDisplayShell *shell)
 {
   GimpCanvasProxyGroup *group = GIMP_CANVAS_PROXY_GROUP (shell->sample_points);
-  GimpCanvasItem       *item;
   GList                *list;
   gint                  i;
 
-  item = gimp_canvas_proxy_group_get_item (group, sample_point);
-
-  gimp_display_shell_expose_item (shell, item);
-
   gimp_canvas_proxy_group_remove_item (group, sample_point);
 
   for (list = gimp_image_get_sample_points (image), i = 1;
@@ -645,14 +627,13 @@ gimp_display_shell_sample_point_remove_handler (GimpImage        *image,
        list = g_list_next (list), i++)
     {
       GimpSamplePoint *sample_point = list->data;
+      GimpCanvasItem  *item;
 
       item = gimp_canvas_proxy_group_get_item (group, sample_point);
 
       g_object_set (item,
                     "index", i,
                     NULL);
-
-      gimp_display_shell_expose_item (shell, item);
     }
 }
 
@@ -666,14 +647,10 @@ gimp_display_shell_sample_point_move_handler (GimpImage        *image,
 
   item = gimp_canvas_proxy_group_get_item (group, sample_point);
 
-  gimp_display_shell_expose_item (shell, item);
-
   g_object_set (item,
                 "x", sample_point->x,
                 "y", sample_point->y,
                 NULL);
-
-  gimp_display_shell_expose_item (shell, item);
 }
 
 static void
diff --git a/app/display/gimpdisplayshell-items.c b/app/display/gimpdisplayshell-items.c
index d98e1ae..adbc643 100644
--- a/app/display/gimpdisplayshell-items.c
+++ b/app/display/gimpdisplayshell-items.c
@@ -24,12 +24,60 @@
 
 #include "display-types.h"
 
-#include "gimpcanvasgroup.h"
+#include "gimpcanvasproxygroup.h"
 #include "gimpdisplayshell.h"
 #include "gimpdisplayshell-expose.h"
 #include "gimpdisplayshell-items.h"
 
 
+/*  local function prototypes  */
+
+static void   gimp_display_shell_item_update (GimpCanvasItem   *item,
+                                              GdkRegion        *region,
+                                              GimpDisplayShell *shell);
+
+
+/*  public functions  */
+
+void
+gimp_display_shell_items_init (GimpDisplayShell *shell)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  shell->canvas_item = gimp_canvas_group_new (shell);
+
+  shell->guides = gimp_canvas_proxy_group_new (shell);
+  gimp_display_shell_add_item (shell, shell->guides);
+  g_object_unref (shell->guides);
+
+  shell->sample_points = gimp_canvas_proxy_group_new (shell);
+  gimp_display_shell_add_item (shell, shell->sample_points);
+  g_object_unref (shell->sample_points);
+
+  g_signal_connect (shell->canvas_item, "update",
+                    G_CALLBACK (gimp_display_shell_item_update),
+                    shell);
+}
+
+void
+gimp_display_shell_items_free (GimpDisplayShell *shell)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  if (shell->canvas_item)
+    {
+      g_signal_handlers_disconnect_by_func (shell->canvas_item,
+                                            gimp_display_shell_item_update,
+                                            shell);
+
+      g_object_unref (shell->canvas_item);
+      shell->canvas_item = NULL;
+
+      shell->guides        = NULL;
+      shell->sample_points = NULL;
+    }
+}
+
 void
 gimp_display_shell_add_item (GimpDisplayShell *shell,
                              GimpCanvasItem   *item)
@@ -38,8 +86,6 @@ gimp_display_shell_add_item (GimpDisplayShell *shell,
   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
 
   gimp_canvas_group_add_item (GIMP_CANVAS_GROUP (shell->canvas_item), item);
-
-  gimp_display_shell_expose_item (shell, item);
 }
 
 void
@@ -49,7 +95,16 @@ gimp_display_shell_remove_item (GimpDisplayShell *shell,
   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
   g_return_if_fail (GIMP_IS_CANVAS_ITEM (item));
 
-  gimp_display_shell_expose_item (shell, item);
-
   gimp_canvas_group_remove_item (GIMP_CANVAS_GROUP (shell->canvas_item), item);
 }
+
+
+/*  private functions  */
+
+static void
+gimp_display_shell_item_update (GimpCanvasItem   *item,
+                                GdkRegion        *region,
+                                GimpDisplayShell *shell)
+{
+  gimp_display_shell_expose_region (shell, region);
+}
diff --git a/app/display/gimpdisplayshell-items.h b/app/display/gimpdisplayshell-items.h
index 59b040f..4b5b9b3 100644
--- a/app/display/gimpdisplayshell-items.h
+++ b/app/display/gimpdisplayshell-items.h
@@ -22,6 +22,9 @@
 #define __GIMP_DISPLAY_SHELL_ITEMS_H__
 
 
+void   gimp_display_shell_items_init  (GimpDisplayShell *shell);
+void   gimp_display_shell_items_free  (GimpDisplayShell *shell);
+
 void   gimp_display_shell_add_item    (GimpDisplayShell *shell,
                                        GimpCanvasItem   *item);
 void   gimp_display_shell_remove_item (GimpDisplayShell *shell,
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index 36dd15e..06bbcd5 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -53,7 +53,6 @@
 #include "tools/tool_manager.h"
 
 #include "gimpcanvas.h"
-#include "gimpcanvasproxygroup.h"
 #include "gimpdisplay.h"
 #include "gimpdisplayshell.h"
 #include "gimpdisplayshell-appearance.h"
@@ -64,6 +63,7 @@
 #include "gimpdisplayshell-expose.h"
 #include "gimpdisplayshell-filter.h"
 #include "gimpdisplayshell-handlers.h"
+#include "gimpdisplayshell-items.h"
 #include "gimpdisplayshell-progress.h"
 #include "gimpdisplayshell-render.h"
 #include "gimpdisplayshell-scale.h"
@@ -291,17 +291,7 @@ gimp_display_shell_init (GimpDisplayShell *shell)
                                                       GIMP_DISPLAY_RENDER_BUF_WIDTH,
                                                       GIMP_DISPLAY_RENDER_BUF_HEIGHT);
 
-  shell->canvas_item = gimp_canvas_group_new (shell);
-
-  shell->guides = gimp_canvas_proxy_group_new (shell);
-  gimp_canvas_group_add_item (GIMP_CANVAS_GROUP (shell->canvas_item),
-                              shell->guides);
-  g_object_unref (shell->guides);
-
-  shell->sample_points = gimp_canvas_proxy_group_new (shell);
-  gimp_canvas_group_add_item (GIMP_CANVAS_GROUP (shell->canvas_item),
-                              shell->sample_points);
-  g_object_unref (shell->sample_points);
+  gimp_display_shell_items_init (shell);
 
   shell->icon_size  = 32;
 
@@ -806,13 +796,7 @@ gimp_display_shell_dispose (GObject *object)
       shell->mask = NULL;
     }
 
-  if (shell->canvas_item)
-    {
-      g_object_unref (shell->canvas_item);
-      shell->canvas_item = NULL;
-      shell->guides = NULL;
-      shell->sample_points = NULL;
-    }
+  gimp_display_shell_items_free (shell);
 
   if (shell->event_history)
     {



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