Index: components/html-editor/ChangeLog
===================================================================
--- components/html-editor/ChangeLog	(revision 8593)
+++ components/html-editor/ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2007-10-12  Milan Crha  <mcrha@redhat.com>
+
+	** Fix for bug #318592
+
+	* editor-control-factory.c: (editor_api_event):
+	Added invocation of "link_clicked" from editor.
+
 2007-09-27  Milan Crha  <mcrha@redhat.com>
 
 	** Fix for bug #434631
Index: components/html-editor/editor-control-factory.c
===================================================================
--- components/html-editor/editor-control-factory.c	(revision 8593)
+++ components/html-editor/editor-control-factory.c	(working copy)
@@ -776,6 +776,9 @@
 			case GTK_HTML_EDITOR_EVENT_DELETE:
 				send_event_void (engine, listener, "delete");
 				break;
+			case GTK_HTML_EDITOR_EVENT_LINK_CLICKED:
+				retval = send_event_str (engine, listener, "link_clicked", args);
+				break;
 			default:
 				g_warning ("Unsupported event.\n");
 			}
Index: src/ChangeLog
===================================================================
--- src/ChangeLog	(revision 8593)
+++ src/ChangeLog	(working copy)
@@ -1,3 +1,20 @@
+2007-10-12  Milan Crha  <mcrha@redhat.com>
+
+	** Fix for bug #318592
+
+	* gtkhtml-private.h: (struct _GtkHTMLPrivate):
+	New member 'in_url_test_mode'.
+	* gtkhtml-enums.h: (enum GtkHTMLEditorEventType):
+	New value 'GTK_HTML_EDITOR_EVENT_LINK_CLICKED'.
+	* gtkhtml.c: (update_mouse_cursor), (key_press_event),
+	(key_release_event), (on_object), (gtk_html_init):
+	When editable, then tracking Control key to enable clicking on links
+	to test them. Signal "link_clicked" is now emitted only when not in
+	editable mode or when in test_url_mode (before it was emitted always).
+	Also marked links as visited when clicked on them in editable mode.
+	Event "link_clicked" is emitted as editor event too in case of
+	active editable mode.
+
 2007-09-14  Akira TAGOH  <akira@tagoh.org>
 
 	** Fixes bug #443850
Index: src/gtkhtml-private.h
===================================================================
--- src/gtkhtml-private.h	(revision 8593)
+++ src/gtkhtml-private.h	(working copy)
@@ -74,6 +74,8 @@
 	gboolean in_object_resize;
 	GdkCursor *resize_cursor;
 	HTMLObject *resize_object;
+
+	gboolean in_url_test_mode;
 };
 
 void  gtk_html_private_calc_scrollbars  (GtkHTML                *html,
Index: src/gtkhtml-enums.h
===================================================================
--- src/gtkhtml-enums.h	(revision 8593)
+++ src/gtkhtml-enums.h	(working copy)
@@ -243,7 +243,8 @@
 	GTK_HTML_EDITOR_EVENT_COMMAND_BEFORE,
 	GTK_HTML_EDITOR_EVENT_COMMAND_AFTER,
 	GTK_HTML_EDITOR_EVENT_IMAGE_URL,
-	GTK_HTML_EDITOR_EVENT_DELETE
+	GTK_HTML_EDITOR_EVENT_DELETE,
+	GTK_HTML_EDITOR_EVENT_LINK_CLICKED
 } GtkHTMLEditorEventType;
 
 typedef enum {
Index: src/gtkhtml.c
===================================================================
--- src/gtkhtml.c	(revision 8593)
+++ src/gtkhtml.c	(working copy)
@@ -163,6 +163,8 @@
 				      gdouble old_width, gdouble old_height,
 				      gboolean *changed_x, gboolean *changed_y);
 
+static gint motion_notify_event (GtkWidget *widget, GdkEventMotion *event);
+
 /* keybindings signal hadlers */
 static void     scroll                 (GtkHTML *html, GtkOrientation orientation, GtkScrollType scroll_type, gfloat position);
 static void     cursor_move            (GtkHTML *html, GtkDirectionType dir_type, GtkHTMLCursorSkipType skip);
@@ -962,6 +964,21 @@
 	html_engine_schedule_update (engine);
 }
 
