app: fix airbrush periodic stamp behavior

Commit ddfc7715cb changed the
airbrush periodic stamp behavior, so that instead of using the main
brush, it issued a full MOTION event, potentially using a different
brush when using a GIH brush.

Fix this, by renaming the "timeout" signal of GimpAirbrush to
"stamp", and by adding a new gimp_airbrush_stamp() function, which
should be used for painting the periodic airbrush dab in response,
instead of calling gimp_paint_core_paint() directly, and which
calls gimp_airbrush_paint() instead, as the old code did.

In order to call this function from the paint thread, we replace
the various gimp_paint_tool_paint_core_foo() functions, introduced
in the above commit, with a generic gimp_paint_tool_paint_push()
function, which takes a callback (and a data pointer) to run on the
paint thread, and queues it for execution (when not using the paint
thread, the function is called directly from the calling thread.)
This commit is contained in:
Ell 2018-04-18 13:35:28 -04:00
parent ce8c4cb2a0
commit 542a04735b
5 changed files with 200 additions and 218 deletions

View file

@ -38,7 +38,7 @@
enum
{
TIMEOUT,
STAMP,
LAST_SIGNAL
};
@ -88,11 +88,11 @@ gimp_airbrush_class_init (GimpAirbrushClass *klass)
paint_core_class->paint = gimp_airbrush_paint;
airbrush_signals[TIMEOUT] =
g_signal_new ("timeout",
airbrush_signals[STAMP] =
g_signal_new ("stamp",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpAirbrushClass, timeout),
G_STRUCT_OFFSET (GimpAirbrushClass, stamp),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@ -114,6 +114,8 @@ gimp_airbrush_finalize (GObject *object)
airbrush->timeout_id = 0;
}
g_clear_object (&airbrush->sym);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -158,6 +160,13 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
fade_point = gimp_paint_options_get_fade (paint_options, image,
paint_core->pixel_dist);
airbrush->drawable = drawable;
airbrush->paint_options = paint_options;
if (airbrush->sym)
g_object_unref (airbrush->sym);
airbrush->sym = g_object_ref (sym);
/* Base our timeout on the original stroke. */
coords = gimp_symmetry_get_origin (sym);
@ -180,6 +189,8 @@ gimp_airbrush_paint (GimpPaintCore *paint_core,
paint_options,
sym,
paint_state, time);
g_clear_object (&airbrush->sym);
break;
}
}
@ -221,7 +232,23 @@ gimp_airbrush_timeout (gpointer data)
airbrush->timeout_id = 0;
g_signal_emit (airbrush, airbrush_signals[TIMEOUT], 0);
g_signal_emit (airbrush, airbrush_signals[STAMP], 0);
return G_SOURCE_REMOVE;
}
/* public functions */
void
gimp_airbrush_stamp (GimpAirbrush *airbrush)
{
g_return_if_fail (GIMP_IS_AIRBRUSH (airbrush));
gimp_airbrush_paint (GIMP_PAINT_CORE (airbrush),
airbrush->drawable,
airbrush->paint_options,
airbrush->sym,
GIMP_PAINT_STATE_MOTION, 0);
}

View file

