diff --git a/components/editor/gtkhtml-editor.c b/components/editor/gtkhtml-editor.c
index 8f10855..c9cdc67 100644
--- a/components/editor/gtkhtml-editor.c
+++ b/components/editor/gtkhtml-editor.c
@@ -32,7 +32,8 @@ enum {
 	PROP_HTML_MODE,
 	PROP_INLINE_SPELLING,
 	PROP_MAGIC_LINKS,
-	PROP_MAGIC_SMILEYS
+	PROP_MAGIC_SMILEYS,
+	PROP_CHANGED
 };
 
 enum {
@@ -217,6 +218,12 @@ editor_url_requested_cb (GtkhtmlEditor *editor,
 }
 
 static void
+engine_undo_changed_cb (GtkhtmlEditor *editor, HTMLEngine *engine)
+{
+	g_object_notify (G_OBJECT (editor), "changed");
+}
+
+static void
 editor_command_popup_menu (GtkhtmlEditor *editor)
 {
 	g_warning ("GtkHTML command \"popup-menu\" not implemented");
@@ -500,6 +507,10 @@ editor_constructor (GType type,
 		html, "url_requested",
 		G_CALLBACK (editor_url_requested_cb), editor);
 
+	g_signal_connect_swapped (
+		html->engine, "undo-changed",
+		G_CALLBACK (engine_undo_changed_cb), editor);
+
 	/* Connect property dialog widgets to actions. */
 
 	gtk_activatable_set_related_action (
@@ -644,6 +655,11 @@ editor_set_property (GObject *object,
 				GTKHTML_EDITOR (object),
 				g_value_get_boolean (value));
 			return;
+		case PROP_CHANGED:
+			gtkhtml_editor_set_changed (
+				GTKHTML_EDITOR (object),
+				g_value_get_boolean (value));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -697,6 +713,11 @@ editor_get_property (GObject *object,
 				value, gtkhtml_editor_get_magic_smileys (
 				GTKHTML_EDITOR (object)));
 			return;
+		case PROP_CHANGED:
+			g_value_set_boolean (
+				value, gtkhtml_editor_get_changed (
+				GTKHTML_EDITOR (object)));
+			return;
 	}
 
 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -847,6 +868,16 @@ editor_class_init (GtkhtmlEditorClass *class)
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT));
 
+	g_object_class_install_property (
+		object_class,
+		PROP_CHANGED,
+		g_param_spec_boolean (
+			"changed",
+			_("Changed property"),
+			_("Whether editor changed"),
+			FALSE,
+			G_PARAM_READWRITE));
+
 	signals[COMMAND_AFTER] = g_signal_new (
 		"command-after",
 		G_OBJECT_CLASS_TYPE (class),
@@ -1108,6 +1139,8 @@ gtkhtml_editor_set_changed (GtkhtmlEditor *editor,
 	}
 
 	editor->priv->changed = changed;
+
+	g_object_notify (G_OBJECT (editor), "changed");
 }
 
 const gchar *
@@ -1726,7 +1759,7 @@ gtkhtml_editor_undo_end (GtkhtmlEditor *editor)
 
 	html = gtkhtml_editor_get_html (editor);
 
-	html_undo_level_end (html->engine->undo);
+	html_undo_level_end (html->engine->undo, html->engine);
 }
 
 gboolean
diff --git a/gtkhtml/gtkhtml.c b/gtkhtml/gtkhtml.c
index 17a8692..e49e235 100644
--- a/gtkhtml/gtkhtml.c
+++ b/gtkhtml/gtkhtml.c
@@ -2712,7 +2712,7 @@ drag_data_received (GtkWidget *widget, GdkDragContext *context,
                                  pasted = TRUE;
                          }
                  } while (list_len);
-                 html_undo_level_end (engine->undo);
+                 html_undo_level_end (engine->undo, engine);
 	}
 	break;
 	}
@@ -6136,7 +6136,7 @@ gtk_html_insert_html_generic (GtkHTML *html, GtkHTML *tmp, const gchar *html_src
 			html_object_remove_child (o->parent, o);
 			html_engine_append_flow (html->engine, o, html_object_get_recursive_length (o));
 		}
