Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtkhtml2/ChangeLog,v
retrieving revision 1.401
diff -u -p -r1.401 ChangeLog
--- ChangeLog	14 Dec 2003 12:27:56 -0000	1.401
+++ ChangeLog	16 Dec 2003 17:44:40 -0000
@@ -1,3 +1,91 @@
+2003-12-16  Padraig O'Briain  <padraig.obriain@sun.com>
+
+	This is part of the fix for bug #123008. It uses F7 to toggle whether
+	cursor should be visible. It adds support for Left, Right, Ctrl+Left
+	and Ctrl+Right to navigate  or select the text in a HtmlView.
+
+	* libgtkhtml/view/htmlselection.c:
+	(html_selection_get_text): Add casts to fix compiler warnings.
+	(html_selection_extend): New function to extend the current selection.
+
+	* libgtkhtml/view/htmlview.c:
+	(html_view_get_box_text_for_offset): New function which returns
+	the HtmlBoxText which contains the specified character offset.
+	(html_view_get_offset_for_box_text): New function which returns
+	the offset for the  start of a specified HtmlBoxText.
+	(html_view_get_cursor_position): New function which returns the 
+	cursor position. If text is selected it uses the end of the selection.
+	(html_view_set_cursor_position): New function which sets the cursor
+	position
+	(html_view_get_selection_bound): New function which returns the 
+	selection bound. If texrt is selected it used the start of the 
+	selection.
+	(html_view_set_selection_bound): New function which sets the selection
+	bound.
+	(html_view_get_cursor_visible): New function which returns whether the 
+	cursor should be visible when blinking.
+	(html_view_set_cursor_visible): New function which sets whether the
+	cursor should be visible when blinking.
+	(html_view_get_blink_timeout): New function which gets the blink 
+	timeout handler id.
+	(html_view_set_blink_timeout): New function which sets the blink 
+	timeout handler id.
+	(html_view_get_button): New function which gets the mouse button 
+	which is pressed.
+	(html_view_set_button): New function which sets the mouse button 
+	which is pressed.
+	(html_view_get_layout): New function which gets the PangoLayout for
+	the HtmlView which is used to navigate the text.
+	(html_view_get_layout_text): New function which gets the txet in the
+	PangoLayout for the HtmlView.
+	(html_view_set_layout): New function which sets the PangoLayout for
+	the HtmlView.
+	(html_view_setup_layout): New function which sets the text in the
+	PangoLayout for the HtmlView.
+	(html_view_toggle_cursor): New function used to toggle whether the
+	cursor should be shown.
+	(html_view_draw_insertion_cursor): New function to draw the cursor.
+	It is based on _gtk_draw_insertion_cursor() from gtkstyle.c.
+	(html_view_draw_cursor): New function whether determines whether the
+	cursor should be drawn. If so, it determines it should be drawn and
+	calls html_view_draw_insertion_cursor.
+	(html_view_check_cursor_blink): New function which checks whether
+	a cursor should be drawn and calls a timeout handler to blink the
+	cursor or remove a timeout handler if one exists.
+	(html_view_pend_cursor_blink): New function which determines whether
+	cursor should blink and calls a timeout handler to blink the cursor.
+	(html_view_move_visually): New function which moves a character
+	offset visually.
+	(html_view_move_backward_word): New function which moves a character 
+	offset to the start of a word.
+	(html_view_move_forward_word): New function which moves a character 
+	offset to the end of a word.
+	(html_view_paint): Add code to draw the cursor if it should be drawn.
+	(html_view_insert_node): Remove PangoLayout if root node is being set.
+	Set cursor position and selection bound to 0.
+	(html_view_text_updated): Fix compiler warning.
+	(html_view_disconnect_document): Fix compiler warnings.
+	(html_view_motion_notify): Check that correct mouse button is pressed.
+	All call to html_view_check_cursor_blink
+	(html_view_button_press): Store the mouse button which is pressed.
+	(html_view_button_release): Check that correct mouse button is pressed.
+	Unset the stored mouse button.
+	(html_view_focus_in): Add call to html_view_check_cursor_blink.
+	(html_view_focus_out): Add call to html_view_check_cursor_blink.
+	(html_view_key_press): New function which calls 
+	html_view_pend_cursor_blink abd chains up.
+	(html_view_finalize): Destroy the PangoLayout.
+	(html_real_move_cursor): Add code to support GtkMoveMentTypes
+	GTK_MOVEMENT_VISUAL_POSITIONS and GTK_MOVEMENT_WORDS when moving the
+	cursor. Add support for selection using the keyboard.
+	(html_view_add_move_key_binding): Add support for selection extension.
+	(html_view_class_init): Add signal "toggle-cursor" which no
+	default signal handler.
+	Add keybindings for Ctrl+Left and Ctrl+Right for word movement.
+	Bind toggle-cursor to F7.
+	(html_view_init): Add signal handler for toggle-cursor.
+	
+	
 2003-12-14  Padraig O'Briain  <padraig.obriain@sun.com>
 
 	* libgtkhtml/a11y/htmlboxaccessible.c (html_box_text_accessible_new):
Index: libgtkhtml/view/htmlselection.c
===================================================================
RCS file: /cvs/gnome/gtkhtml2/libgtkhtml/view/htmlselection.c,v
retrieving revision 1.9
diff -u -p -r1.9 htmlselection.c
--- libgtkhtml/view/htmlselection.c	14 Apr 2003 14:07:56 -0000	1.9
+++ libgtkhtml/view/htmlselection.c	16 Dec 2003 17:44:40 -0000
@@ -49,18 +49,18 @@ html_selection_get_text (HtmlView *view)
 			g_assert_not_reached ();
 			break;
 		case HTML_BOX_TEXT_SELECTION_END:
-			g_string_append_len (str, text->canon_text, g_utf8_offset_to_pointer (text->canon_text, text->sel_end_index) - (gchar *)text->canon_text);
+			g_string_append_len (str, (gchar *)text->canon_text, g_utf8_offset_to_pointer ((gchar *)text->canon_text, text->sel_end_index) - (gchar *)text->canon_text);
 			break;
 		case HTML_BOX_TEXT_SELECTION_START:
