app: fix text tool drawing for good this time (hopefully)

Earlier I claimed that drawing would work now because we make sure
that buffer and layout are always in sync. This was nonsense. In fact,
we constantly ran into the sutiation where the buffer was modified,
and we were drawing with the previous layout. It's unclear why this
didn't cause drawing artifacts, but it did cause e.g. the cursor
temporarily jumping to the next position while editing in the middle
of text (especially visible at line ends).

Several underlying problems existed: first, we now modify the buffer
from outside the text tool (from GimpTextStyleEditor) where we can't
pause the tool; second, proxy changes are handled asymetrically
(property changes are queued and processed all together in an idle
function) so we can't pause/resume drawing across the entire operation
because it has many beginnings and only one end.

Therefore:

- add gimp_text_tool_block_drawing()/unblock_drawing(), where block()
  can be called as many times as needed, and a single unblock()
  enables drawing again. block() also clears the layout, because it
  served its purpose (it was just used to pause drawing, and we know
  the buffer will change, so kill it).
- connect to GtkTextBuffer::begin-user-action and call block() from
  the callback, so we undraw stuff and kill the cached layout before
  any buffer change happens.
- call unblock() at the end of gimp_text_tool_apply() because then
  the text and the buffer are in sync again, the tool is undrawn and
  we can safely create the layout again to draw our stuff.
- also call block()/unblock() from some other places, like when a
  new text layer is created.
- get rid of *all* calls to draw_tool_pause()/resume() around buffer
  modifications, they are not needed any longer.
- add calls to begin/end_user_action() where they were missing.
This commit is contained in:
Michael Natterer 2010-03-04 23:47:23 +01:00
parent e54a05f78f
commit 5284c9c836
3 changed files with 80 additions and 69 deletions

View File

