Blob Blame History Raw
--- gtkhtml-3.3.2/src/gtkhtml-private.h.imcommit	2004-05-14 07:24:15.000000000 -0400
+++ gtkhtml-3.3.2/src/gtkhtml-private.h	2004-09-21 17:40:45.896197864 -0400
@@ -57,6 +57,7 @@
 	gint im_pre_len;
 	gint im_pre_pos;
 	GtkHTMLFontStyle im_orig_style;
+	gboolean im_hide_cursor;
 	gboolean im_block_reset;
 
 	HTMLObject *dnd_object;
--- gtkhtml-3.3.2/src/gtkhtml.c.imcommit	2004-09-16 18:17:19.000000000 -0400
+++ gtkhtml-3.3.2/src/gtkhtml.c	2004-09-21 17:40:46.036176584 -0400
@@ -1009,7 +1009,7 @@
 
 	html_engine_unrealize (html->engine);
 
-	gtk_im_context_set_client_window (html->priv->im_context, widget->window);
+	gtk_im_context_set_client_window (html->priv->im_context, NULL);
 
 	html_image_factory_stop_animations (html->engine->image_factory);
 
@@ -2993,130 +2993,151 @@
 	}
 }
 
+/* Removes the current preedit string if any; note that it doesn't reset
+ * im_pre_pos/im_pre_len, so it must be followed by a call to update_preedit
+ */
 static void
-gtk_html_im_commit_cb (GtkIMContext *context, const gchar *str, GtkHTML *html)
+remove_preedit (GtkHTML *html)
 {
-	gboolean state = html->priv->im_block_reset;
-	gint pos;
-
-        if (html->priv->im_pre_len > 0) {
-                D_IM (printf ("IM delete last preedit %d + %d\n", html->priv->im_pre_pos, html->priv->im_pre_len);)
-                                                                                
-                html_undo_freeze (html->engine->undo);
-                html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos);
-                html_engine_set_mark (html->engine);
-                html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos + html->priv->im_pre_len);
-                html_engine_delete (html->engine);
-                html->priv->im_pre_len = 0;
-                html_undo_thaw (html->engine->undo);
-        }
-
-	pos = html->engine->cursor->position;
-	if (html->engine->mark && html->engine->mark->position > pos)
-		pos = html->engine->mark->position;
-
-	html->priv->im_block_reset = TRUE;
-	D_IM (printf ("IM commit %s\n", str);)
-	
-	/* Move cusor before preedit pos and commit the string */
-	html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos);
-	html_engine_paste_text (html->engine, str, -1);
-	/* Add preedit pos with number of str committed and move back */
-	html->priv->im_pre_pos += g_utf8_strlen (str, -1);
-	html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos);
-
-	html->priv->im_block_reset = state;
-
-	D_IM (printf ("IM commit pos: %d pre_pos: %d\n", pos, html->priv->im_pre_pos);)
-
-	if (html->priv->im_pre_pos >= pos)
-		html->priv->im_pre_pos += html->engine->cursor->position - pos;
-}
+	if (html->priv->im_pre_len > 0) {
+		gboolean state = html->priv->im_block_reset;
+		html->priv->im_block_reset = TRUE;
+		
+		html_undo_freeze (html->engine->undo);
+		html_engine_selection_push (html->engine);
 
-static void
-gtk_html_im_preedit_start_cb (GtkIMContext *context, GtkHTML *html)
-{
-	html->priv->im_pre_len = 0;
+		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos);
+		html_engine_set_mark (html->engine);
+		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos + html->priv->im_pre_len);
+		html_engine_delete (html->engine);
+		
+		html_engine_selection_pop (html->engine);
+		html_undo_thaw (html->engine->undo);
+		
+		html->priv->im_block_reset = state;
+	} else {
+		/* The current style can get confused while we are have a preedit string
+		 * in place, so we save the current style before we start preediting, and
+		 * restore it when the preedit string vanishes. (See bug #66204)
+		 */
+		html->priv->im_orig_style = html_engine_get_font_style (html->engine);
+	}
 }
 
 static void