-			g_string_append_len (str, g_utf8_offset_to_pointer (text->canon_text, text->sel_start_index),
-					 g_utf8_offset_to_pointer (text->canon_text, text->length) - g_utf8_offset_to_pointer (text->canon_text, text->sel_start_index));
+			g_string_append_len (str, g_utf8_offset_to_pointer ((gchar *)text->canon_text, text->sel_start_index),
+					 g_utf8_offset_to_pointer ((gchar *)text->canon_text, text->length) - g_utf8_offset_to_pointer ((gchar *)text->canon_text, text->sel_start_index));
 			break;
 		case HTML_BOX_TEXT_SELECTION_FULL:
-			g_string_append_len (str, text->canon_text, g_utf8_offset_to_pointer (text->canon_text, text->length) - (gchar *)text->canon_text);
+			g_string_append_len (str, (gchar *)text->canon_text, g_utf8_offset_to_pointer ((gchar *)text->canon_text, text->length) - (gchar *)text->canon_text);
 			break;
 		case HTML_BOX_TEXT_SELECTION_BOTH:
-			g_string_append_len (str, g_utf8_offset_to_pointer (text->canon_text, MIN (text->sel_start_index, text->sel_end_index)),
-					 g_utf8_offset_to_pointer (text->canon_text, MAX (text->sel_end_index, text->sel_start_index)) - g_utf8_offset_to_pointer (text->canon_text, MIN (text->sel_start_index, text->sel_end_index)));
+			g_string_append_len (str, g_utf8_offset_to_pointer ((gchar *)text->canon_text, MIN (text->sel_start_index, text->sel_end_index)),
+					 g_utf8_offset_to_pointer ((gchar *)text->canon_text, MAX (text->sel_end_index, text->sel_start_index)) - g_utf8_offset_to_pointer ((gchar *)text->canon_text, MIN (text->sel_start_index, text->sel_end_index)));
 			break;
 		}
 	}