+static void
+update_mouse_cursor (GtkWidget *widget, guint state)
+{
+	GdkEventMotion event;
+
+	/* a bit hacky here */
+	memset (&event, 0, sizeof (GdkEventMotion));
+	event.type = GDK_MOTION_NOTIFY;
+	event.window = widget->window;
+	event.send_event = FALSE;
+	event.state = state;
+
+	motion_notify_event (widget, &event);
+}
+
 static gint
 key_press_event (GtkWidget *widget, GdkEventKey *event)
 {
@@ -970,11 +987,23 @@
 	gboolean retval = FALSE, update = TRUE;
 	HTMLObject *focus_object;
 	gint focus_object_offset;
+	gboolean url_test_mode;
 
 	html->binding_handled = FALSE;
 	html->priv->update_styles = FALSE;
 	html->priv->event_time = event->time;
 
+	if ((event->keyval == GDK_Control_L || event->keyval == GDK_Control_R)
+	    && html_engine_get_editable (html->engine))
+		url_test_mode = TRUE;
+	else
+		url_test_mode = FALSE;
+
+	if (html->priv->in_url_test_mode != url_test_mode) {
+		html->priv->in_url_test_mode = url_test_mode;
+		update_mouse_cursor (widget, event->state);
+	}
+
 	if (html_engine_get_editable (html->engine)) {
 		if (gtk_im_context_filter_keypress (html->priv->im_context, event)) {
 			html_engine_reset_blinking_cursor (html->engine);
@@ -1036,6 +1065,11 @@
 {
 	GtkHTML *html = GTK_HTML (widget);
 
+	if (html->priv->in_url_test_mode) {
+		html->priv->in_url_test_mode = FALSE;
+		update_mouse_cursor (widget, event->state);
+	}
+
 	if (!html->binding_handled && html_engine_get_editable (html->engine)) {
 		if (gtk_im_context_filter_keypress (html->priv->im_context, event)) {
 			html->priv->need_im_reset = TRUE;
@@ -1300,7 +1334,7 @@
 			set_pointer_url (html, url);
 			dnd_link_set (widget, obj, offset);
 			
-			if (html->engine->editable)
+			if (html->engine->editable && !html->priv->in_url_test_mode)
 				gdk_window_set_cursor (window, html->ibeam_cursor);
 			else {
 				gdk_window_set_cursor (window, html->hand_cursor);
@@ -1907,12 +1941,30 @@
 		html->in_selection_drag = FALSE;
 
 		if (!html->priv->dnd_in_progress
-		    && html->pointer_url != NULL && ! html->in_selection) {
+		    && html->pointer_url != NULL && ! html->in_selection
+		    && (!gtk_html_get_editable (html) || html->priv->in_url_test_mode)) {
 			g_signal_emit (widget,  signals[LINK_CLICKED], 0, html->pointer_url);
 			focus_object = html_engine_get_focus_object (html->engine, &focus_object_offset);
 			if (HTML_IS_TEXT(focus_object)) {
 				html_text_set_link_visited (HTML_TEXT(focus_object), focus_object_offset, html->engine, TRUE);
-			}   
+			}
+
+			if (html->priv->in_url_test_mode) {
+				GValue arg;
+				guint offset;
+
+				memset (&arg, 0, sizeof (GValue));
+				g_value_init (&arg, G_TYPE_STRING);
+				g_value_set_string (&arg, html->pointer_url);
+
+				gtk_html_editor_event (html, GTK_HTML_EDITOR_EVENT_LINK_CLICKED, &arg);
+
+				g_value_unset (&arg);
+
+				focus_object = html_engine_get_object_at (html->engine, x, y, &offset, TRUE);
+				if (HTML_IS_TEXT (focus_object))
+					html_text_set_link_visited (HTML_TEXT (focus_object), (gint) offset, html->engine, TRUE);
+			}
 		}
 	}
 
@@ -3457,6 +3509,7 @@
 	html->priv->search_input_line = NULL;
 	html->priv->in_object_resize = FALSE;
 	html->priv->resize_cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
+	html->priv->in_url_test_mode = FALSE;
 
 	gtk_selection_add_targets (GTK_WIDGET (html),
 				   GDK_SELECTION_PRIMARY,