@ -416,15 +416,11 @@ gimp_text_tool_editor_key_press (GimpTextTool *text_tool,
gint x_pos = -1;
gboolean retval = TRUE;
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
if (gtk_im_context_filter_keypress (text_tool->im_context, kevent))
{
text_tool->needs_im_reset = TRUE;
text_tool->x_pos = -1;
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
return TRUE;
}
@ -435,8 +431,6 @@ gimp_text_tool_editor_key_press (GimpTextTool *text_tool,
{
GIMP_LOG (TEXT_EDITING, "binding handled event");
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
return TRUE;
}
@ -473,8 +467,6 @@ gimp_text_tool_editor_key_press (GimpTextTool *text_tool,
text_tool->x_pos = x_pos;
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
return retval;
}
@ -833,11 +825,7 @@ static void
gimp_text_tool_insert_at_cursor (GimpTextTool *text_tool,
const gchar *str)
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gimp_text_buffer_insert (text_tool->buffer, str);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static gboolean
@ -896,11 +884,7 @@ gimp_text_tool_delete_from_cursor (GimpTextTool *text_tool,
case GTK_DELETE_CHARS:
if (gtk_text_buffer_get_has_selection (buffer))
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
return;
}
else
@ -962,11 +946,7 @@ gimp_text_tool_delete_from_cursor (GimpTextTool *text_tool,
if (! gtk_text_iter_equal (&cursor, &end))
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_delete_interactive (buffer, &cursor, &end, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
}
@ -977,8 +957,6 @@ gimp_text_tool_backspace (GimpTextTool *text_tool)
gimp_text_tool_reset_im_context (text_tool);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
if (gtk_text_buffer_get_has_selection (buffer))
{
gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
@ -992,8 +970,6 @@ gimp_text_tool_backspace (GimpTextTool *text_tool)
gtk_text_buffer_backspace (buffer, &cursor, TRUE, TRUE);
}
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static void
@ -1048,13 +1024,9 @@ gimp_text_tool_change_baseline (GimpTextTool *text_tool,
gtk_text_buffer_get_end_iter (buffer, &end);
}
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_iter_order (&start, &end);
gimp_text_buffer_change_baseline (text_tool->buffer, &start, &end,
count * PANGO_SCALE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static void
@ -1073,13 +1045,9 @@ gimp_text_tool_change_kerning (GimpTextTool *text_tool,
gtk_text_iter_forward_char (&end);
}
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_iter_order (&start, &end);
gimp_text_buffer_change_kerning (text_tool->buffer, &start, &end,
count * PANGO_SCALE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static void
@ -1167,7 +1135,7 @@ gimp_text_tool_enter_text (GimpTextTool *text_tool,
had_selection = gtk_text_buffer_get_has_selection (buffer);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_begin_user_action (buffer);
gimp_text_tool_delete_selection (text_tool);
@ -1184,7 +1152,7 @@ gimp_text_tool_enter_text (GimpTextTool *text_tool,
gimp_text_buffer_insert (text_tool->buffer, str);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_end_user_action (buffer);
}
static void

View File

@ -163,7 +163,12 @@ static gboolean gimp_text_tool_set_drawable (GimpTextTool *text_tool,
GimpDrawable *drawable,
gboolean confirm);
static void gimp_text_tool_buffer_edited (GimpTextBuffer *buffer,
static void gimp_text_tool_block_drawing (GimpTextTool *text_tool);
static void gimp_text_tool_unblock_drawing (GimpTextTool *text_tool);
static void gimp_text_tool_buffer_begin_edit (GimpTextBuffer *buffer,
GimpTextTool *text_tool);
static void gimp_text_tool_buffer_end_edit (GimpTextBuffer *buffer,
GimpTextTool *text_tool);
@ -246,8 +251,11 @@ gimp_text_tool_init (GimpTextTool *text_tool)
text_tool->buffer = gimp_text_buffer_new ();
g_signal_connect (text_tool->buffer, "begin-user-action",
G_CALLBACK (gimp_text_tool_buffer_begin_edit),
text_tool);
g_signal_connect (text_tool->buffer, "end-user-action",
G_CALLBACK (gimp_text_tool_buffer_edited),
G_CALLBACK (gimp_text_tool_buffer_end_edit),
text_tool);
text_tool->handle_rectangle_change_complete = TRUE;
@ -496,13 +504,19 @@ gimp_text_tool_button_release (GimpTool *tool,
* can we do...
*/
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_begin_edit,
text_tool);
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_end_edit,
text_tool);
gimp_text_tool_editor_button_release (text_tool);
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_end_edit,
text_tool);
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_begin_edit,
text_tool);
text_tool->selecting = FALSE;
@ -872,6 +886,8 @@ gimp_text_tool_rectangle_change_complete (GimpRectangleTool *rect_tool)
gimp_image_get_resolution (text_tool->image, &xres, &yres);
gimp_text_tool_block_drawing (text_tool);
g_object_set (text_tool->proxy,
"box-mode", GIMP_TEXT_BOX_FIXED,
"box-width", gimp_pixels_to_units (x2 - x1,
@ -924,7 +940,10 @@ gimp_text_tool_connect (GimpTextTool *text_tool,
GimpTextOptions *options = GIMP_TEXT_TOOL_GET_OPTIONS (tool);
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_begin_edit,
text_tool);
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_end_edit,
text_tool);
if (text_tool->text)
@ -977,7 +996,10 @@ gimp_text_tool_connect (GimpTextTool *text_tool,
}
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_end_edit,
text_tool);
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_begin_edit,
text_tool);
}
@ -1036,7 +1058,7 @@ gimp_text_tool_text_notify (GimpText *text,
{
g_return_if_fail (text == text_tool->text);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gimp_text_tool_block_drawing (text_tool);
if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE)
{
@ -1066,7 +1088,10 @@ gimp_text_tool_text_notify (GimpText *text,
strcmp (pspec->name, "markup") == 0)
{
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_begin_edit,
text_tool);
g_signal_handlers_block_by_func (text_tool->buffer,
gimp_text_tool_buffer_end_edit,
text_tool);
if (pspec->name[0] == 't')
@ -1075,27 +1100,24 @@ gimp_text_tool_text_notify (GimpText *text,
gimp_text_buffer_set_markup (text_tool->buffer, text->markup);
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_edited,
gimp_text_tool_buffer_end_edit,
text_tool);
g_signal_handlers_unblock_by_func (text_tool->buffer,
gimp_text_tool_buffer_begin_edit,
text_tool);
}
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static void
gimp_text_tool_text_changed (GimpText *text,
GimpTextTool *text_tool)
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
/* we need to redraw the rectangle in any case because whatever
* changes to the text can change its size
*/
gimp_text_tool_frame_item (text_tool);
gimp_text_tool_clear_layout (text_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
gimp_text_tool_unblock_drawing (text_tool);
}
static gboolean
@ -1168,8 +1190,6 @@ gimp_text_tool_apply (GimpTextTool *text_tool)
}
}
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
if (push_undo)
{
if (layer->modified)
@ -1242,9 +1262,7 @@ gimp_text_tool_apply (GimpTextTool *text_tool)
gimp_image_flush (image);
gimp_text_tool_clear_layout (text_tool);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
gimp_text_tool_unblock_drawing (text_tool);
return FALSE;
}
@ -1260,6 +1278,8 @@ gimp_text_tool_create_layer (GimpTextTool *text_tool,
gint x1, y1;
gint x2, y2;
gimp_text_tool_block_drawing (text_tool);
if (text)
{
text = gimp_config_duplicate (GIMP_CONFIG (text));
@ -1344,10 +1364,14 @@ gimp_text_tool_create_layer (GimpTextTool *text_tool,
text_tool->proxy->box_unit,
yres),
NULL);
gimp_text_tool_apply (text_tool); /* unblocks drawing */
}
else
{
gimp_text_tool_frame_item (text_tool);
gimp_text_tool_unblock_drawing (text_tool);
}
gimp_image_undo_group_end (image);
@ -1582,8 +1606,38 @@ gimp_text_tool_set_drawable (GimpTextTool *text_tool,
}
static void
gimp_text_tool_buffer_edited (GimpTextBuffer *buffer,
GimpTextTool *text_tool)
gimp_text_tool_block_drawing (GimpTextTool *text_tool)
{
if (! text_tool->drawing_blocked)
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gimp_text_tool_clear_layout (text_tool);
text_tool->drawing_blocked = TRUE;
}
}
static void
gimp_text_tool_unblock_drawing (GimpTextTool *text_tool)
{
g_return_if_fail (text_tool->drawing_blocked == TRUE);
text_tool->drawing_blocked = FALSE;
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
static void
gimp_text_tool_buffer_begin_edit (GimpTextBuffer *buffer,
GimpTextTool *text_tool)
{
gimp_text_tool_block_drawing (text_tool);
}
static void
gimp_text_tool_buffer_end_edit (GimpTextBuffer *buffer,
GimpTextTool *text_tool)
{
if (text_tool->text)
{
@ -1713,11 +1767,7 @@ gimp_text_tool_delete_selection (GimpTextTool *text_tool)
if (gtk_text_buffer_get_has_selection (buffer))
{
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_delete_selection (buffer, TRUE, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
}
@ -1734,12 +1784,8 @@ gimp_text_tool_cut_clipboard (GimpTextTool *text_tool)
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (shell),
GDK_SELECTION_CLIPBOARD);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_cut_clipboard (GTK_TEXT_BUFFER (text_tool->buffer),
clipboard, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
void
@ -1772,12 +1818,8 @@ gimp_text_tool_paste_clipboard (GimpTextTool *text_tool)
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (shell),
GDK_SELECTION_CLIPBOARD);
gimp_draw_tool_pause (GIMP_DRAW_TOOL (text_tool));
gtk_text_buffer_paste_clipboard (GTK_TEXT_BUFFER (text_tool->buffer),
clipboard, NULL, TRUE);
gimp_draw_tool_resume (GIMP_DRAW_TOOL (text_tool));
}
void

View File

@ -62,6 +62,7 @@ struct _GimpTextTool
gboolean text_box_fixed;
GimpTextLayout *layout;
gboolean drawing_blocked;
/* text editor state: */