From 2ae16ca6045d3c8c1efbf8e624335bd7d8f25cc6 Mon Sep 17 00:00:00 2001 From: Ell Date: Mon, 9 Apr 2018 12:09:51 -0400 Subject: [PATCH] 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. --- app/tools/gimppainttool-paint.c | 370 +++++++++++++++++++++++--------- app/tools/gimppainttool-paint.h | 17 +- app/tools/gimppainttool.c | 127 ++--------- app/tools/gimppainttool.h | 3 + 4 files changed, 299 insertions(+), 218 deletions(-) diff --git a/app/tools/gimppainttool-paint.c b/app/tools/gimppainttool-paint.c index 124296688e..edce86aa25 100644 --- a/app/tools/gimppainttool-paint.c +++ b/app/tools/gimppainttool-paint.c @@ -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, - const GimpCoords *coords, - guint32 time) +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; - GimpImage *image = gimp_display_get_image (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); } } diff --git a/app/tools/gimppainttool-paint.h b/app/tools/gimppainttool-paint.h index 05dfadece2..51d3080a7f 100644 --- a/app/tools/gimppainttool-paint.h +++ b/app/tools/gimppainttool-paint.h @@ -19,12 +19,19 @@ #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, - const GimpCoords *coords, - guint32 time); +void gimp_paint_tool_paint_motion (GimpPaintTool *tool, + const GimpCoords *coords, + guint32 time); #endif /* __GIMP_PAINT_TOOL_PAINT_H__ */ diff --git a/app/tools/gimppainttool.c b/app/tools/gimppainttool.c index e0531e6512..92bd9bc283 100644 --- a/app/tools/gimppainttool.c +++ b/app/tools/gimppainttool.c @@ -251,15 +251,12 @@ gimp_paint_tool_button_press (GimpTool *tool, GimpButtonPressType press_type, GimpDisplay *display) { - 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; + GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (tool); + GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool); + GimpDisplayShell *shell = gimp_display_get_shell (display); + GimpImage *image = gimp_display_get_image (display); + GimpDrawable *drawable = gimp_image_get_active_drawable (image); + 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,71 +303,26 @@ gimp_paint_tool_button_press (GimpTool *tool, tool->display = display; } - if (! gimp_paint_core_start (core, drawable, paint_options, &curr_coords, - &error)) + 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); g_clear_error (&error); 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 @@ -388,12 +333,10 @@ gimp_paint_tool_button_release (GimpTool *tool, GimpButtonReleaseType release_type, 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); + GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool); + GimpDisplayShell *shell = gimp_display_get_shell (display); + GimpImage *image = gimp_display_get_image (display); + 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)); @@ -434,36 +369,14 @@ gimp_paint_tool_motion (GimpTool *tool, GdkModifierType state, 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; + GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool); 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 diff --git a/app/tools/gimppainttool.h b/app/tools/gimppainttool.h index 1ca6b5e235..3dbb4aaec5 100644 --- a/app/tools/gimppainttool.h +++ b/app/tools/gimppainttool.h @@ -56,6 +56,9 @@ struct _GimpPaintTool const gchar *status_ctrl; /* additional message for the ctrl modifier */ GimpPaintCore *core; + + GimpDisplay *display; + GimpDrawable *drawable; }; struct _GimpPaintToolClass