mirror of https://github.com/GNOME/gimp.git
Bug 795081 - Crash when using a brush combined with a dynamics
In GimpPaintTool, brush outline generation took place during gimp_paint_tool_draw() even while painting. This function is run concurrently with the paint thread. When using dynamics, this introduced a race conidition between updating the brush mask in the paint thread, and updating the brush boundary in the main thread. Move brush outline generation during painting to gimppainttool-paint.c, and perform it in the display-update timeout, while the main thread and the paint thread are synchronized.
This commit is contained in:
parent
e98506b000
commit
f5cb1fed85
|
@ -1669,3 +1669,11 @@ gimp_drawable_flush_paint (GimpDrawable *drawable)
|
|||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gimp_drawable_is_painting (GimpDrawable *drawable)
|
||||
{
|
||||
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
|
||||
|
||||
return drawable->private->paint_count > 0;
|
||||
}
|
||||
|
|
|
@ -231,6 +231,7 @@ const guchar * gimp_drawable_get_colormap (GimpDrawable *drawable)
|
|||
void gimp_drawable_start_paint (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_end_paint (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_flush_paint (GimpDrawable *drawable);
|
||||
gboolean gimp_drawable_is_painting (GimpDrawable *drawable);
|
||||
|
||||
|
||||
#endif /* __GIMP_DRAWABLE_H__ */
|
||||
|
|
|
@ -68,10 +68,12 @@ typedef struct
|
|||
|
||||
/* 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_update_outline (GimpPaintTool *paint_tool);
|
||||
|
||||
|
||||
/* static variables */
|
||||
|
@ -180,6 +182,9 @@ gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
|
|||
|
||||
update = gimp_drawable_flush_paint (drawable);
|
||||
|
||||
if (update)
|
||||
gimp_paint_tool_paint_update_outline (paint_tool);
|
||||
|
||||
paint_timeout_pending = FALSE;
|
||||
g_cond_signal (&paint_cond);
|
||||
|
||||
|
@ -202,6 +207,36 @@ gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
|
|||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_paint_tool_paint_update_outline (GimpPaintTool *paint_tool)
|
||||
{
|
||||
if (gimp_paint_tool_paint_use_thread (paint_tool))
|
||||
{
|
||||
gimp_paint_tool_set_draw_fallback (paint_tool, FALSE, 0.0);
|
||||
|
||||
if (paint_tool->draw_brush)
|
||||
{
|
||||
GimpPaintCore *core = paint_tool->core;
|
||||
GimpDisplay *display = paint_tool->display;
|
||||
GimpDrawable *drawable = paint_tool->drawable;
|
||||
gint off_x, off_y;
|
||||
gdouble x, y;
|
||||
|
||||
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
|
||||
|
||||
x = core->cur_coords.x + off_x;
|
||||
y = core->cur_coords.y + off_y;
|
||||
|
||||
if (paint_tool->outline)
|
||||
g_object_unref (paint_tool->outline);
|
||||
|
||||
paint_tool->outline =
|
||||
GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->get_outline (paint_tool,
|
||||
display, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -303,6 +338,9 @@ gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
|
|||
GIMP_PAINT_STATE_MOTION, time);
|
||||
}
|
||||
|
||||
/* Update the brush outline */
|
||||
gimp_paint_tool_paint_update_outline (paint_tool);
|
||||
|
||||
gimp_projection_flush_now (gimp_image_get_projection (image));
|
||||
gimp_display_flush_now (display);
|
||||
|
||||
|
@ -384,6 +422,9 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
|
|||
else
|
||||
gimp_paint_core_finish (core, drawable, TRUE);
|
||||
|
||||
/* Clear the brush outline */
|
||||
g_clear_object (&paint_tool->outline);
|
||||
|
||||
/* Exit paint mode */
|
||||
if (gimp_paint_tool_paint_use_thread (paint_tool))
|
||||
gimp_drawable_end_paint (drawable);
|
||||
|
|
|
@ -672,12 +672,9 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
|
|||
line_drawn = TRUE;
|
||||
}
|
||||
|
||||
gimp_paint_tool_set_draw_fallback (paint_tool, FALSE, 0.0);
|
||||
|
||||
if (paint_tool->draw_brush)
|
||||
outline = gimp_paint_tool_get_outline (paint_tool,
|
||||
draw_tool->display,
|
||||
cur_x, cur_y);
|
||||
outline = gimp_paint_tool_get_outline (paint_tool,
|
||||
draw_tool->display,
|
||||
cur_x, cur_y);
|
||||
|
||||
if (outline)
|
||||
{
|
||||
|
@ -770,9 +767,22 @@ gimp_paint_tool_get_outline (GimpPaintTool *paint_tool,
|
|||
gdouble x,
|
||||
gdouble y)
|
||||
{
|
||||
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->get_outline)
|
||||
return GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->get_outline (paint_tool,
|
||||
display, x, y);
|
||||
if (paint_tool->drawable && gimp_drawable_is_painting (paint_tool->drawable))
|
||||
{
|
||||
if (paint_tool->outline)
|
||||
return g_object_ref (paint_tool->outline);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_paint_tool_set_draw_fallback (paint_tool, FALSE, 0.0);
|
||||
|
||||
if (paint_tool->draw_brush &&
|
||||
GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->get_outline)
|
||||
{
|
||||
return GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->get_outline (
|
||||
paint_tool, display, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -39,26 +39,28 @@ typedef struct _GimpPaintToolClass GimpPaintToolClass;
|
|||
|
||||
struct _GimpPaintTool
|
||||
{
|
||||
GimpColorTool parent_instance;
|
||||
GimpColorTool parent_instance;
|
||||
|
||||
gboolean pick_colors; /* pick color if ctrl is pressed */
|
||||
gboolean draw_line;
|
||||
gboolean pick_colors; /* pick color if ctrl is pressed */
|
||||
gboolean draw_line;
|
||||
|
||||
gboolean show_cursor;
|
||||
gboolean draw_brush;
|
||||
gboolean draw_fallback;
|
||||
gint fallback_size;
|
||||
gboolean draw_circle;
|
||||
gint circle_size;
|
||||
gboolean show_cursor;
|
||||
gboolean draw_brush;
|
||||
gboolean draw_fallback;
|
||||
gint fallback_size;
|
||||
gboolean draw_circle;
|
||||
gint circle_size;
|
||||
|
||||
const gchar *status; /* status message */
|
||||
const gchar *status_line; /* status message when drawing a line */
|
||||
const gchar *status_ctrl; /* additional message for the ctrl modifier */
|
||||
const gchar *status; /* status message */
|
||||
const gchar *status_line; /* status message when drawing a line */
|
||||
const gchar *status_ctrl; /* additional message for the ctrl modifier */
|
||||
|
||||
GimpPaintCore *core;
|
||||
GimpPaintCore *core;
|
||||
|
||||
GimpDisplay *display;
|
||||
GimpDrawable *drawable;
|
||||
GimpDisplay *display;
|
||||
GimpDrawable *drawable;
|
||||
|
||||
GimpCanvasItem *outline;
|
||||
};
|
||||
|
||||
struct _GimpPaintToolClass
|
||||
|
|
Loading…
Reference in New Issue