@@ -437,8 +437,8 @@ set_traversal (HtmlView *view, HtmlBox *
 			int text_len;
 				
 			view->sel_list = g_slist_prepend (view->sel_list, text);
-			text_len = g_utf8_pointer_to_offset (text->canon_text,
-							     text->canon_text + text->length);
+			text_len = g_utf8_pointer_to_offset ((gchar *)text->canon_text,
+							     (gchar *)text->canon_text + text->length);
 				
 			if (*offset > 0) {
 				if (*offset < text_len) {
@@ -516,3 +516,44 @@ html_selection_set (HtmlView *view, 
 	g_slist_foreach (view->sel_list, repaint_sel, view);
 	html_selection_update_primary_selection (view);
 }
+
+/**
+ * html_selection_extend:
+ * @view:   the view in which to extend the selection.
+ * @start:  the HtmlBoxText the @offset is relative of.
+ * @offset: offset in characters from @start box to the selection start.
+ * @len:    selection length in characters.
+ * 
+ * This function extends the current selection from the @start box + @offset 
+ * @len characters forward.
+ **/
+void
+html_selection_extend (HtmlView *view, 
+		       HtmlBox *start, int start_offset, 
+		       int len)
+{
+	HtmlBox *root;
+	int found_start = TRUE;
+
+	g_return_if_fail (HTML_IS_VIEW (view));
+	g_return_if_fail (HTML_IS_BOX (start));
+
+	if (!view->sel_list) {
+		view->sel_start = start;
+		view->sel_end = NULL;
+		view->sel_start_index = start_offset;
+		html_selection_update_primary_selection (view);
+		html_selection_clear (view);
+		view->sel_flag = TRUE;
+	}
+	g_return_if_fail (start == view->sel_start);
+	g_return_if_fail (start_offset == view->sel_start_index);
+	root      = view->root;
+
+	html_selection_clear (view);
+
+	set_traversal (view, root, start, &start_offset, &len, &found_start);
+
+	g_slist_foreach (view->sel_list, repaint_sel, view);
+	html_selection_update_primary_selection (view);
+}
Index: libgtkhtml/view/htmlselection.h
===================================================================
RCS file: /cvs/gnome/gtkhtml2/libgtkhtml/view/htmlselection.h,v
retrieving revision 1.4
diff -u -p -r1.4 htmlselection.h
--- libgtkhtml/view/htmlselection.h	7 Apr 2003 08:30:56 -0000	1.4
+++ libgtkhtml/view/htmlselection.h	16 Dec 2003 17:44:40 -0000
@@ -33,6 +33,7 @@ void html_selection_end    (HtmlView *vi
 void html_selection_update (HtmlView *view, GdkEventMotion *event);
 void html_selection_clear  (HtmlView *view);
 void html_selection_set    (HtmlView *view, DomNode *start, int offset, int len);
+void html_selection_extend (HtmlView *view, HtmlBox *start, int start_offset, int len);
 gchar *html_selection_get_text (HtmlView *view);
 
 G_END_DECLS
Index: libgtkhtml/view/htmlview.c
===================================================================
RCS file: /cvs/gnome/gtkhtml2/libgtkhtml/view/htmlview.c,v
retrieving revision 1.159
diff -u -p -r1.159 htmlview.c
--- libgtkhtml/view/htmlview.c	28 Nov 2003 12:58:41 -0000	1.159
+++ libgtkhtml/view/htmlview.c	16 Dec 2003 17:44:41 -0000
@@ -40,6 +40,7 @@
 #include "graphics/htmlgdkpainter.h"
 #include "util/htmlmarshal.h"
 #include "htmlevent.h"
+#include "htmlselection.h"
 #include "htmlview.h"
 #include "config.h"
 
@@ -59,6 +60,7 @@ enum {
 	ON_URL,
 	ACTIVATE,
 	MOVE_FOCUS_OUT,
+	TOGGLE_CURSOR,
 	LAST_SIGNAL
 };
 
@@ -84,6 +86,685 @@ HTML_ACCESSIBLE_FACTORY (HTML_TYPE_BOX_T
 #endif
 
 static GQuark quark_moving_focus_out = 0;
+static GQuark quark_cursor_position = 0;
+static GQuark quark_selection_bound = 0;
+static GQuark quark_layout = 0;
+static GQuark quark_cursor_visible = 0;
+static GQuark quark_blink_timeout = 0;
+static GQuark quark_button = 0;
+static gboolean cursor_showing = FALSE;
+
+static HtmlBoxText*
+find_box (HtmlBox *box, gint *offset)
+{
+	HtmlBox *child;
+	HtmlBoxText *text;
+	gchar *char_text;
+	gint len;
+
+	if (HTML_IS_BOX_TEXT (box)) {
+		text = HTML_BOX_TEXT (box);
+		char_text = html_box_text_get_text (text, &len);
+		len = g_utf8_strlen (char_text, len);
+		if (len > *offset)
+			return text;
+		else
+			*offset -= len;
+	}
+	child = box->children;	
+	while (child) {
+		text = find_box (child, offset);
+		if (text)
+			return text;
+		child = child->next;
+	}
+	return NULL;
+}
+
+static HtmlBoxText*
+html_view_get_box_text_for_offset (HtmlView *view, gint *offset)
+{
+	HtmlBox *root;
+	gint temp_offset = *offset;
+	HtmlBoxText *text;
+
+	root = view->root;
+
+	if (root) {
+		text = find_box (root, &temp_offset);	
+		if (text)
+			*offset = temp_offset;
+		return text;
+	} else
+		return NULL;
+}
+
+static gboolean
+find_offset (HtmlBox *box, HtmlBoxText *box_text, gint *offset)
+{
+	HtmlBox *child;
+	HtmlBoxText *text;
+	gchar *char_text;
+	gint len;
+	gboolean ret;
+
+	if (HTML_IS_BOX_TEXT (box)) {
+		text = HTML_BOX_TEXT (box);
+		if (box_text == text)
+			return TRUE;
+		char_text = html_box_text_get_text (text, &len);
+		len = g_utf8_strlen (char_text, len);
+		*offset += len;
+	}
+	child = box->children;	
+	while (child) {
+		ret = find_offset (child, box_text, offset);
+		if (ret)
+			return ret;
+		child = child->next;
+	}
+	return FALSE;
+}
+
+static gboolean
+html_view_get_offset_for_box_text (HtmlView *view, HtmlBoxText *text, gint *offset)
+{
+	HtmlBox *root;
+	gint temp_offset = 0;
+	gboolean ret = FALSE;
+
+	root = view->root;
+
+	if (root) {
+		ret = find_offset (root, text, &temp_offset);
+		if (ret && offset)
+			*offset = temp_offset;
+	}
+	return ret;
+	
+}
+
+static gint
+html_view_get_cursor_position (HtmlView *view)
+{
+	gint val;
+	HtmlBoxText *text;
+
+	if (view->sel_list) {
+		text = HTML_BOX_TEXT (g_slist_last (view->sel_list)->data);	
+		if (html_view_get_offset_for_box_text (view, text, &val)) {
+			return val + view->sel_end_index;
+		}
+	}
+
+	if (quark_cursor_position == 0)
+		return 0;
+	val = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (view),
+						   quark_cursor_position));
+	return val;
+}
+
+static void
+html_view_set_cursor_position (HtmlView *view, gint cursor_position)
+{
+	if (quark_cursor_position == 0)
+		quark_cursor_position = g_quark_from_static_string ("html-view-cursor-position");
+
+	g_object_set_qdata (G_OBJECT (view), 
+			    quark_cursor_position,
+			    GINT_TO_POINTER (cursor_position));
+}
+
+static gint
+html_view_get_selection_bound (HtmlView *view)
+{
+	gint val;
+	HtmlBoxText *text;
+
+	if (view->sel_list) {
+		text = HTML_BOX_TEXT (view->sel_list->data);	
+		if (html_view_get_offset_for_box_text (view, text, &val)) {
+			return val + view->sel_start_index;
+		}
+	}
+	if (quark_selection_bound == 0)
+		return 0;
+
+	val = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (view),
+						   quark_selection_bound));
+	return val;
+}
+
+static void
+html_view_set_selection_bound (HtmlView *view, gint selection_bound)
+{
+	if (quark_selection_bound == 0)
+		quark_selection_bound = g_quark_from_static_string ("html-view-selection-bound");
+
+	g_object_set_qdata (G_OBJECT (view), 
+			    quark_selection_bound,
+			    GINT_TO_POINTER (selection_bound));
+}
+
+static gint
+html_view_get_cursor_visible (HtmlView *view)
+{
+	gint val;
+
+	if (quark_cursor_visible == 0)
+		return 0;
+	val = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (view),
+						   quark_cursor_visible));
+	return val;
+}
+
+static void
+html_view_set_cursor_visible (HtmlView *view, gint cursor_visible)
+{
+	if (quark_cursor_visible == 0)
+		quark_cursor_visible = g_quark_from_static_string ("html-view-cursor-visible");
+
+	g_object_set_qdata (G_OBJECT (view), 
+			    quark_cursor_visible,
+			    GINT_TO_POINTER (cursor_visible));
+}
+
+static guint
+html_view_get_blink_timeout (HtmlView *view)
+{
+	guint val;
+
+	if (quark_blink_timeout == 0)
+		return 0;
+	val = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (view),
+						    quark_blink_timeout));
+	return val;
+}
+
+static void
+html_view_set_blink_timeout (HtmlView *view, guint blink_timeout)
+{
+	if (quark_blink_timeout == 0)
+		quark_blink_timeout = g_quark_from_static_string ("html-view-blink-timeout");
+
+	g_object_set_qdata (G_OBJECT (view), 
+			    quark_blink_timeout,
+			    GUINT_TO_POINTER (blink_timeout));
+}
+
+static guint
+html_view_get_button (HtmlView *view)
+{
+	guint val;
+
+	if (quark_button == 0)
+		return 0;
+	val = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (view),
+						    quark_button));
+	return val;
+}
+
+static void
+html_view_set_button (HtmlView *view, guint button)
+{
+	if (quark_button == 0)
+		quark_button = g_quark_from_static_string ("html-view-buttont");
+
+	g_object_set_qdata (G_OBJECT (view), 
+			    quark_button,
+			    GUINT_TO_POINTER (button));
+}
+
+static PangoLayout*
+html_view_get_layout (HtmlView *view)
+{
+	gpointer val;
+
+	val = g_object_get_qdata (G_OBJECT (view),
+			          quark_layout);
+	return (PangoLayout*)val;
+}
+
+static const char*
+html_view_get_layout_text (HtmlView *view)
+{
+	PangoLayout *layout;
+	const char *ret;
+
+	layout = html_view_get_layout (view);
+	if (layout)
+		ret = pango_layout_get_text (layout);
+	else
+		ret = NULL;
+	return ret;
+}
+
+static void
+html_view_set_layout (HtmlView *view, const gchar *text)
+{
+	PangoLayout *layout;
+
+	if (quark_layout == 0)
+		quark_layout = g_quark_from_static_string ("html-view-layout");
+
+	layout = html_view_get_layout (view);
+	if (!layout) {
+		layout = gtk_widget_create_pango_layout (GTK_WIDGET (view), NULL);
+
+		g_object_set_qdata (G_OBJECT (view), 
+				    quark_layout,
+				    layout);
+	}
+	if (text)
+		pango_layout_set_text (layout, text, -1);
+}
+
+void
+add_text (HtmlBox *box, GString *str)
+{
+	HtmlBox *child;
+	HtmlBoxText *text;
+
+	if (HTML_IS_BOX_TEXT (box)) {
+		text = HTML_BOX_TEXT (box);
+		if (text->canon_text != NULL) {
+			g_string_append_len (str, (gchar*)text->canon_text, g_utf8_offset_to_pointer ((gchar*)text->canon_text, text->length) - (gchar*)text->canon_text);
+		}
+	}
+	child = box->children;
+	while (child) {
+		add_text (child, str);
+		child = child->next;
+	}
+	return;
+}
+
+static void
+html_view_setup_layout (HtmlView *view)
+{
+	HtmlBox *root;
+	GString *str;
+	int len;
+
+	if (html_view_get_layout_text (view))
+		return;
+
+	str = g_string_new ("");
+	root = view->root;
+
+	if (root)
+		add_text (root, str);
+	len = str->len;
+	if (len > 0)
+		str->str[len] = '\0';
+
+	html_view_set_layout (view, str->str);
+	g_string_free (str, TRUE);
+}
+
+static void
+html_view_toggle_cursor (HtmlView *view)
+{
+	cursor_showing = !cursor_showing;
+	gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
+/*
+ * This is a copy of the function _gtk_draw_insertion_cursor
+ * from gtkstyle.c
+ */
+static void
+html_view_draw_insertion_cursor (GtkWidget        *widget,
+                                 GdkDrawable      *drawable,
+                                 GdkGC            *gc,
+                                 GdkRectangle     *location,
+                                 GtkTextDirection  direction,
+                                 gboolean          draw_arrow)
+{
+	gint stem_width;
+	gint arrow_width;
+	gint x, y;
+	gint i;
+	gfloat cursor_aspect_ratio;
+	gint offset;
+
+	g_return_if_fail (direction != GTK_TEXT_DIR_NONE);
+
+	gtk_widget_style_get (widget, "cursor-aspect-ratio", &cursor_aspect_ratio, NULL);
+	stem_width = location->height * cursor_aspect_ratio + 1;
+	arrow_width = stem_width + 1;
+
+	/* put (stem_width % 2) on the proper side of the cursor */
+	if (direction == GTK_TEXT_DIR_LTR)
+		offset = stem_width / 2;
+	else
+		offset = stem_width - stem_width / 2;
+
+	for (i = 0; i < stem_width; i++)
+		gdk_draw_line (drawable, gc,
+                               location->x + i - offset,
+                               location->y,
+                               location->x + i - offset,
+                               location->y + location->height - 1);
+
+	if (draw_arrow) {
+		if (direction == GTK_TEXT_DIR_RTL) {
+			x = location->x - offset - 1;
+			y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
+
+			for (i = 0; i < arrow_width; i++) {
+				gdk_draw_line (drawable, gc,
+					       x, y + i + 1,
+					       x, y + 2 * arrow_width - i - 1);
+				x --;
+			}
+		} else if (direction == GTK_TEXT_DIR_LTR) {
+			x = location->x + stem_width - offset;
+			y = location->y + location->height - arrow_width * 2 - arrow_width + 1;
+
+			for (i = 0; i < arrow_width; i++) {
+				gdk_draw_line (drawable, gc,
+					       x, y + i + 1,
+					       x, y + 2 * arrow_width - i - 1);
+				x++;
+			}
+		}
+	}
+}
+
+static void 
+html_view_draw_cursor (HtmlView *view)
+{
+	gint cursor_position;
+	GdkRectangle rect;
+	gint x, y;
+	HtmlBoxText *text;
+	HtmlBox *box;
+	HtmlGdkPainter *gdk_painter;
+	gint direction;
+	GtkTextDirection text_direction;
+	gboolean at_end;
+
+	if (!cursor_showing)
+		return;
+
+        cursor_position = html_view_get_cursor_position (view);
+	text = html_view_get_box_text_for_offset (view, &cursor_position);
+	at_end = (text == NULL);
+	if (at_end) {
+		cursor_position--;
+		text = html_view_get_box_text_for_offset (view, &cursor_position);
+		g_return_if_fail (text);
+	}
+	html_box_text_get_character_extents (text, cursor_position, &rect);
+	box = HTML_BOX (text);
+	x = html_box_get_absolute_x (box);
+	y = html_box_get_absolute_y (box);
+	direction = html_box_get_bidi_level (box);
+	text_direction = (direction == HTML_DIRECTION_RTL) ? GTK_TEXT_DIR_RTL
+								   : GTK_TEXT_DIR_LTR;
+	rect.x += x;
+	if (at_end)
+		rect.x += rect.width;
+	rect.y += y;
+	rect.width = 0;
+	gdk_painter = HTML_GDK_PAINTER (view->painter); 
+	html_view_draw_insertion_cursor (GTK_WIDGET (view),
+					 gdk_painter->window,
+					 gdk_painter->gc,
+					 &rect,
+					 GTK_TEXT_DIR_LTR,
+					 FALSE);
+}
+
+/* We display the cursor when
+ *
+ *  - the selection is empty, AND
+ *  - the widget has focus
+ */
+
+#define CURSOR_ON_MULTIPLIER 0.66
+#define CURSOR_OFF_MULTIPLIER 0.34
+#define CURSOR_PEND_MULTIPLIER 1.0
+
+static gboolean
+cursor_blinks (HtmlView *view)
+{
+	GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (view));
+	gboolean blink;
+
+	if (GTK_WIDGET_HAS_FOCUS (view) &&
+	    cursor_showing &&
+	    html_view_get_selection_bound (view) == html_view_get_cursor_position (view)) {
+		g_object_get (settings, "gtk-cursor-blink", &blink, NULL);
+		return blink;
+	} else
+		return FALSE;
+}
+
+static gint
+get_cursor_time (HtmlView *view)
+{
+	GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (view));
+	gint time;
+
+	g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
+
+	return time;
+}
+
+static void
+show_cursor (HtmlView *view)
+{
+	if (!html_view_get_cursor_visible (view)) {
+		html_view_set_cursor_visible (view, 1);
+
+		if (GTK_WIDGET_HAS_FOCUS (view) && 
+		    (html_view_get_selection_bound (view) == html_view_get_cursor_position (view)))
+			gtk_widget_queue_draw (GTK_WIDGET (view));
+	}
+}
+
+static void
+hide_cursor (HtmlView *view)
+{
+	if (html_view_get_cursor_visible (view)) {
+		html_view_set_cursor_visible (view, 0);
+
+		if (GTK_WIDGET_HAS_FOCUS (view) && 
+		    html_view_get_selection_bound (view) == html_view_get_cursor_position (view))
+			gtk_widget_queue_draw (GTK_WIDGET (view));
+	}
+}
+
+/*
+ * Blink!
+ */
+static gint
+blink_cb (gpointer data)
+{
+	HtmlView *view;
+	guint blink_timeout;
+
+	GDK_THREADS_ENTER ();
+
+	view = HTML_VIEW (data);
+
+	if (!GTK_WIDGET_HAS_FOCUS (view)) {
+		g_warning ("HtmlView - did not receive focus-out-event. If you\n"
+			   "connect a handler to this signal, it must return\n"
+			   "FALSE so the entry gets the event as well");
+	}
+
+	g_assert (GTK_WIDGET_HAS_FOCUS (view));
+	g_assert (html_view_get_selection_bound (view) == html_view_get_cursor_position (view));
+
+	if (html_view_get_cursor_visible (view)) {
+		hide_cursor (view);
+		blink_timeout = g_timeout_add (get_cursor_time (view) * CURSOR_OFF_MULTIPLIER,
+					       blink_cb,
+					       view);
+	} else {
+		show_cursor (view);
+		blink_timeout = g_timeout_add (get_cursor_time (view) * CURSOR_ON_MULTIPLIER,
+					       blink_cb,
+					       view);
+	}
+	html_view_set_blink_timeout (view, blink_timeout);
+
+	GDK_THREADS_LEAVE ();
+
+	/* Remove ourselves */
+	return FALSE;
+}
+
+static void
+html_view_check_cursor_blink (HtmlView *view)
+{
+	guint blink_timeout;
+
+	if (cursor_blinks (view)) {
+		if (!html_view_get_blink_timeout (view)) {
+			blink_timeout = g_timeout_add (get_cursor_time (view) * CURSOR_ON_MULTIPLIER,
+               	                                blink_cb,
+               	                                view);
+			html_view_set_blink_timeout (view, blink_timeout);
+			show_cursor (view);
+		}
+	} else {
+		blink_timeout = html_view_get_blink_timeout (view);
+		if (blink_timeout) {
+			g_source_remove (blink_timeout);
+			html_view_set_blink_timeout (view, 0);
+		}
+		html_view_set_cursor_visible (view, 0);
+	}
+}
+
+static void
+html_view_pend_cursor_blink (HtmlView *view)
+{
+	guint blink_timeout;
+
+	if (cursor_blinks (view)) {
+		blink_timeout = html_view_get_blink_timeout (view);
+		if (blink_timeout)
+			g_source_remove (blink_timeout);
+
+		blink_timeout = g_timeout_add (get_cursor_time (view) * CURSOR_PEND_MULTIPLIER,
+					       blink_cb,
+					       view);
+		html_view_set_blink_timeout (view, blink_timeout);
+		show_cursor (view);
+ 	}
+}
+
+static gint
+html_view_move_visually (HtmlView *view, gint start, gint count)
+{
+	PangoLayout *layout;
+	const gchar* text;
+	gint index;
+
+	if (!cursor_showing)
+		return start;
+
+	html_view_setup_layout (view);
+	layout = html_view_get_layout (view);
+
+	text = pango_layout_get_text (layout);
+ 
+	index = g_utf8_offset_to_pointer (text, start) - text;
+
+	while (count != 0) {
+		int new_index, new_trailing;
+		gboolean strong;
+
+		strong = TRUE;
+
+		if (count > 0) {
+			pango_layout_move_cursor_visually (layout, strong, index, 0, 1, &new_index, &new_trailing);
+			count--;
+		} else {
+			pango_layout_move_cursor_visually (layout, strong, index, 0, -1, &new_index, &new_trailing);
+			count++;
+		}
+
+		if (new_index < 0 || new_index == G_MAXINT)
+			break;
+
+		index = new_index;
+
+		while (new_trailing--)
+			index = g_utf8_next_char (text + new_index) - text;
+	}
+ 
+	return g_utf8_pointer_to_offset (text, text + index);
+}
+
+static gint
+html_view_move_backward_word (HtmlView *view, gint start)
+{
+	PangoLayout *layout;
+	gint new_pos = start;
+	PangoLogAttr *log_attrs;
+	gint n_attrs;
+	HtmlBoxText *text;
+	gint box_offset;
+	const char *char_text;
+
+	html_view_setup_layout (view);
+	layout = html_view_get_layout (view);
+
+	pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+
+	new_pos--;
+	box_offset = new_pos;
+	text = html_view_get_box_text_for_offset (view, &box_offset);
+	box_offset = new_pos - box_offset;
+	/* Find the previous word beginning or start of current box*/
+	while (new_pos > 0 && (!log_attrs[new_pos].is_word_start &&
+				new_pos	> box_offset))
+		new_pos--;
+
+	g_free (log_attrs);
+	return new_pos;
+}
+
+static gint
+html_view_move_forward_word (HtmlView *view, gint start)
+{
+	PangoLayout *layout;
+	gint new_pos = start;
+	PangoLogAttr *log_attrs;
+	gint n_attrs;
+	HtmlBoxText *text;
+	gint box_offset;
+	const char *char_text;
+	gint len;
+	
+	html_view_setup_layout (view);
+	layout = html_view_get_layout (view);
+	len = g_utf8_strlen (pango_layout_get_text (layout), -1);
+	if (new_pos >= len)
+		return new_pos;
+
+	pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
+
+	/* Find the next word end or end of current box*/
+	new_pos++;
+	box_offset = new_pos;
+	text = html_view_get_box_text_for_offset (view, &box_offset);
+	char_text = html_box_text_get_text (text, &len);
+	len = g_utf8_strlen (char_text, len);
+	len += new_pos - box_offset;
+	while (new_pos < n_attrs && (!log_attrs[new_pos].is_word_end &&
+				     new_pos < len))
+		new_pos++;
+
+	g_free (log_attrs);
+	return new_pos;
+}
 
 static gboolean
 is_moving_focus_out (HtmlView *view)
