From 047265333cff7e13db173db8d0bddc6279e9e318 Mon Sep 17 00:00:00 2001 From: Jehan Date: Mon, 19 Nov 2018 14:13:03 +0100 Subject: [PATCH] app: better handle drawable and image update for line art computation. The "update" signal on drawable or projection can actually be emitted many times for a single painting event. Just add new signals ("painted" on GimpDrawable and "rendered" on GimpProjection) which are emitted once for a single update (from user point of view), at the end, after actual rendering is done (i.e. after the various "update" signals). Also better support the sample merge vs current drawable paths for bucket fill. --- app/core/gimpdrawable.c | 30 +++++++++++++++++++ app/core/gimpdrawable.h | 1 + app/core/gimpprojection.c | 11 +++++++ app/core/gimpprojection.h | 13 ++++---- app/tools/gimpbucketfilltool.c | 54 +++++++++++++++++++++++----------- 5 files changed, 86 insertions(+), 23 deletions(-) diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 91b0cad1e7..7b783209d8 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -66,6 +66,7 @@ enum { UPDATE, + PAINTED, ALPHA_CHANGED, LAST_SIGNAL }; @@ -219,6 +220,16 @@ gimp_drawable_class_init (GimpDrawableClass *klass) GimpFilterClass *filter_class = GIMP_FILTER_CLASS (klass); GimpItemClass *item_class = GIMP_ITEM_CLASS (klass); + /** + * GimpDrawable::update: + * @drawable: the object which received the signal. + * @x: + * @y: + * @width: + * @height: + * + * This signal is emitted when a region of the drawable is updated. + **/ gimp_drawable_signals[UPDATE] = g_signal_new ("update", G_TYPE_FROM_CLASS (klass), @@ -232,6 +243,24 @@ gimp_drawable_class_init (GimpDrawableClass *klass) G_TYPE_INT, G_TYPE_INT); + /** + * GimpDrawable::painted: + * @drawable: the object which received the signal. + * + * This signal is emitted when the drawable has been painted. Unlike + * the "update" signal, it will be emitted once for a single paint + * event (whereas several "update" signals could be emitted + * sequentially for various regions of the drawable). + **/ + gimp_drawable_signals[PAINTED] = + g_signal_new ("painted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpDrawableClass, painted), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + gimp_drawable_signals[ALPHA_CHANGED] = g_signal_new ("alpha-changed", G_TYPE_FROM_CLASS (klass), @@ -998,6 +1027,7 @@ gimp_drawable_update (GimpDrawable *drawable, { g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0, x, y, width, height); + g_signal_emit (drawable, gimp_drawable_signals[PAINTED], 0); } else { diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index 5a59f33c5c..58cf9281c6 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -50,6 +50,7 @@ struct _GimpDrawableClass gint y, gint width, gint height); + void (* painted) (GimpDrawable *drawable); void (* alpha_changed) (GimpDrawable *drawable); /* virtual functions */ diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c index 8e97972955..158cb48231 100644 --- a/app/core/gimpprojection.c +++ b/app/core/gimpprojection.c @@ -81,6 +81,7 @@ static gdouble GIMP_PROJECTION_CHUNK_TIME = 0.0666; enum { UPDATE, + RENDERED, LAST_SIGNAL }; @@ -251,6 +252,15 @@ gimp_projection_class_init (GimpProjectionClass *klass) G_TYPE_INT, G_TYPE_INT); + projection_signals[RENDERED] = + g_signal_new ("rendered", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GimpProjectionClass, rendered), + NULL, NULL, + gimp_marshal_VOID__VOID, + G_TYPE_NONE, 0); + object_class->finalize = gimp_projection_finalize; object_class->set_property = gimp_projection_set_property; object_class->get_property = gimp_projection_get_property; @@ -834,6 +844,7 @@ gimp_projection_chunk_render_stop (GimpProjection *proj) g_source_remove (proj->priv->chunk_render.idle_id); proj->priv->chunk_render.idle_id = 0; + g_signal_emit (proj, projection_signals[RENDERED], 0); } static gboolean diff --git a/app/core/gimpprojection.h b/app/core/gimpprojection.h index 2446e93420..269e5b91d6 100644 --- a/app/core/gimpprojection.h +++ b/app/core/gimpprojection.h @@ -44,12 +44,13 @@ struct _GimpProjectionClass { GimpObjectClass parent_class; - void (* update) (GimpProjection *proj, - gboolean now, - gint x, - gint y, - gint width, - gint height); + void (* update) (GimpProjection *proj, + gboolean now, + gint x, + gint y, + gint width, + gint height); + void (* rendered) (GimpProjection *proj); }; diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c index 76bcdcd88e..f5e5ab5e7e 100644 --- a/app/tools/gimpbucketfilltool.c +++ b/app/tools/gimpbucketfilltool.c @@ -137,11 +137,9 @@ static void gimp_bucket_fill_tool_image_changed (GimpContext *c GimpBucketFillTool *tool); static void gimp_bucket_fill_tool_drawable_changed (GimpImage *image, GimpBucketFillTool *tool); -static void gimp_bucket_fill_tool_drawable_update (GimpDrawable *drawable, - gint x, - gint y, - gint width, - gint height, +static void gimp_bucket_fill_tool_projection_rendered (GimpProjection *proj, + GimpBucketFillTool *tool); +static void gimp_bucket_fill_tool_drawable_painted (GimpDrawable *drawable, GimpBucketFillTool *tool); @@ -239,6 +237,8 @@ gimp_bucket_fill_tool_finalize (GObject *object) if (image) { g_signal_handlers_disconnect_by_data (image, tool); + g_signal_handlers_disconnect_by_data (gimp_image_get_projection (image), + tool); g_object_unref (image); } if (drawable) @@ -403,10 +403,14 @@ gimp_bucket_fill_tool_preview (GimpBucketFillTool *tool, static void gimp_bucket_fill_tool_commit (GimpBucketFillTool *tool) { - tool->priv->fill_in_progress = FALSE; - if (tool->priv->filter) { + GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool); + + /* Make sure the drawable will signal being painted. */ + if (! options->sample_merged) + tool->priv->fill_in_progress = FALSE; + gimp_drawable_filter_commit (tool->priv->filter, GIMP_PROGRESS (tool), FALSE); gimp_image_flush (gimp_display_get_image (GIMP_TOOL (tool)->display)); @@ -846,7 +850,11 @@ gimp_bucket_fill_tool_image_changed (GimpContext *context, g_clear_object (&tool->priv->line_art); if (prev_image) - g_signal_handlers_disconnect_by_data (prev_image, tool); + { + g_signal_handlers_disconnect_by_data (prev_image, tool); + g_signal_handlers_disconnect_by_data (gimp_image_get_projection (prev_image), + tool); + } if (prev_drawable) { g_signal_handlers_disconnect_by_data (prev_drawable, tool); @@ -863,6 +871,9 @@ gimp_bucket_fill_tool_image_changed (GimpContext *context, g_signal_connect (image, "active-channel-changed", G_CALLBACK (gimp_bucket_fill_tool_drawable_changed), tool); + g_signal_connect (gimp_image_get_projection (image), "rendered", + G_CALLBACK (gimp_bucket_fill_tool_projection_rendered), + tool); gimp_bucket_fill_tool_drawable_changed (image, tool); } } @@ -884,8 +895,8 @@ gimp_bucket_fill_tool_drawable_changed (GimpImage *image, g_weak_ref_set (&tool->priv->cached_drawable, drawable ? drawable : NULL); if (drawable) - g_signal_connect (drawable, "update", - G_CALLBACK (gimp_bucket_fill_tool_drawable_update), + g_signal_connect (drawable, "painted", + G_CALLBACK (gimp_bucket_fill_tool_drawable_painted), tool); gimp_bucket_fill_compute_line_art (tool); @@ -895,12 +906,21 @@ gimp_bucket_fill_tool_drawable_changed (GimpImage *image, } static void -gimp_bucket_fill_tool_drawable_update (GimpDrawable *drawable, - gint x, - gint y, - gint width, - gint height, - GimpBucketFillTool *tool) +gimp_bucket_fill_tool_projection_rendered (GimpProjection *proj, + GimpBucketFillTool *tool) { - gimp_bucket_fill_compute_line_art (tool); + GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool); + + if (options->sample_merged) + gimp_bucket_fill_compute_line_art (tool); +} + +static void +gimp_bucket_fill_tool_drawable_painted (GimpDrawable *drawable, + GimpBucketFillTool *tool) +{ + GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool); + + if (! options->sample_merged) + gimp_bucket_fill_compute_line_art (tool); }