@ -34,9 +34,13 @@ typedef struct _GimpAirbrushClass GimpAirbrushClass;
struct _GimpAirbrush
{
GimpPaintbrush parent_instance;
GimpPaintbrush parent_instance;
guint timeout_id;
guint timeout_id;
GimpSymmetry *sym;
GimpDrawable *drawable;
GimpPaintOptions *paint_options;
};
struct _GimpAirbrushClass
@ -44,7 +48,7 @@ struct _GimpAirbrushClass
GimpPaintbrushClass parent_class;
/* signals */
void (* timeout) (GimpAirbrush *airbrush);
void (* stamp) (GimpAirbrush *airbrush);
};
@ -53,5 +57,7 @@ void gimp_airbrush_register (Gimp *gimp,
GType gimp_airbrush_get_type (void) G_GNUC_CONST;
void gimp_airbrush_stamp (GimpAirbrush *airbrush);
#endif /* __GIMP_AIRBRUSH_H__ */

View file

@ -24,6 +24,7 @@
#include "tools-types.h"
#include "paint/gimpairbrush.h"
#include "paint/gimpairbrushoptions.h"
#include "widgets/gimphelp-ids.h"
@ -37,12 +38,15 @@
#include "gimp-intl.h"
static void gimp_airbrush_tool_constructed (GObject *object);
static void gimp_airbrush_tool_constructed (GObject *object);
static void gimp_airbrush_tool_airbrush_timeout (GimpAirbrush *airbrush,
GimpAirbrushTool *airbrush_tool);
static void gimp_airbrush_tool_airbrush_stamp (GimpAirbrush *airbrush,
GimpAirbrushTool *airbrush_tool);
static GtkWidget * gimp_airbrush_options_gui (GimpToolOptions *tool_options);
static void gimp_airbrush_tool_stamp (GimpAirbrushTool *airbrush_tool,
gpointer data);
static GtkWidget * gimp_airbrush_options_gui (GimpToolOptions *tool_options);
G_DEFINE_TYPE (GimpAirbrushTool, gimp_airbrush_tool, GIMP_TYPE_PAINTBRUSH_TOOL)
@ -91,17 +95,30 @@ gimp_airbrush_tool_constructed (GObject *object)
G_OBJECT_CLASS (parent_class)->constructed (object);
g_signal_connect_object (paint_tool->core, "timeout",
G_CALLBACK (gimp_airbrush_tool_airbrush_timeout),
g_signal_connect_object (paint_tool->core, "stamp",
G_CALLBACK (gimp_airbrush_tool_airbrush_stamp),
object, 0);
}
static void
gimp_airbrush_tool_airbrush_timeout (GimpAirbrush *airbrush,
GimpAirbrushTool *airbrush_tool)
gimp_airbrush_tool_airbrush_stamp (GimpAirbrush *airbrush,
GimpAirbrushTool *airbrush_tool)
{
gimp_paint_tool_paint_core_paint (GIMP_PAINT_TOOL (airbrush_tool),
GIMP_PAINT_STATE_MOTION, 0);
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (airbrush_tool);
gimp_paint_tool_paint_push (
paint_tool,
(GimpPaintToolPaintFunc) gimp_airbrush_tool_stamp,
NULL);
}
static void
gimp_airbrush_tool_stamp (GimpAirbrushTool *airbrush_tool,
gpointer data)
{
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (airbrush_tool);
gimp_airbrush_stamp (GIMP_AIRBRUSH (paint_tool->core));
}

View file

@ -41,44 +41,36 @@
#define DISPLAY_UPDATE_INTERVAL 10000 /* microseconds */
typedef enum
{
PAINT_ITEM_TYPE_CORE_PAINT,
PAINT_ITEM_TYPE_CORE_INTERPOLATE,
PAINT_ITEM_TYPE_FINISH
} PaintItemType;
#define PAINT_FINISH NULL
typedef struct
{
PaintItemType type;
GimpPaintTool *paint_tool;
GimpPaintToolPaintFunc func;
union
{
struct
{
GimpPaintTool *paint_tool;
union
{
GimpPaintState state;
GimpCoords coords;
};
guint32 time;
gpointer data;
gboolean *finished;
};
gboolean *finished;
};
} PaintItem;
typedef struct
{
GimpCoords coords;
guint32 time;
} InterpolateData;
/* local function prototypes */
static gboolean gimp_paint_tool_paint_use_thread (GimpPaintTool *paint_tool);
static gpointer gimp_paint_tool_paint_thread (gpointer data);
static gboolean gimp_paint_tool_paint_use_thread (GimpPaintTool *paint_tool);
static gpointer gimp_paint_tool_paint_thread (gpointer data);
static gboolean gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool);
static gboolean gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool);
static void gimp_paint_tool_paint_interpolate (GimpPaintTool *paint_tool,
InterpolateData *data);
/* static variables */
@ -136,56 +128,23 @@ gimp_paint_tool_paint_thread (gpointer data)
while (! (item = g_queue_pop_head (&paint_queue)))
g_cond_wait (&paint_queue_cond, &paint_queue_mutex);
switch (item->type)
if (item->func == PAINT_FINISH)
{
case PAINT_ITEM_TYPE_CORE_PAINT:
{
GimpPaintTool *paint_tool = item->paint_tool;
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDrawable *drawable = paint_tool->drawable;
*item->finished = TRUE;
g_cond_signal (&paint_queue_cond);
}
else
{
g_mutex_unlock (&paint_queue_mutex);
g_mutex_lock (&paint_mutex);
g_mutex_unlock (&paint_queue_mutex);
g_mutex_lock (&paint_mutex);
while (paint_timeout_pending)
g_cond_wait (&paint_cond, &paint_mutex);
while (paint_timeout_pending)
g_cond_wait (&paint_cond, &paint_mutex);
item->func (item->paint_tool, item->data);
gimp_paint_core_paint (core, drawable, paint_options,
item->state, item->time);
g_mutex_unlock (&paint_mutex);
g_mutex_lock (&paint_queue_mutex);
}
break;
case PAINT_ITEM_TYPE_CORE_INTERPOLATE:
{
GimpPaintTool *paint_tool = item->paint_tool;
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDrawable *drawable = paint_tool->drawable;
g_mutex_unlock (&paint_queue_mutex);
g_mutex_lock (&paint_mutex);
while (paint_timeout_pending)
g_cond_wait (&paint_cond, &paint_mutex);
gimp_paint_core_interpolate (core, drawable, paint_options,
&item->coords, item->time);
g_mutex_unlock (&paint_mutex);
g_mutex_lock (&paint_queue_mutex);
}
break;
case PAINT_ITEM_TYPE_FINISH:
{
*item->finished = TRUE;
g_cond_signal (&paint_queue_cond);
}
break;
g_mutex_unlock (&paint_mutex);
g_mutex_lock (&paint_queue_mutex);
}
g_slice_free (PaintItem, item);
@ -233,6 +192,20 @@ gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
return G_SOURCE_CONTINUE;
}
static void
gimp_paint_tool_paint_interpolate (GimpPaintTool *paint_tool,
InterpolateData *data)
{
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDrawable *drawable = paint_tool->drawable;
gimp_paint_core_interpolate (core, drawable, paint_options,
&data->coords, data->time);
g_slice_free (InterpolateData, data);
}
/* public functions */
@ -380,13 +353,16 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
gboolean finished = FALSE;
guint64 end_time;
g_return_if_fail (gimp_paint_tool_paint_is_active (paint_tool));
g_source_remove (paint_timeout_id);
paint_timeout_id = 0;
item = g_slice_new (PaintItem);
item->type = PAINT_ITEM_TYPE_FINISH;
item->finished = &finished;
item->paint_tool = paint_tool;
item->func = PAINT_FINISH;
item->finished = &finished;
g_mutex_lock (&paint_queue_mutex);
@ -446,6 +422,53 @@ gimp_paint_tool_paint_is_active (GimpPaintTool *paint_tool)
gimp_drawable_is_painting (paint_tool->drawable);
}
void
gimp_paint_tool_paint_push (GimpPaintTool *paint_tool,
GimpPaintToolPaintFunc func,
gpointer data)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (func != NULL);
if (gimp_paint_tool_paint_use_thread (paint_tool))
{
PaintItem *item;
g_return_if_fail (gimp_paint_tool_paint_is_active (paint_tool));
/* Push an item to the queue, to be processed by the paint thread */
item = g_slice_new (PaintItem);
item->paint_tool = paint_tool;
item->func = func;
item->data = data;
g_mutex_lock (&paint_queue_mutex);
g_queue_push_tail (&paint_queue, item);
g_cond_signal (&paint_queue_cond);
g_mutex_unlock (&paint_queue_mutex);
}
else
{
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
/* Paint directly */
gimp_draw_tool_pause (draw_tool);
func (paint_tool, data);
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (draw_tool);
}
}
void
gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
@ -455,7 +478,7 @@ gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDrawable *drawable;
GimpCoords curr_coords;
InterpolateData *data;
gint off_x, off_y;
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
@ -466,123 +489,30 @@ gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
core = paint_tool->core;
drawable = paint_tool->drawable;
curr_coords = *coords;
data = g_slice_new (InterpolateData);
data->coords = *coords;
data->time = time;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
data->coords.x -= off_x;
data->coords.y -= off_y;
gimp_paint_core_smooth_coords (core, paint_options, &curr_coords);
gimp_paint_core_smooth_coords (core, paint_options, &data->coords);
/* Don't paint while the Shift key is pressed for line drawing */
if (paint_tool->draw_line)
{
gimp_paint_core_set_current_coords (core, &curr_coords);
gimp_paint_core_set_current_coords (core, &data->coords);
g_slice_free (InterpolateData, data);
return;
}
gimp_paint_tool_paint_core_interpolate (paint_tool, &curr_coords, time);
}
void
gimp_paint_tool_paint_core_paint (GimpPaintTool *paint_tool,
GimpPaintState state,
guint32 time)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
if (gimp_paint_tool_paint_use_thread (paint_tool))
{
PaintItem *item;
/* Push an item to the queue, to be processed by the paint thread */
item = g_slice_new (PaintItem);
item->type = PAINT_ITEM_TYPE_CORE_PAINT;
item->paint_tool = paint_tool;
item->state = state;
item->time = time;
g_mutex_lock (&paint_queue_mutex);
g_queue_push_tail (&paint_queue, item);
g_cond_signal (&paint_queue_cond);
g_mutex_unlock (&paint_queue_mutex);
}
else
{
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = paint_tool->drawable;
/* Paint directly */
gimp_draw_tool_pause (draw_tool);
gimp_paint_core_paint (core,
drawable, paint_options, state, time);
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (draw_tool);
}
}
void
gimp_paint_tool_paint_core_interpolate (GimpPaintTool *paint_tool,
const GimpCoords *coords,
guint32 time)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (coords != NULL);
if (gimp_paint_tool_paint_use_thread (paint_tool))
{
PaintItem *item;
/* Push an item to the queue, to be processed by the paint thread */
item = g_slice_new (PaintItem);
item->type = PAINT_ITEM_TYPE_CORE_INTERPOLATE;
item->paint_tool = paint_tool;
item->coords = *coords;
item->time = time;
g_mutex_lock (&paint_queue_mutex);
g_queue_push_tail (&paint_queue, item);
g_cond_signal (&paint_queue_cond);
g_mutex_unlock (&paint_queue_mutex);
}
else
{
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
GimpPaintCore *core = paint_tool->core;
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = paint_tool->drawable;
/* Paint directly */
gimp_draw_tool_pause (draw_tool);
gimp_paint_core_interpolate (core,
drawable, paint_options, coords, time);
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (draw_tool);
}
gimp_paint_tool_paint_push (
paint_tool,
(GimpPaintToolPaintFunc) gimp_paint_tool_paint_interpolate,
data);
}