@@ -363,6 +1044,10 @@ html_view_paint (HtmlView *view, GdkRect
 		/* Check that the document has not been deleted */
 		if (view->root->dom_node) {
 			html_box_paint (view->root, view->painter, area, 0, 0);
+			if (GTK_WIDGET_HAS_FOCUS (view) &&
+			    (html_view_get_selection_bound (view) == html_view_get_cursor_position (view)) &&
+			    html_view_get_cursor_visible (view))
+				html_view_draw_cursor (view);
 		}
 	}
 }
@@ -413,10 +1098,22 @@ html_view_insert_node (HtmlView *view, D
 				parent_box = view->root;
 		}
 		if (parent_box == NULL) {
+			PangoLayout *layout;
+
 			html_view_layout_tree_free (view, view->root);
 			if (view->document && view->document->focus_element)
 				html_document_update_focus_element (view->document, NULL);
 			view->root = new_box;
+
+			layout = html_view_get_layout (view);
+			if (layout) {
+				g_object_unref (layout);	
+				g_object_set_qdata (G_OBJECT (view), 
+						    quark_layout,
+						    NULL);
+			}
+			html_view_set_cursor_position (view, 0);
+			html_view_set_selection_bound (view, 0);
 		 } else {
 			html_box_append_child (parent_box, new_box);
 
@@ -491,7 +1188,7 @@ html_view_text_updated (HtmlDocument *do
 
 	if (box) {
 		/* FIXME: perhaps use g_object_set here? */
-		html_box_text_set_text (HTML_BOX_TEXT (box), node->xmlnode->content);
+		html_box_text_set_text (HTML_BOX_TEXT (box), (char *)node->xmlnode->content);
 		html_box_set_unrelayouted_up (box);
 	}
 	else {
@@ -660,33 +1357,33 @@ html_view_disconnect_document (HtmlView 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_inserted, view);
+					      (gpointer)html_view_inserted, view);
 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_removed, view);
+					      (gpointer)html_view_removed, view);
 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_text_updated, view);