-gtk_html_im_preedit_changed_cb (GtkIMContext *context, GtkHTML *html)
+update_preedit (GtkHTML *html)
 {
 	PangoAttrList *attrs;
 	gchar *preedit_string;
-	gint cursor_pos, initial_position;
+	gint cursor_pos, preedit_position;
 	gboolean state = html->priv->im_block_reset;
-	gboolean pop_selection = FALSE;
-	gint deleted = 0;
+	gboolean had_selection = FALSE;
+	gboolean had_preedit = html->priv->im_pre_len > 0;
+	gboolean hide_cursor;
 
-	D_IM (printf ("IM preedit changed cb [begin] cursor %d(%p) mark %d(%p) active: %d\n",
-		      html->engine->cursor ? html->engine->cursor->position : 0, html->engine->cursor,
-		      html->engine->mark ? html->engine->mark->position : 0, html->engine->mark,
-		      html_engine_is_selection_active (html->engine));)
 	html->priv->im_block_reset = TRUE;
 
+	html_undo_freeze (html->engine->undo);
+
+	/* The handling of the combination of a selection and a preedit string
+	 * is imperfect because the selection runs from the 'mark' to the cursor,
+	 * so we can't display the selection plus a separate cursor.
+	 *
+	 * What we do is display the preedit text after the selection (even if
+	 * the cursor is at the beginning of the selection), and hide the cursor.
+	 * It is generally going to be less confusing not to display a cursor
+	 * at all then to display a cursor in the wrong location. Putting the
+	 * preedit text after the selection has the handy side effect that the
+	 * preedit string doesn't affect the selection bounds.
+	 */
 	if (html_engine_is_selection_active (html->engine)) {
-		D_IM (printf ("IM push selection\n");)
 		html_engine_selection_push (html->engine);
+
+		preedit_position = MAX (html_cursor_get_position (html->engine->mark),
+					html_cursor_get_position (html->engine->cursor));
+		
+		/* We need to temporarily remove the selection, or when we paste in the preedit text,
+		 * it will replace the selection. 
+		 */
 		html_engine_disable_selection (html->engine);
+		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, preedit_position);
 		html_engine_edit_selection_updater_update_now (html->engine->selection_updater);
-		pop_selection = TRUE;
+		had_selection = TRUE;
 	}
-	initial_position = html->engine->cursor->position;
-	D_IM (printf ("IM initial position %d\n", initial_position);)
 
-	html_undo_freeze (html->engine->undo);
-
-	if (html->priv->im_pre_len > 0) {
-		D_IM (printf ("IM delete last preedit %d + %d\n", html->priv->im_pre_pos, html->priv->im_pre_len);)
-		
-		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos);
-		html_engine_set_mark (html->engine);
-		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos + html->priv->im_pre_len);
-		html_engine_delete (html->engine);
-		deleted = html->priv->im_pre_len;
-	} else
-		html->priv->im_orig_style = html_engine_get_font_style (html->engine);
-
-	gtk_im_context_get_preedit_string (html->priv->im_context, &preedit_string, &attrs, &cursor_pos);
-
-	D_IM (printf ("IM preedit changed to %s\n", preedit_string);)
+	/* Insert the new preedit string
+	 */
+	gtk_im_context_get_preedit_string (html->priv->im_context,
+					   &preedit_string, &attrs, &cursor_pos);
+	
 	html->priv->im_pre_len = g_utf8_strlen (preedit_string, -1);
+	cursor_pos = CLAMP (cursor_pos, 0, html->priv->im_pre_len); /* Paranoia */
 
 	if (html->priv->im_pre_len > 0) {
-		cursor_pos = CLAMP (cursor_pos, 0, html->priv->im_pre_len);
 		html->priv->im_pre_pos = html->engine->cursor->position;
 		html_engine_paste_text_with_extra_attributes (html->engine, preedit_string, html->priv->im_pre_len, attrs);
-		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos + cursor_pos);
-	} else
+	} else if (had_preedit)
 		html_engine_set_font_style (html->engine, 0, html->priv->im_orig_style);
+
 	g_free (preedit_string);
+	pango_attr_list_unref (attrs);
 
-	if (pop_selection) {
-		gint position= html->engine->cursor->position, cpos, mpos;
-		D_IM (printf ("IM pop selection\n");)
-		g_assert (html_engine_selection_stack_top (html->engine, &cpos, &mpos));
-		if (position < MAX (cpos, mpos) + html->priv->im_pre_len - deleted)
-			g_assert (html_engine_selection_stack_top_modify (html->engine, html->priv->im_pre_len - deleted));
-		html_engine_selection_pop (html->engine);
+	/* Update the cursor hiding
+	 */
+	hide_cursor = had_selection && html->priv->im_pre_len > 0;
+	if (hide_cursor != html->priv->im_hide_cursor) {
+		if (hide_cursor)
+			html_engine_hide_cursor (html->engine);
+		else
+			html_engine_show_cursor (html->engine);
+
+		html->priv->im_hide_cursor = hide_cursor;
 	}
-	/* that works for now, but idealy we should be able to have cursor positioned outside selection, so that preedit
-	   cursor is in the right place */
-	if (html->priv->im_pre_len == 0)
-		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine,
-						       initial_position >= html->priv->im_pre_pos + deleted ? initial_position - deleted : initial_position);
+
+	/* Get the correct cursor and mark for the new preedit string
+	 */
+	if (had_selection)
+		html_engine_selection_pop (html->engine);
+	else if (html->priv->im_pre_len > 0)
+		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, html->priv->im_pre_pos + cursor_pos);
 
 	if (html->engine->freeze_count == 1)
 		html_engine_thaw_idle_flush (html->engine);
-	/* FIXME gtk_im_context_set_cursor_location (im_context, &area); */
+	
 	html->priv->im_block_reset = state;
 
 	html_undo_thaw (html->engine->undo);
