app: reorganize gimppaintool-paint

Reorganize/clean up gimppainttool-paint.  In particular, move all
paint-core interaction during painting to gimppainttool-paint.c, so
that we can have more control over what's going on; specifically,
enter the drawable into paint mode *before* starting the paint
core, so that it picks up the correct buffer.  This fixes painting
with the paint thread using GimpApplicator, and enables us to use
the paint thread with GimpMybrushTool.
This commit is contained in:
Ell 2018-04-09 12:09:51 -04:00
parent f77edcdf19
commit 2ae16ca604
4 changed files with 299 additions and 218 deletions

View File

@ -32,6 +32,7 @@
#include "paint/gimppaintoptions.h"
#include "display/gimpdisplay.h"
#include "display/gimpdisplayshell-utils.h"
#include "gimppainttool.h"
#include "gimppainttool-paint.h"
@ -67,11 +68,10 @@ typedef struct
/* local function prototypes */
static gboolean gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool);
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 gboolean gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool);
/* static variables */
@ -92,90 +92,11 @@ static volatile gboolean paint_timeout_pending;
/* private functions */
static gboolean
gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
{
GimpTool *tool = GIMP_TOOL (paint_tool);
gboolean update;
paint_timeout_pending = TRUE;
g_mutex_lock (&paint_mutex);
update = gimp_drawable_flush_paint (tool->drawable);
paint_timeout_pending = FALSE;
g_cond_signal (&paint_cond);
g_mutex_unlock (&paint_mutex);
if (update)
{
GimpDisplay *display = tool->display;
GimpImage *image = gimp_display_get_image (display);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (paint_tool));
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (paint_tool));
}
return G_SOURCE_CONTINUE;
}
static gpointer
gimp_paint_tool_paint_thread (gpointer data)
{
g_mutex_lock (&paint_queue_mutex);
while (TRUE)
{
PaintItem *item;
while (! (item = g_queue_pop_head (&paint_queue)))
g_cond_wait (&paint_queue_cond, &paint_queue_mutex);
switch (item->type)
{
case PAINT_ITEM_TYPE_INTERPOLATE:
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 (
item->paint_tool->core,
GIMP_TOOL (item->paint_tool)->drawable,
GIMP_PAINT_TOOL_GET_OPTIONS (item->paint_tool),
&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_slice_free (PaintItem, item);
}
g_mutex_unlock (&paint_queue_mutex);
return NULL;
}
static gboolean
gimp_paint_tool_paint_use_thread (GimpPaintTool *paint_tool)
{
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->use_paint_thread)
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->use_paint_thread &&
! paint_tool->draw_line)
{
if (! paint_thread)
{
@ -197,32 +118,225 @@ gimp_paint_tool_paint_use_thread (GimpPaintTool *paint_tool)
return FALSE;
}
static gpointer
gimp_paint_tool_paint_thread (gpointer data)
{
g_mutex_lock (&paint_queue_mutex);
while (TRUE)
{
PaintItem *item;
while (! (item = g_queue_pop_head (&paint_queue)))
g_cond_wait (&paint_queue_cond, &paint_queue_mutex);
switch (item->type)
{
case PAINT_ITEM_TYPE_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_slice_free (PaintItem, item);
}
g_mutex_unlock (&paint_queue_mutex);
return NULL;
}
static gboolean
gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
{
GimpDrawable *drawable = paint_tool->drawable;
gboolean update;
paint_timeout_pending = TRUE;
g_mutex_lock (&paint_mutex);
update = gimp_drawable_flush_paint (drawable);
paint_timeout_pending = FALSE;
g_cond_signal (&paint_cond);
g_mutex_unlock (&paint_mutex);
if (update)
{
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
gimp_draw_tool_pause (draw_tool);
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (draw_tool);
}
return G_SOURCE_CONTINUE;
}
/* public functions */
void
gimp_paint_tool_paint_start (GimpPaintTool *paint_tool)
gboolean
gimp_paint_tool_paint_start (GimpPaintTool *paint_tool,
GimpDisplay *display,
const GimpCoords *coords,
guint32 time,
gboolean constrain,
GError **error)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
GimpTool *tool;
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDisplayShell *shell;
GimpImage *image;
GimpDrawable *drawable;
GimpCoords curr_coords;
gint off_x, off_y;
g_return_val_if_fail (GIMP_IS_PAINT_TOOL (paint_tool), FALSE);
g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
g_return_val_if_fail (coords != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_return_val_if_fail (paint_tool->display == NULL, FALSE);
tool = GIMP_TOOL (paint_tool);
paint_tool = GIMP_PAINT_TOOL (paint_tool);
paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
core = paint_tool->core;
shell = gimp_display_get_shell (display);
image = gimp_display_get_image (display);
drawable = gimp_image_get_active_drawable (image);
curr_coords = *coords;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
/* If we use a separate paint thread, enter paint mode before starting the
* paint core
*/
if (gimp_paint_tool_paint_use_thread (paint_tool))
gimp_drawable_start_paint (drawable);
/* Start the paint core */
if (! gimp_paint_core_start (core,
drawable, paint_options, &curr_coords,
error))
{
gimp_drawable_end_paint (drawable);
return FALSE;
}
paint_tool->display = display;
paint_tool->drawable = drawable;
if ((display != tool->display) || ! paint_tool->draw_line)
{
/* If this is a new display, resest the "last stroke's endpoint"
* because there is none
*/
if (display != tool->display)
core->start_coords = core->cur_coords;
core->last_coords = core->cur_coords;
core->distance = 0.0;
core->pixel_dist = 0.0;
}
else if (paint_tool->draw_line)
{
/* If shift is down and this is not the first paint
* stroke, then draw a line from the last coords to the pointer
*/
gimp_paint_core_round_line (
core, paint_options,
constrain,
gimp_display_shell_get_constrained_line_offset_angle (shell));
}
/* Let the specific painting function initialize itself */
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_INIT, time);
/* Paint to the image */
if (paint_tool->draw_line)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
&core->cur_coords, time);
}
else
{
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_MOTION, time);
}
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
/* Start the display update timeout */
if (gimp_paint_tool_paint_use_thread (paint_tool))
{
gimp_drawable_start_paint (GIMP_TOOL (paint_tool)->drawable);
paint_timeout_id = g_timeout_add_full (
G_PRIORITY_HIGH_IDLE,
DISPLAY_UPDATE_INTERVAL / 1000,
(GSourceFunc) gimp_paint_tool_paint_timeout,
paint_tool, NULL);
}
return TRUE;
}
void
gimp_paint_tool_paint_end (GimpPaintTool *paint_tool)
gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
guint32 time,
gboolean cancel)
{
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDrawable *drawable;
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (paint_tool->display != NULL);
paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
core = paint_tool->core;
drawable = paint_tool->drawable;
/* Process remaining paint items */
if (gimp_paint_tool_paint_use_thread (paint_tool))
{
PaintItem *item;
@ -260,28 +374,72 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool)
}
g_mutex_unlock (&paint_queue_mutex);
gimp_drawable_end_paint (GIMP_TOOL (paint_tool)->drawable);
}
/* Let the specific painting function finish up */
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_FINISH, time);
if (cancel)
gimp_paint_core_cancel (core, drawable);
else
gimp_paint_core_finish (core, drawable, TRUE);
/* Exit paint mode */
if (gimp_paint_tool_paint_use_thread (paint_tool))
gimp_drawable_end_paint (drawable);
paint_tool->display = NULL;
paint_tool->drawable = NULL;
}
void
gimp_paint_tool_paint_interpolate (GimpPaintTool *paint_tool,
gimp_paint_tool_paint_motion (GimpPaintTool *paint_tool,
const GimpCoords *coords,
guint32 time)
{
GimpPaintOptions *paint_options;
GimpPaintCore *core;
GimpDrawable *drawable;
GimpCoords curr_coords;
gint off_x, off_y;
g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
g_return_if_fail (coords != NULL);
g_return_if_fail (paint_tool->display != NULL);
paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
core = paint_tool->core;
drawable = paint_tool->drawable;
curr_coords = *coords;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
gimp_paint_core_smooth_coords (core, paint_options, &curr_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);
return;
}
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_INTERPOLATE;
item->paint_tool = paint_tool;
item->coords = *coords;
item->coords = curr_coords;
item->time = time;
g_mutex_lock (&paint_queue_mutex);
@ -293,20 +451,20 @@ gimp_paint_tool_paint_interpolate (GimpPaintTool *paint_tool,
}
else
{
GimpTool *tool = GIMP_TOOL (paint_tool);
GimpDisplay *display = tool->display;
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (paint_tool));
/* Paint directly */
gimp_paint_core_interpolate (paint_tool->core,
tool->drawable,
GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool),
coords, time);
gimp_draw_tool_pause (draw_tool);
gimp_paint_core_interpolate (core,
drawable, paint_options, &curr_coords, time);
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (paint_tool));
gimp_draw_tool_resume (draw_tool);
}
}