+					      (gpointer)html_view_text_updated, view);
 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_style_updated, view);
+					      (gpointer)html_view_style_updated, view);
 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_relayout_callback, 
+					      (gpointer)html_view_relayout_callback, 
 					      view);
 
 	g_signal_handlers_disconnect_matched (G_OBJECT (view->document),
 					      G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA,
 					      0, 0, NULL,
-					      html_view_repaint_callback, 
+					      (gpointer)html_view_repaint_callback, 
 					      view);
 }
 
@@ -787,13 +1484,20 @@ html_view_motion_notify (GtkWidget *widg
 {
 	gint x, y;
 	GdkModifierType mask;
+	HtmlView *view;
 	
 	if (event->window != GTK_LAYOUT (widget)->bin_window)
 		return FALSE;
 
 	gdk_window_get_pointer (widget->window, &x, &y, &mask);
 
-	html_event_mouse_move (HTML_VIEW (widget), event);
+	view = HTML_VIEW (widget);
+	if (html_view_get_button (view) != 1)
+		return FALSE;
+
+	html_event_mouse_move (view, event);
+
+	html_view_check_cursor_blink (view);
 
 	return FALSE;
 }
@@ -801,13 +1505,23 @@ html_view_motion_notify (GtkWidget *widg
 static gboolean
 html_view_button_press (GtkWidget *widget, GdkEventButton *event)
 {
-	if (!GTK_WIDGET_HAS_FOCUS (widget))
-		gtk_widget_grab_focus (widget);
-	
+	HtmlView *view;
+	guint button;
+
 	if (event->window != GTK_LAYOUT (widget)->bin_window)
 		return FALSE;
 
-	html_event_button_press (HTML_VIEW (widget), event);
+	view = HTML_VIEW (widget);
+
+	button = html_view_get_button (view);
+	if (button && event->button != button)
+		return FALSE;
+	html_view_set_button (view, event->button);
+
+	if (!GTK_WIDGET_HAS_FOCUS (widget))
+		gtk_widget_grab_focus (widget);
+	
+	html_event_button_press (view, event);
 	
 	return FALSE;
 }
@@ -815,10 +1529,18 @@ html_view_button_press (GtkWidget *widge
 static gboolean
 html_view_button_release (GtkWidget *widget, GdkEventButton *event)
 {
+	HtmlView *view;
+
 	if (event->window != GTK_LAYOUT (widget)->bin_window)
 		return FALSE;
 
-	html_event_button_release (HTML_VIEW (widget), event);
+	view = HTML_VIEW (widget);
+	if (html_view_get_button (view) != event->button)
+		return FALSE;
+
+	html_view_set_button (view, 0);
+
+	html_event_button_release (view, event);
 	
 	return FALSE;
 }
@@ -835,6 +1557,8 @@ html_view_focus_in (GtkWidget *widget, G
 	if (element) {
 		html_document_update_focus_element (view->document, element);
 	}
+	html_view_check_cursor_blink (view);
+
 	return GTK_WIDGET_CLASS (parent_class)->focus_in_event (widget, event);
 }
 
@@ -850,17 +1574,22 @@ html_view_focus_out (GtkWidget *widget, 
 		if (GTK_CONTAINER (widget)->focus_child == NULL)
 			html_document_update_focus_element (view->document, NULL);
 	}
+	html_view_check_cursor_blink (view);
 	return GTK_WIDGET_CLASS (parent_class)->focus_out_event (widget, event);
 }
 
-#if 0
+
 static gboolean
 html_view_key_press (GtkWidget *widget, GdkEventKey *event)
 {
+	gboolean ret ;
+	HtmlView *view = HTML_VIEW (widget);
 
-	return html_event_key_press (HTML_VIEW (widget), event);
+	ret = GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+	html_view_pend_cursor_blink (view);
+	return ret;
 }
-#endif
+
 
 static void
 focus_element_destroyed (gpointer data)
@@ -911,7 +1640,12 @@ html_view_destroy (GtkObject *object)
 static void
 html_view_finalize (GObject *object)
 {
-	/*HtmlView *view = HTML_VIEW (object);*/
+	HtmlView *view = HTML_VIEW (object);
+	PangoLayout *layout;
+
+	layout = html_view_get_layout (view);
+	if (layout)
+		g_object_unref (layout);	
 
 	if (G_OBJECT_CLASS (parent_class)->finalize)
 		(G_OBJECT_CLASS (parent_class)->finalize) (object);
@@ -985,35 +1719,131 @@ html_view_set_focus_child (GtkContainer 
 	GTK_CONTAINER_CLASS (parent_class)->set_focus_child (container, child);
 }
 
+/* Compute the X position for an offset that corresponds to the "more important
+ * cursor position for that offset. We use this when trying to guess to which
+ * end of the selection we should go to when the user hits the left or
+ * right arrow key.
+ */
+static gint
+get_better_cursor_x (HtmlView *view,
+                     gint      offset)
+{
+  	GdkKeymap *keymap;
+  	GtkTextDirection keymap_direction;
+  	GtkTextDirection widget_direction;
+  	gboolean split_cursor;
+	GtkWidget *widget;
+  	PangoLayout *layout;
+  	const gchar *text;
+  	gint index;
+  	PangoRectangle strong_pos, weak_pos;
+
+	widget = GTK_WIDGET (view);
+
+  	keymap = gdk_keymap_get_for_display (gtk_widget_get_display (widget));
+  	keymap_direction =
+		(gdk_keymap_get_direction (keymap) == PANGO_DIRECTION_LTR) ?
+		GTK_TEXT_DIR_LTR : GTK_TEXT_DIR_RTL;
+  	widget_direction = gtk_widget_get_direction (widget);
+
+	html_view_setup_layout (view);
+	layout = html_view_get_layout (view);
+
+	text = pango_layout_get_text (layout);
+  	index = g_utf8_offset_to_pointer (text, offset) - text;
+	g_object_get (gtk_widget_get_settings (widget),
+			"gtk-split-cursor", &split_cursor,
+			NULL);
+
+	pango_layout_get_cursor_pos (layout, index, &strong_pos, &weak_pos);
+	if (split_cursor)
+		return strong_pos.x / PANGO_SCALE;
+	else
+	return (keymap_direction == widget_direction) ? 
+		strong_pos.x / PANGO_SCALE : weak_pos.x / PANGO_SCALE;
+}
+
 static void
 html_view_real_move_cursor (HtmlView *html_view, GtkMovementStep step, gint count, gboolean extend_selection)
 {
 	GtkAdjustment *vertical, *horizontal;
+	gint new_pos;
+	gint selection_bound;
+	gint cursor_position;
 
 	vertical = GTK_LAYOUT (html_view)->vadjustment;
 	horizontal = GTK_LAYOUT (html_view)->hadjustment;
 	
-	switch (step) {
-	case GTK_MOVEMENT_VISUAL_POSITIONS:
-		set_adjustment_clamped (horizontal, horizontal->value + horizontal->step_increment * count);
-		break;
-	case GTK_MOVEMENT_DISPLAY_LINES:
-		set_adjustment_clamped (vertical, vertical->value + vertical->step_increment * count);
-		break;
-	case GTK_MOVEMENT_PAGES:
-		set_adjustment_clamped (vertical, vertical->value + vertical->page_increment * count);
-		break;
-	case GTK_MOVEMENT_BUFFER_ENDS:
-		if (count == -1) {
-			set_adjustment_clamped (vertical, vertical->lower);
-		}
-		else {
-			set_adjustment_clamped (vertical, vertical->upper);
+	cursor_position = html_view_get_cursor_position (html_view);
+	selection_bound = html_view_get_selection_bound (html_view);
+	new_pos = cursor_position;
+	if (cursor_position != selection_bound && !extend_selection) {
+	/*
+	 * If we have a current selection and are not extending it move to the
+	 * start or end of the selection as appropriate.
+	 */
+		switch (step) {
+		case GTK_MOVEMENT_VISUAL_POSITIONS:
+			{
+			gint current_x = get_better_cursor_x (html_view, cursor_position);
+			gint bound_x = get_better_cursor_x (html_view, selection_bound);
+
+			if (count < 0)
+				new_pos = current_x < bound_x ? cursor_position : selection_bound;
+			else
+				new_pos = current_x > bound_x ? cursor_position : selection_bound;
+
+			html_selection_clear (html_view);
+			break;
+          		}
+          	}
+	} else {
+		switch (step) {
+		case GTK_MOVEMENT_VISUAL_POSITIONS:
+			new_pos = html_view_move_visually (html_view, new_pos, count);
+			set_adjustment_clamped (horizontal, horizontal->value + horizontal->step_increment * count);
+			break;
+        	case GTK_MOVEMENT_WORDS:
+			while (count > 0) {
+				new_pos = html_view_move_forward_word (html_view, new_pos);
+				count--;
+			}
+			while (count < 0) {
+				new_pos = html_view_move_backward_word (html_view, new_pos);
+				count++;
+			}	
+			break;
+		case GTK_MOVEMENT_DISPLAY_LINES:
+			set_adjustment_clamped (vertical, vertical->value + vertical->step_increment * count);
+			break;
+		case GTK_MOVEMENT_PAGES:
+			set_adjustment_clamped (vertical, vertical->value + vertical->page_increment * count);
+			break;
+		case GTK_MOVEMENT_BUFFER_ENDS:
+			if (count == -1) {
+				set_adjustment_clamped (vertical, vertical->lower);
+			} else {
+				set_adjustment_clamped (vertical, vertical->upper);
+			}
+			break;
+		default:
+			g_warning ("unknown step!\n");
 		}
-		break;
-	default:
-		g_warning ("unknown step!\n");
 	}
+
+	if (extend_selection) {
+		HtmlBoxText *old_text;
+		gint old_pos = selection_bound;
+
+		old_text = html_view_get_box_text_for_offset (html_view, &old_pos);
+		html_view_set_cursor_position (html_view, new_pos);
+		html_selection_extend (html_view, HTML_BOX (old_text), old_pos, new_pos - selection_bound);
+	} else {
+		html_view_set_cursor_position (html_view, new_pos);
+		html_view_set_selection_bound (html_view, new_pos);
+	}
+	html_view_check_cursor_blink (html_view);
+	html_view_pend_cursor_blink (html_view);
 }
 
 static void
@@ -1045,6 +1875,13 @@ html_view_add_move_binding (GtkBindingSe
 				      GTK_TYPE_ENUM, step,
 				      GTK_TYPE_INT, count,
 				      GTK_TYPE_BOOL, FALSE);
+
+	/* Selection-extending version */
+	gtk_binding_entry_add_signal (binding_set, keyval, modmask | GDK_SHIFT_MASK,
+				      "move_cursor", 3,
+				      GTK_TYPE_ENUM, step,
+				      GTK_TYPE_INT, count,
+				      GTK_TYPE_BOOL, TRUE);
 }
 
 static void
@@ -1211,6 +2048,7 @@ html_view_class_init (HtmlViewClass *kla
 	widget_class->motion_notify_event = html_view_motion_notify;
 	widget_class->button_press_event = html_view_button_press;
 	widget_class->button_release_event = html_view_button_release;
+	widget_class->key_press_event = html_view_key_press;
 
 	widget_class->focus_in_event = html_view_focus_in;
 	widget_class->focus_out_event = html_view_focus_out;
@@ -1280,6 +2118,15 @@ html_view_class_init (HtmlViewClass *kla
 			      G_TYPE_NONE, 1,
 			      GTK_TYPE_DIRECTION_TYPE);
 
+	view_signals [TOGGLE_CURSOR] =
+		g_signal_new ("toggle_cursor",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+			      0, /* No default signal handler */
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
 	widget_class->activate_signal = view_signals[ACTIVATE];
 
 	html_view_add_move_binding (binding_set, GDK_Page_Down, 0,
@@ -1293,17 +2140,34 @@ html_view_class_init (HtmlViewClass *kla
 
 	html_view_add_move_binding (binding_set, GDK_Down, 0,
 				    GTK_MOVEMENT_DISPLAY_LINES, 1);
+	html_view_add_move_binding (binding_set, GDK_KP_Down, 0,
+				    GTK_MOVEMENT_DISPLAY_LINES, 1);
 	html_view_add_move_binding (binding_set, GDK_Up, 0,
 				    GTK_MOVEMENT_DISPLAY_LINES, -1);
+	html_view_add_move_binding (binding_set, GDK_KP_Up, 0,
+				    GTK_MOVEMENT_DISPLAY_LINES, -1);
 
 	html_view_add_move_binding (binding_set, GDK_Right, 0,
 				    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
+	html_view_add_move_binding (binding_set, GDK_KP_Right, 0,
+				    GTK_MOVEMENT_VISUAL_POSITIONS, 1);
 	html_view_add_move_binding (binding_set, GDK_Left, 0,
 				    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
+	html_view_add_move_binding (binding_set, GDK_KP_Left, 0,
+				    GTK_MOVEMENT_VISUAL_POSITIONS, -1);
+	html_view_add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK,
+				    GTK_MOVEMENT_WORDS, 1);
+	html_view_add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
+				    GTK_MOVEMENT_WORDS, 1);
+	html_view_add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK,
+				    GTK_MOVEMENT_WORDS, -1);
+	html_view_add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
+				    GTK_MOVEMENT_WORDS, -1);
 	
 	html_view_add_tab_binding (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
 	html_view_add_tab_binding (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
-	
+	gtk_binding_entry_add_signal (binding_set, GDK_F7, 0,
+				      "toggle_cursor", 0);
 }
 
 static void
@@ -1323,6 +2187,9 @@ html_view_init (HtmlView *view)
 	view->relayout_idle_id = 0;
 	view->relayout_timeout_id = 0;
 	view->magnification = 1.0;
+	g_signal_connect (view, "toggle-cursor", G_CALLBACK (html_view_toggle_cursor), NULL);
+	html_view_set_cursor_position (view, 0);
+	html_view_set_layout (view, NULL);
 }
 
 GType