+}
 
-	D_IM (printf ("IM preedit changed cb [end] cursor %d(%p) mark %d(%p) active: %d\n",
-		      html->engine->cursor ? html->engine->cursor->position : 0, html->engine->cursor,
-		      html->engine->mark ? html->engine->mark->position : 0, html->engine->mark,
-		      html_engine_is_selection_active (html->engine));)
+static void
+gtk_html_im_commit_cb (GtkIMContext *context, const gchar *str, GtkHTML *html)
+{
+	gboolean state = html->priv->im_block_reset;
+
+	html->priv->im_block_reset = TRUE;
+	
+	D_IM (printf ("IM commit %s\n", str);)
+	
+	remove_preedit (html);
+
+	html_engine_paste_text (html->engine, str, -1);
+	
+	update_preedit (html);
+
+	html->priv->im_block_reset = state;
+}
+
+static void
+gtk_html_im_preedit_start_cb (GtkIMContext *context, GtkHTML *html)
+{
+	html->priv->im_pre_len = 0;
+}
+
+static void
+gtk_html_im_preedit_changed_cb (GtkIMContext *context, GtkHTML *html)
+{
+	remove_preedit (html);
+	update_preedit (html);
 }
 
 static gchar *
@@ -3127,6 +3148,7 @@
 	gchar *text = NULL;
 
 	if (!html_object_is_text (o)) {
+		*offset = 0;
 		if (e->cursor->offset == 0) {
 			prev = html_object_prev_not_slave (o);
 			if (html_object_is_text (prev)) {
@@ -3142,7 +3164,6 @@
 			} else
 				return NULL;
 		}
-		*offset = 0;
 	} else
 		*offset = e->cursor->offset;
 
@@ -3163,10 +3184,14 @@
 static gboolean
 gtk_html_im_retrieve_surrounding_cb (GtkIMContext *context, GtkHTML *html)
 {
-	gint offset;
+	gint cursor_offset, cursor_index;
+	gchar *str;
+
+	D_IM (printf ("IM gtk_html_im_retrieve_surrounding_cb\n"));
 
-	D_IM (printf ("IM gtk_html_im_retrieve_surrounding_cb\n");)
-	gtk_im_context_set_surrounding (context, get_surrounding_text (html->engine, &offset), -1, offset);
+	str = get_surrounding_text (html->engine, &cursor_offset);
+	cursor_index = g_utf8_offset_to_pointer (str, cursor_offset) - str;
+	gtk_im_context_set_surrounding (context, str, -1, cursor_index);
 
 	return TRUE;
 }
@@ -3182,8 +3207,9 @@
 		html_engine_set_mark (html->engine);
 		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, orig_position + offset + n_chars);
 		html_engine_delete (html->engine);
-		if (offset >= 0)
-			html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, orig_position);
+		if (offset < 0)
+			orig_position -= MIN (n_chars, - offset);
+		html_cursor_jump_to_position_no_spell (html->engine->cursor, html->engine, orig_position);
 	}
 	return TRUE;
 }
--- gtkhtml-3.3.2/src/htmlengine-edit-cut-and-paste.c.imcommit	2004-09-16 17:49:53.000000000 -0400
+++ gtkhtml-3.3.2/src/htmlengine-edit-cut-and-paste.c	2004-09-21 17:40:46.039176128 -0400
@@ -460,11 +460,11 @@
 place_cursor_before_mark (HTMLEngine *e)
 {
 	if (e->mark->position < e->cursor->position) {
-		HTMLCursor *tmp;
+		HTMLCursor tmp;
 
-		tmp = e->cursor;
-		e->cursor = e->mark;
-		e->mark = tmp;
+		html_cursor_copy (&tmp, e->cursor);
+		html_cursor_copy (e->cursor, e->mark);
+		html_cursor_copy (e->mark, &tmp);
 	}
 }
 
@@ -1713,12 +1713,10 @@
 
 		while (start->position < end->position) {
 			if (start->object->parent->parent == end->object->parent->parent) {
-				if (e->mark)
-					html_cursor_destroy (e->mark);
-				html_cursor_destroy (e->cursor);
-				e->mark = start;
-				e->cursor = end;
-				start = end = NULL;
+				if (!e->mark)
+					e->mark = html_cursor_new ();
+				html_cursor_copy (e->mark, start);
+				html_cursor_copy (e->cursor, end);
 				delete_object (e, NULL, NULL, HTML_UNDO_UNDO, TRUE);
 				break;
 			} else {
@@ -1750,10 +1748,8 @@
 			}
 		}
 
-		if (start)
-			html_cursor_destroy (start);
-		if (end)
-			html_cursor_destroy (end);
+		html_cursor_destroy (start);
+		html_cursor_destroy (end);
 		html_cursor_jump_to_position (e->cursor, e, start_position);
 	}
 	html_undo_level_end (e->undo);