-		html_undo_level_end (html->engine->undo);
+		html_undo_level_end (html->engine->undo, html->engine);
 	} else {
 		g_return_if_fail (tmp->engine->clue);
 
diff --git a/gtkhtml/htmlengine-edit-clueflowstyle.c b/gtkhtml/htmlengine-edit-clueflowstyle.c
index 0bce7e8..0b99f03 100644
--- a/gtkhtml/htmlengine-edit-clueflowstyle.c
+++ b/gtkhtml/htmlengine-edit-clueflowstyle.c
@@ -241,7 +241,7 @@ static void
 add_undo (HTMLEngine *engine,
 	  ClueFlowStyleOperation *op, HTMLUndoDirection dir)
 {
-	html_undo_add_action (engine->undo, undo_action_from_op (engine, op), dir);
+	html_undo_add_action (engine->undo, engine, undo_action_from_op (engine, op), dir);
 }
 
 
diff --git a/gtkhtml/htmlengine-edit-cut-and-paste.c b/gtkhtml/htmlengine-edit-cut-and-paste.c
index 25a0ff9..d773abc 100644
--- a/gtkhtml/htmlengine-edit-cut-and-paste.c
+++ b/gtkhtml/htmlengine-edit-cut-and-paste.c
@@ -461,7 +461,7 @@ delete_setup_undo (HTMLEngine *e, HTMLObject *buffer, guint len, guint position_
 #ifdef OP_DEBUG
 	printf ("delete undo len %d\n", len);
 #endif
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Delete object", delete_undo_action,
 						    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
 						    position_after),
@@ -721,7 +721,7 @@ fix_empty_aligned_setup_undo (HTMLEngine *e, HTMLUndoDirection dir, HTMLObject *
 	undo->data.destroy = fix_empty_aligned_undo_destroy;
 	undo->ac       = ac;
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Remove empty aligned", fix_empty_aligned_undo_action,
 						    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
 						    html_cursor_get_position (e->cursor)),
@@ -825,7 +825,7 @@ html_engine_cut (HTMLEngine *e)
 	}
 
 	rv = delete_object (e, &e->clipboard, &e->clipboard_len, HTML_UNDO_UNDO, TRUE);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 
 #ifdef OP_DEBUG
 	printf ("cut  len: %d\n", e->clipboard_len);
@@ -989,7 +989,7 @@ insert_setup_undo (HTMLEngine *e, guint len, guint position_before, HTMLUndoDire
 
 	/* printf ("insert undo len %d\n", len); */
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Insert", insert_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -1024,7 +1024,7 @@ fix_aligned_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection di
 	html_clue_remove (HTML_CLUE (cf->parent), cf);
 	html_object_destroy (cf);
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Fix aligned", fix_aligned_redo_action,
 						    undo, html_cursor_get_position (e->cursor),
 						    position_before),
@@ -1041,7 +1041,7 @@ fix_align_setup_undo (HTMLEngine *e, guint position_before, HTMLUndoDirection di
 	html_undo_data_init (HTML_UNDO_DATA (undo));
 	/* printf ("insert undo len %d\n", len); */
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Undo aligned fix", fix_aligned_undo_action,
 						    undo, html_cursor_get_position (e->cursor),
 						    position_before),
@@ -1153,7 +1153,7 @@ html_engine_paste_object (HTMLEngine *e, HTMLObject *o, guint len)
 	html_undo_level_begin (e->undo, "Paste", "Paste");
 	html_engine_delete (e);
 	html_engine_insert_object (e, o, len, html_engine_get_insert_level_for_object (e, o));
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -1242,7 +1242,7 @@ insert_empty_paragraph (HTMLEngine *e, HTMLUndoDirection dir, gboolean add_undo)
 
 	gtk_html_editor_event_command (e->widget, GTK_HTML_COMMAND_INSERT_PARAGRAPH, FALSE);
 	if (add_undo)
-		html_undo_level_end (e->undo);
+		html_undo_level_end (e->undo, e);
 
 	html_engine_thaw (e);
 	g_signal_emit_by_name (e->widget, "object_inserted", 0, 0);