View File

@ -19,10 +19,17 @@
#define __GIMP_PAINT_TOOL_PAINT_H__
void gimp_paint_tool_paint_start (GimpPaintTool *tool);
void gimp_paint_tool_paint_end (GimpPaintTool *tool);
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);
void gimp_paint_tool_paint_interpolate (GimpPaintTool *tool,
void gimp_paint_tool_paint_motion (GimpPaintTool *tool,
const GimpCoords *coords,
guint32 time);

View File

@ -253,13 +253,10 @@ gimp_paint_tool_button_press (GimpTool *tool,
{
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool);
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
GimpPaintCore *core = paint_tool->core;
GimpDisplayShell *shell = gimp_display_get_shell (display);
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
GimpCoords curr_coords;
gint off_x, off_y;
gboolean constrain;
GError *error = NULL;
if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
@ -290,13 +287,6 @@ gimp_paint_tool_button_press (GimpTool *tool,
return;
}
curr_coords = *coords;
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
if (gimp_draw_tool_is_active (draw_tool))
gimp_draw_tool_stop (draw_tool);
@ -313,7 +303,10 @@ gimp_paint_tool_button_press (GimpTool *tool,
tool->display = display;
}
if (! gimp_paint_core_start (core, drawable, paint_options, &curr_coords,
constrain = (state & gimp_get_constrain_behavior_mask ()) != 0;
if (! gimp_paint_tool_paint_start (paint_tool,
display, coords, time, constrain,
&error))
{
gimp_tool_message_literal (tool, display, error->message);
@ -321,63 +314,15 @@ gimp_paint_tool_button_press (GimpTool *tool,
return;
}
if ((display != tool->display) || ! paint_tool->draw_line)
{
/* if this is a new display, resest the "last stroke's endpoint"
* because there is none
*/
if (display != tool->display)
core->start_coords = core->cur_coords;
core->last_coords = core->cur_coords;
core->distance = 0.0;
core->pixel_dist = 0.0;
}
else if (paint_tool->draw_line)
{
gboolean constrain = (state & gimp_get_constrain_behavior_mask ()) != 0;
/* If shift is down and this is not the first paint
* stroke, then draw a line from the last coords to the pointer
*/
gimp_paint_core_round_line (
core, paint_options,
constrain,
gimp_display_shell_get_constrained_line_offset_angle (shell));
}
tool->display = display;
tool->drawable = drawable;
/* pause the current selection */
gimp_display_shell_selection_pause (shell);
/* Let the specific painting function initialize itself */
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_INIT, time);
/* Paint to the image */
if (paint_tool->draw_line)
{
gimp_paint_core_interpolate (core, drawable, paint_options,
&core->cur_coords, time);
}
else
{
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_MOTION, time);
}
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
gimp_draw_tool_start (draw_tool, display);
gimp_tool_control_activate (tool->control);
if (! paint_tool->draw_line)
gimp_paint_tool_paint_start (paint_tool);
}
static void
@ -389,11 +334,9 @@ gimp_paint_tool_button_release (GimpTool *tool,
GimpDisplay *display)
{
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
GimpPaintCore *core = paint_tool->core;
GimpDisplayShell *shell = gimp_display_get_shell (display);
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
gboolean cancel;
if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
{
@ -403,25 +346,17 @@ gimp_paint_tool_button_release (GimpTool *tool,
return;
}
if (! paint_tool->draw_line)
gimp_paint_tool_paint_end (paint_tool);
cancel = (release_type == GIMP_BUTTON_RELEASE_CANCEL);
gimp_paint_tool_paint_end (paint_tool, time, cancel);
gimp_tool_control_halt (tool->control);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
/* Let the specific painting function finish up */
gimp_paint_core_paint (core, drawable, paint_options,
GIMP_PAINT_STATE_FINISH, time);
/* resume the current selection */
gimp_display_shell_selection_resume (shell);
if (release_type == GIMP_BUTTON_RELEASE_CANCEL)
gimp_paint_core_cancel (core, drawable);
else
gimp_paint_core_finish (core, drawable, TRUE);
gimp_image_flush (image);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
@ -435,35 +370,13 @@ gimp_paint_tool_motion (GimpTool *tool,
GimpDisplay *display)
{
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
GimpPaintCore *core = paint_tool->core;
GimpImage *image = gimp_display_get_image (display);
GimpDrawable *drawable = gimp_image_get_active_drawable (image);
GimpCoords curr_coords;
gint off_x, off_y;
GIMP_TOOL_CLASS (parent_class)->motion (tool, coords, time, state, display);
if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
return;
curr_coords = *coords;
gimp_paint_core_smooth_coords (core, paint_options, &curr_coords);
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
curr_coords.x -= off_x;
curr_coords.y -= off_y;
/* 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);
return;
}
gimp_paint_tool_paint_interpolate (paint_tool, &curr_coords, time);
gimp_paint_tool_paint_motion (paint_tool, coords, time);
}
static void

View File

@ -56,6 +56,9 @@ struct _GimpPaintTool
const gchar *status_ctrl; /* additional message for the ctrl modifier */
GimpPaintCore *core;
GimpDisplay *display;
GimpDrawable *drawable;
};
struct _GimpPaintToolClass