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
This commit is contained in:
Michael Natterer 2010-10-01 17:13:00 +02:00
parent d3f19baf0d
commit d9cd9f8a07
9 changed files with 201 additions and 92 deletions

View file

@ -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);
}

View file

@ -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;
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->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;
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",
@ -202,6 +228,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,

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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,

View file

@ -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)
{