@@ -1445,7 +1445,7 @@ html_engine_insert_text_with_extra_attributes (HTMLEngine *e, const gchar *text,
 			text = nl + 1;
 		}
 	} while (nl);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -1465,7 +1465,7 @@ html_engine_paste_text_with_extra_attributes (HTMLEngine *e, const gchar *text,
 	g_free (redo_name);
 	html_engine_delete (e);
 	html_engine_insert_text_with_extra_attributes (e, text, len, attrs);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -1533,7 +1533,7 @@ html_engine_delete_n (HTMLEngine *e, guint len, gboolean forward)
 				html_cursor_backward (e->cursor, e);
 				html_engine_delete (e);
 				html_engine_insert_text (e, picto, -1);
-				html_undo_level_end (e->undo);
+				html_undo_level_end (e->undo, e);
 				g_free (picto);
 
 				html_engine_unblock_selection (e);
@@ -1569,7 +1569,7 @@ html_engine_cut_line (HTMLEngine *e)
 		html_cursor_forward (e->cursor, e);
 
 	html_engine_cut (e);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 typedef struct {
@@ -1684,7 +1684,7 @@ html_engine_append_object (HTMLEngine *e, HTMLObject *o, guint len)
 {
 	html_undo_level_begin (e->undo, "Append object", "Remove appended object");
 	append_object (e, o, len, HTML_UNDO_UNDO);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 static void
@@ -1753,7 +1753,7 @@ html_engine_append_flow (HTMLEngine *e, HTMLObject *o, guint len)
 {
 	html_undo_level_begin (e->undo, "Append flow", "Remove appended flow");
 	append_flow (e, o, len, HTML_UNDO_UNDO);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -1788,7 +1788,7 @@ html_engine_cut_and_paste_end (HTMLEngine *e)
 		insert_object (e, e->clipboard, e->clipboard_len, position, level, HTML_UNDO_UNDO, TRUE);
 		e->clipboard = NULL;
 	}
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 	html_engine_clipboard_pop (e);
 	html_engine_selection_pop (e);
 	html_engine_show_cursor (e);
@@ -1924,5 +1924,5 @@ html_engine_delete (HTMLEngine *e)
 		html_cursor_jump_to_position (e->cursor, e, start_position);
 
 	}
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
diff --git a/gtkhtml/htmlengine-edit-fontstyle.c b/gtkhtml/htmlengine-edit-fontstyle.c
index 9058821..6f7740d 100644
--- a/gtkhtml/htmlengine-edit-fontstyle.c
+++ b/gtkhtml/htmlengine-edit-fontstyle.c
@@ -321,7 +321,7 @@ set_empty_flow_style (HTMLEngine *e, GtkHTMLFontStyle and_mask, GtkHTMLFontStyle
 	undo->and_mask = and_mask;
 	undo->or_mask = old_or_mask;
 	undo->data.destroy = NULL;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set empty paragraph text style", set_empty_flow_style_undo_action,
 						    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
 						    html_cursor_get_position (e->cursor)), dir);
diff --git a/gtkhtml/htmlengine-edit-table.c b/gtkhtml/htmlengine-edit-table.c
index c4e7fad..eca7ae9 100644
--- a/gtkhtml/htmlengine-edit-table.c
+++ b/gtkhtml/htmlengine-edit-table.c
@@ -154,7 +154,7 @@ insert_column_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection
 static void
 insert_column_setup_undo (HTMLEngine *e, gint col, guint position_before, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Insert table column", insert_column_undo_action,
 						    insert_undo_data_new (col), html_cursor_get_position (e->cursor),
 						    position_before),
@@ -355,7 +355,7 @@ delete_column_undo_action (HTMLEngine *e, HTMLUndoData *undo_data, HTMLUndoDirec
 static void
 delete_column_setup_undo (HTMLEngine *e, HTMLTableCell **column, gint size, guint position_after, gint col, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Delete table column", delete_column_undo_action,
 						    HTML_UNDO_DATA (delete_cells_undo_new (column, size, col)),
 						    html_cursor_get_position (e->cursor),
@@ -506,7 +506,7 @@ insert_row_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection dir
 static void
 insert_row_setup_undo (HTMLEngine *e, gint row, guint position_before, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Insert table row", insert_row_undo_action,
 						    insert_undo_data_new (row),
 						    html_cursor_get_position (e->cursor),
@@ -610,7 +610,7 @@ static void
 delete_row_setup_undo (HTMLEngine *e, HTMLTableCell **row_cells, gint size, guint position_after,
 		       gint row, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Delete table row", delete_row_undo_action,
 						    HTML_UNDO_DATA (delete_cells_undo_new (row_cells, size, row)),
 						    html_cursor_get_position (e->cursor),
@@ -817,7 +817,7 @@ table_set_border_width (HTMLEngine *e, HTMLTable *t, gint border_width, gboolean
 	html_object_change_set (HTML_OBJECT (t), HTML_CHANGE_ALL_CALC);
 	html_engine_thaw (e);
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table border width", table_set_border_width_undo_action,
 						    HTML_UNDO_DATA (undo), html_cursor_get_position (e->cursor),
 						    html_cursor_get_position (e->cursor)), dir);
@@ -860,7 +860,7 @@ table_set_bg_color (HTMLEngine *e, HTMLTable *t, GdkColor *c, HTMLUndoDirection
 		undo->attr.color.has_bg_color = TRUE;
 	} else
 		undo->attr.color.has_bg_color = FALSE;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table background color", table_set_bg_color_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -906,7 +906,7 @@ table_set_bg_pixmap (HTMLEngine *e, HTMLTable *t, gchar *url, HTMLUndoDirection
 
 	undo = attr_undo_new (HTML_TABLE_BGPIXMAP);
 	undo->attr.pixmap = t->bgPixmap ? g_strdup (t->bgPixmap->url) : NULL;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table background pixmap", table_set_bg_pixmap_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -960,7 +960,7 @@ table_set_spacing (HTMLEngine *e, HTMLTable *t, gint spacing, gboolean relative,
 
 	undo = attr_undo_new (HTML_TABLE_SPACING);
 	undo->attr.spacing = t->spacing;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table spacing", table_set_spacing_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -1012,7 +1012,7 @@ table_set_padding (HTMLEngine *e, HTMLTable *t, gint padding, gboolean relative,
 
 	undo = attr_undo_new (HTML_TABLE_PADDING);
 	undo->attr.padding = t->padding;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table padding", table_set_padding_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -1085,7 +1085,7 @@ table_set_align (HTMLEngine *e, HTMLTable *t, HTMLHAlignType align, HTMLUndoDire
 	} else
 		g_assert_not_reached ();
 
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table align", table_set_align_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -1129,7 +1129,7 @@ table_set_width (HTMLEngine *e, HTMLTable *t, gint width, gboolean percent, HTML
 		: (HTML_OBJECT (t)->flags & HTML_OBJECT_FLAG_FIXEDWIDTH
 		   ? t->specified_width : 0);
 	undo->attr.width.percent = HTML_OBJECT (t)->percent != 0;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set table width", table_set_width_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
diff --git a/gtkhtml/htmlengine-edit-tablecell.c b/gtkhtml/htmlengine-edit-tablecell.c
index e522c5d..d045211 100644
--- a/gtkhtml/htmlengine-edit-tablecell.c
+++ b/gtkhtml/htmlengine-edit-tablecell.c
@@ -133,7 +133,7 @@ table_cell_set_bg_color (HTMLEngine *e, HTMLTableCell *cell, GdkColor *c, HTMLUn
 	undo = attr_undo_new (HTML_TABLE_CELL_BGCOLOR);
 	undo->attr.color.color        = cell->bg;
 	undo->attr.color.has_bg_color = cell->have_bg;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set cell background color", table_cell_set_bg_color_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -172,7 +172,7 @@ table_cell_set_bg_pixmap (HTMLEngine *e, HTMLTableCell *cell, gchar *url, HTMLUn
 
 	undo = attr_undo_new (HTML_TABLE_CELL_BGPIXMAP);
 	undo->attr.pixmap = cell->have_bgPixmap ? g_strdup (cell->bgPixmap->url) : NULL;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set cell background pixmap", table_cell_set_bg_pixmap_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -214,7 +214,7 @@ table_cell_set_halign (HTMLEngine *e, HTMLTableCell *cell, HTMLHAlignType halign
 
 	undo = attr_undo_new (HTML_TABLE_CELL_HALIGN);
 	undo->attr.halign = HTML_CLUE (cell)->halign;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set cell horizontal align", table_cell_set_halign_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -252,7 +252,7 @@ table_cell_set_valign (HTMLEngine *e, HTMLTableCell *cell, HTMLVAlignType valign
 
 	undo = attr_undo_new (HTML_TABLE_CELL_VALIGN);
 	undo->attr.valign = HTML_CLUE (cell)->valign;
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Set cell vertical align", table_cell_set_valign_undo_action,
 						    HTML_UNDO_DATA (undo),
 						    html_cursor_get_position (e->cursor),
@@ -291,7 +291,7 @@ table_cell_set_no_wrap (HTMLEngine *e, HTMLTableCell *cell, gboolean no_wrap, HT
 
 		undo = attr_undo_new (HTML_TABLE_CELL_NOWRAP);
 		undo->attr.no_wrap = cell->no_wrap;
-		html_undo_add_action (e->undo,
+		html_undo_add_action (e->undo, e,
 				      html_undo_action_new ("Set cell wrapping", table_cell_set_no_wrap_undo_action,
 							    HTML_UNDO_DATA (undo),
 							    html_cursor_get_position (e->cursor),
@@ -331,7 +331,7 @@ table_cell_set_heading (HTMLEngine *e, HTMLTableCell *cell, gboolean heading, HT
 
 		undo = attr_undo_new (HTML_TABLE_CELL_HEADING);
 		undo->attr.heading = cell->heading;
-		html_undo_add_action (e->undo,
+		html_undo_add_action (e->undo, e,
 				      html_undo_action_new ("Set cell style", table_cell_set_heading_undo_action,
 							    HTML_UNDO_DATA (undo),
 							    html_cursor_get_position (e->cursor),
@@ -374,7 +374,7 @@ table_cell_set_width (HTMLEngine *e, HTMLTableCell *cell, gint width, gboolean p
 		undo = attr_undo_new (HTML_TABLE_CELL_WIDTH);
 		undo->attr.width.width = cell->fixed_width;
 		undo->attr.width.percent = cell->percent_width;
-		html_undo_add_action (e->undo,
+		html_undo_add_action (e->undo, e,
 				      html_undo_action_new ("Set cell style", table_cell_set_width_undo_action,
 							    HTML_UNDO_DATA (undo),
 							    html_cursor_get_position (e->cursor),
@@ -584,7 +584,7 @@ expand_cspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection d
 static void
 expand_cspan_setup_undo (HTMLEngine *e, GSList *slist, gint cspan, guint position_before, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Expand Column Span", expand_cspan_undo_action,
 						    expand_undo_data_new (cspan, slist), html_cursor_get_position (e->cursor),
 						    position_before),
@@ -666,7 +666,7 @@ collapse_cspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection
 static void
 collapse_cspan_setup_undo (HTMLEngine *e, gint cspan, guint position_before, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Collapse Column Span", collapse_cspan_undo_action,
 						    collapse_undo_data_new (cspan), html_cursor_get_position (e->cursor),
 						    position_before),
@@ -777,7 +777,7 @@ collapse_rspan_undo_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection
 static void
 collapse_rspan_setup_undo (HTMLEngine *e, gint rspan, guint position_before, HTMLUndoDirection dir)
 {
-	html_undo_add_action (e->undo,
+	html_undo_add_action (e->undo, e,
 			      html_undo_action_new ("Collapse Row Span", collapse_rspan_undo_action,
 						    collapse_undo_data_new (rspan), html_cursor_get_position (e->cursor),
 						    position_before),
diff --git a/gtkhtml/htmlengine-edit-text.c b/gtkhtml/htmlengine-edit-text.c
index 27e32a8..1cd49c5 100644
--- a/gtkhtml/htmlengine-edit-text.c
+++ b/gtkhtml/htmlengine-edit-text.c
@@ -82,7 +82,7 @@ html_engine_capitalize_word (HTMLEngine *e)
 						   upper_lower, GINT_TO_POINTER (FALSE));
 			html_engine_disable_selection (e);
 		}
-		html_undo_level_end (e->undo);
+		html_undo_level_end (e->undo, e);
 	}
 }
 
diff --git a/gtkhtml/htmlengine-edit.c b/gtkhtml/htmlengine-edit.c
index a746e0b..5a66b16 100644
--- a/gtkhtml/htmlengine-edit.c
+++ b/gtkhtml/htmlengine-edit.c
@@ -560,7 +560,7 @@ html_engine_indent_paragraph (HTMLEngine *e)
 
 	html_cursor_jump_to_position (e->cursor, e, position);
 	html_engine_thaw (e);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -615,7 +615,7 @@ html_engine_indent_pre_line (HTMLEngine *e)
 
 	html_cursor_jump_to_position (e->cursor, e, position);
 	html_engine_thaw (e);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -682,7 +682,7 @@ html_engine_space_and_fill_line (HTMLEngine *e)
 	html_engine_fill_pre_line (e);
 
 	html_engine_thaw (e);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 void
@@ -697,7 +697,7 @@ html_engine_break_and_fill_line (HTMLEngine *e)
 
 	html_engine_insert_empty_paragraph (e);
 	html_engine_thaw (e);
-	html_undo_level_end (e->undo);
+	html_undo_level_end (e->undo, e);
 }
 
 gboolean
diff --git a/gtkhtml/htmlengine.c b/gtkhtml/htmlengine.c
index 4d8d758..a9ab521 100644
--- a/gtkhtml/htmlengine.c
+++ b/gtkhtml/htmlengine.c
@@ -149,6 +149,7 @@ enum {
 	REDIRECT,
 	SUBMIT,
 	OBJECT_REQUESTED,
+	UNDO_CHANGED,
 	LAST_SIGNAL
 };
 
@@ -4336,6 +4337,15 @@ html_engine_class_init (HTMLEngineClass *klass)
 			      G_TYPE_BOOLEAN, 1,
 			      G_TYPE_OBJECT);
 
+	signals [UNDO_CHANGED] =
+		g_signal_new ("undo-changed",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (HTMLEngineClass, undo_changed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
 	object_class->finalize = html_engine_finalize;
 	object_class->set_property = html_engine_set_property;
 
@@ -6046,7 +6056,7 @@ html_engine_replace_do (HTMLEngine *e, HTMLReplaceQueryAnswer answer)
 		replace (e);
 		while (html_engine_search_next (e))
 			replace (e);
-		html_undo_level_end (e->undo);
+		html_undo_level_end (e->undo, e);
 	case RQA_Cancel:
 		html_replace_destroy (e->replace_info);
 		e->replace_info = NULL;
@@ -6057,7 +6067,7 @@ html_engine_replace_do (HTMLEngine *e, HTMLReplaceQueryAnswer answer)
 	case RQA_Replace:
 		html_undo_level_begin (e->undo, "Replace", "Revert replace");
 		replace (e);
-		html_undo_level_end (e->undo);
+		html_undo_level_end (e->undo, e);
 	case RQA_Next:
 		finished = !html_engine_search_next (e);
 		if (finished)
@@ -6990,3 +7000,12 @@ html_engine_refresh_fonts (HTMLEngine *e)
 		html_engine_schedule_update (e);
 	}
 }
+
+void
+html_engine_emit_undo_changed (HTMLEngine *e)
+{
+	g_return_if_fail (e != NULL);
+	g_return_if_fail (HTML_IS_ENGINE (e));
+
+	g_signal_emit (e, signals [UNDO_CHANGED], 0);
+}
diff --git a/gtkhtml/htmlengine.h b/gtkhtml/htmlengine.h
index 02a90bb..ee97df5 100644
--- a/gtkhtml/htmlengine.h
+++ b/gtkhtml/htmlengine.h
@@ -282,6 +282,7 @@ struct _HTMLEngineClass {
         void (* redirect) (HTMLEngine *engine, const gchar *url, gint delay);
         void (* submit) (HTMLEngine *engine, const gchar *method, const gchar *action, const gchar *encoding);
 	gboolean (* object_requested) (HTMLEngine *engine, GtkHTMLEmbedded *);
+	void (* undo_changed) (HTMLEngine *engine);
 };
 
 
@@ -498,4 +499,6 @@ void html_engine_opened_streams_set (HTMLEngine *e, gint value);
 
 void html_engine_refresh_fonts (HTMLEngine *e);
 
+void html_engine_emit_undo_changed (HTMLEngine *e);
+
 #endif /* _HTMLENGINE_H_ */
diff --git a/gtkhtml/htmltext.c b/gtkhtml/htmltext.c
index 1ca512f..aa50389 100644
--- a/gtkhtml/htmltext.c
+++ b/gtkhtml/htmltext.c
@@ -3245,7 +3245,7 @@ html_text_magic_link (HTMLText *text, HTMLEngine *engine, guint offset)
 		}
 	}
 
-	html_undo_level_end (engine->undo);
+	html_undo_level_end (engine->undo, engine);
 	html_cursor_jump_to_position_no_spell (engine->cursor, engine, saved_position);
 
 	return rv;
diff --git a/gtkhtml/htmlundo.c b/gtkhtml/htmlundo.c
index 92973ba..7f9180e 100644
--- a/gtkhtml/htmlundo.c
+++ b/gtkhtml/htmlundo.c
@@ -53,7 +53,7 @@ static void html_undo_debug (HTMLUndo *undo);
 #define DEBUG(x)
 #endif
 
-static void add_used_and_redo_to_undo (HTMLUndo *undo);
+static void add_used_and_redo_to_undo (HTMLUndo *undo, HTMLEngine *engine);
 static void level_destroy (HTMLUndoData *data);
 
 inline static void
@@ -164,6 +164,8 @@ action_do_and_destroy_undo (HTMLEngine *engine, HTMLUndo *undo, HTMLUndoDirectio
 	if (undo->level == 0) {
 		undo->undo_used.stack = g_list_prepend (undo->undo_used.stack, action);
 		undo->step_counter --;
+
+		html_engine_emit_undo_changed (engine);
 	}
 }
 
@@ -249,7 +251,7 @@ html_undo_discard_redo (HTMLUndo *undo)
 }
 
 void
-html_undo_add_undo_action  (HTMLUndo *undo, HTMLUndoAction *action)
+html_undo_add_undo_action  (HTMLUndo *undo, HTMLEngine *engine, HTMLUndoAction *action)
 {
 	g_return_if_fail (undo != NULL);
 	g_return_if_fail (action != NULL);
@@ -259,7 +261,7 @@ html_undo_add_undo_action  (HTMLUndo *undo, HTMLUndoAction *action)
 
 	if (undo->level == 0) {
 		if (undo->in_redo == 0 && undo->redo.size > 0)
-			add_used_and_redo_to_undo (undo);
+			add_used_and_redo_to_undo (undo, engine);
 
 		if (undo->undo.size >= HTML_UNDO_LIMIT) {
 			HTMLUndoAction *last_action;
@@ -277,6 +279,8 @@ html_undo_add_undo_action  (HTMLUndo *undo, HTMLUndoAction *action)
 		}
 
 		undo->step_counter ++;
+
+		html_engine_emit_undo_changed (engine);
 	}
 
 	undo->undo.stack = g_list_prepend (undo->undo.stack, action);
@@ -305,13 +309,13 @@ html_undo_add_redo_action  (HTMLUndo *undo,
 }
 
 void
-html_undo_add_action  (HTMLUndo *undo, HTMLUndoAction *action, HTMLUndoDirection dir)
+html_undo_add_action  (HTMLUndo *undo, HTMLEngine *engine, HTMLUndoAction *action, HTMLUndoDirection dir)
 {
 	if (undo->freeze_count > 0)
 		return;
 
 	if (dir == HTML_UNDO_UNDO)
-		html_undo_add_undo_action (undo, action);
+		html_undo_add_undo_action (undo, engine, action);
 	else
 		html_undo_add_redo_action (undo, action);
 }
@@ -461,7 +465,7 @@ redo_level_end (HTMLUndo *undo)
 }
 
 void
-html_undo_level_end (HTMLUndo *undo)
+html_undo_level_end (HTMLUndo *undo, HTMLEngine *engine)
 {
 	HTMLUndoLevel *level;
 	HTMLUndoStack  save_undo;
@@ -495,7 +499,7 @@ html_undo_level_end (HTMLUndo *undo)
 #ifdef UNDO_DEBUG
 		action->is_level = TRUE;
 #endif
-		html_undo_add_undo_action (undo, action);
+		html_undo_add_undo_action (undo, engine, action);
 	} else
 		html_undo_data_unref (HTML_UNDO_DATA (level));
 
@@ -544,7 +548,7 @@ undo_step_action (HTMLEngine *e, HTMLUndoData *data, HTMLUndoDirection dir, guin
 	if (dir == HTML_UNDO_UNDO)
 		redo_level_end (undo);
 	else
-		html_undo_level_end (undo);
+		html_undo_level_end (undo, e);
 }
 
 void
@@ -584,7 +588,7 @@ html_undo_direction_reverse (HTMLUndoDirection dir)
 }
 
 static void
-add_used_and_redo_to_undo (HTMLUndo *undo)
+add_used_and_redo_to_undo (HTMLUndo *undo, HTMLEngine *engine)
 {
 	GList *stack;
 	GList *cur;
@@ -595,12 +599,12 @@ add_used_and_redo_to_undo (HTMLUndo *undo)
 
 	/* add undo_used */
 	for (cur = undo->undo_used.stack; cur; cur = cur->next)
-		html_undo_add_undo_action (undo, HTML_UNDO_ACTION (cur->data));
+		html_undo_add_undo_action (undo, engine, HTML_UNDO_ACTION (cur->data));
 	g_list_free (undo->undo_used.stack);
 	undo->undo_used.stack = NULL;
 
 	for (cur = stack; cur; cur = cur->next)
-		html_undo_add_undo_action (undo, HTML_UNDO_ACTION (cur->data));
+		html_undo_add_undo_action (undo, engine, HTML_UNDO_ACTION (cur->data));
 	g_list_free (stack);
 
 #ifdef UNDO_DEBUG
diff --git a/gtkhtml/htmlundo.h b/gtkhtml/htmlundo.h
index 7f5c927..c0dce18 100644
--- a/gtkhtml/htmlundo.h
+++ b/gtkhtml/htmlundo.h
@@ -41,10 +41,12 @@ void      html_undo_do_redo          (HTMLUndo          *undo,
 				      HTMLEngine        *engine);
 void      html_undo_discard_redo     (HTMLUndo          *undo);
 void      html_undo_add_undo_action  (HTMLUndo          *undo,
+				      HTMLEngine	*engine,
 				      HTMLUndoAction    *action);
 void      html_undo_add_redo_action  (HTMLUndo          *undo,
 				      HTMLUndoAction    *action);
 void      html_undo_add_action       (HTMLUndo          *undo,
+				      HTMLEngine	*engine,
 				      HTMLUndoAction    *action,
 				      HTMLUndoDirection  dir);
 gboolean  html_undo_has_undo_steps   (HTMLUndo          *undo);
@@ -52,7 +54,8 @@ void      html_undo_reset            (HTMLUndo          *undo);
 void      html_undo_level_begin      (HTMLUndo          *undo,
 				      const gchar       *undo_description,
 				      const gchar       *redo_description);
-void      html_undo_level_end        (HTMLUndo          *undo);
+void      html_undo_level_end        (HTMLUndo          *undo,
+				      HTMLEngine	*engine);
 gint      html_undo_get_step_count   (HTMLUndo          *undo);
 void      html_undo_freeze           (HTMLUndo          *undo);
 void      html_undo_thaw             (HTMLUndo          *undo);