View file

@ -19,28 +19,30 @@
#define __GIMP_PAINT_TOOL_PAINT_H__
gboolean gimp_paint_tool_paint_start (GimpPaintTool *tool,
GimpDisplay *display,
const GimpCoords *coords,
guint32 time,
gboolean constrain,
GError **error);
void gimp_paint_tool_paint_end (GimpPaintTool *tool,
guint32 time,
gboolean cancel);
typedef void (* GimpPaintToolPaintFunc) (GimpPaintTool *tool,
gpointer data);
gboolean gimp_paint_tool_paint_is_active (GimpPaintTool *tool);
void gimp_paint_tool_paint_motion (GimpPaintTool *tool,
const GimpCoords *coords,
guint32 time);
void gimp_paint_tool_paint_core_paint (GimpPaintTool *tool,
GimpPaintState state,
guint32 time);
void gimp_paint_tool_paint_core_interpolate (GimpPaintTool *tool,
const GimpCoords *coords,
guint32 time);
gboolean gimp_paint_tool_paint_start (GimpPaintTool *tool,
GimpDisplay *display,
const GimpCoords *coords,
guint32 time,
gboolean constrain,
GError **error);
void gimp_paint_tool_paint_end (GimpPaintTool *tool,
guint32 time,
gboolean cancel);
gboolean gimp_paint_tool_paint_is_active (GimpPaintTool *tool);
void gimp_paint_tool_paint_push (GimpPaintTool *tool,
GimpPaintToolPaintFunc func,
gpointer data);
void gimp_paint_tool_paint_motion (GimpPaintTool *tool,
const GimpCoords *coords,
guint32 time);
#endif /* __GIMP_PAINT_TOOL_PAINT_H__ */