Commit 2ae16ca6 authored by Ell's avatar Ell

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.
parent f77edcdf
......@@ -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 */
......@@ -93,36 +93,29 @@ static volatile gboolean paint_timeout_pending;
static gboolean
gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
gimp_paint_tool_paint_use_thread (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)
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->use_paint_thread &&
! paint_tool->draw_line)
{
GimpDisplay *display = tool->display;
GimpImage *image = gimp_display_get_image (display);
if (! paint_thread)
{
static gint use_paint_thread = -1;
gimp_draw_tool_pause (GIMP_DRAW_TOOL (paint_tool));
if (use_paint_thread < 0)
use_paint_thread = g_getenv ("GIMP_NO_PAINT_THREAD") == NULL;
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
if (use_paint_thread)
{
paint_thread = g_thread_new ("paint",
gimp_paint_tool_paint_thread, NULL);
}
}
gimp_draw_tool_resume (GIMP_DRAW_TOOL (paint_tool));
return paint_thread != NULL;
}
return G_SOURCE_CONTINUE;
return FALSE;
}
static gpointer
......@@ -140,27 +133,31 @@ gimp_paint_tool_paint_thread (gpointer data)
switch (item->type)
{
case PAINT_ITEM_TYPE_INTERPOLATE:
g_mutex_unlock (&paint_queue_mutex);
g_mutex_lock (&paint_mutex);
{
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;
while (paint_timeout_pending)
g_cond_wait (&paint_cond, &paint_mutex);
g_mutex_unlock (&paint_queue_mutex);
g_mutex_lock (&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);
while (paint_timeout_pending)
g_cond_wait (&paint_cond, &paint_mutex);
g_mutex_unlock (&paint_mutex);
g_mutex_lock (&paint_queue_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);
{
*item->finished = TRUE;
g_cond_signal (&paint_queue_cond);
}
break;
}
......@@ -173,56 +170,173 @@ gimp_paint_tool_paint_thread (gpointer data)
}
static gboolean
gimp_paint_tool_paint_use_thread (GimpPaintTool *paint_tool)
gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
{
if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->use_paint_thread)
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)
{
if (! paint_thread)
{
static gint use_paint_thread = -1;
GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (paint_tool);
GimpDisplay *display = paint_tool->display;
GimpImage *image = gimp_display_get_image (display);
if (use_paint_thread < 0)
use_paint_thread = g_getenv ("GIMP_NO_PAINT_THREAD") == NULL;
gimp_draw_tool_pause (draw_tool);
if (use_paint_thread)
{
paint_thread = g_thread_new ("paint",
gimp_paint_tool_paint_thread, NULL);
}
}
gimp_projection_flush_now (gimp_image_get_projection (image));
gimp_display_flush_now (display);
return paint_thread != NULL;
gimp_draw_tool_resume (draw_tool);
}
return FALSE;
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_drawable_start_paint (GIMP_TOOL (paint_tool)->drawable);
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))
{
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)
{
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);
/* Paint directly */
gimp_draw_tool_pause (GIMP_DRAW_TOOL (paint_tool));
gimp_draw_tool_pause (draw_tool);
gimp_paint_core_interpolate (paint_tool->core,
tool->drawable,
GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool),
coords, time);
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);
}
}
......@@ -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__ */
......@@ -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
......
......@@ -56,6 +56,9 @@ struct _GimpPaintTool
const gchar *status_ctrl; /* additional message for the ctrl modifier */
GimpPaintCore *core;
GimpDisplay *display;
GimpDrawable *drawable;
};
struct _GimpPaintToolClass
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment