Index: components/editor/gtkhtml-spell-checker.h
===================================================================
--- components/editor/gtkhtml-spell-checker.h	(revision 0)
+++ components/editor/gtkhtml-spell-checker.h	(revision 0)
@@ -0,0 +1,108 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-checker.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Based on Marco Barisione's GSpellChecker. */
+
+#ifndef GTKHTML_SPELL_CHECKER_H
+#define GTKHTML_SPELL_CHECKER_H
+
+#include <gtkhtml-editor-common.h>
+#include <gtkhtml-spell-language.h>
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_SPELL_CHECKER \
+	(gtkhtml_spell_checker_get_type ())
+#define GTKHTML_SPELL_CHECKER(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_SPELL_CHECKER, GtkhtmlSpellChecker))
+#define GTKHTML_SPELL_CHECKER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_SPELL_CHECKER, GtkhtmlSpellCheckerClass))
+#define GTKHTML_IS_SPELL_CHECKER(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_SPELL_CHECKER))
+#define GTKHTML_IS_SPELL_CHECKER_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_SPELL_CHECKER))
+#define GTKHTML_SPELL_CHECKER_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_SPELL_CHECKER, GtkhtmlSpellCheckerClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlSpellChecker GtkhtmlSpellChecker;
+typedef struct _GtkhtmlSpellCheckerClass GtkhtmlSpellCheckerClass;
+typedef struct _GtkhtmlSpellCheckerPrivate GtkhtmlSpellCheckerPrivate;
+
+struct _GtkhtmlSpellChecker {
+	GObject parent;
+	GtkhtmlSpellCheckerPrivate *priv;
+};
+
+struct _GtkhtmlSpellCheckerClass {
+	GObjectClass parent;
+
+	void	(*added)		(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gint length);
+	void	(*added_to_session)	(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gint length);
+	void	(*session_cleared)	(GtkhtmlSpellChecker *checker);
+};
+
+GType		gtkhtml_spell_checker_get_type	(void);
+GtkhtmlSpellChecker *
+		gtkhtml_spell_checker_new
+					(const GtkhtmlSpellLanguage *language);
+const GtkhtmlSpellLanguage *
+		gtkhtml_spell_checker_get_language
+					(GtkhtmlSpellChecker *checker);
+gboolean	gtkhtml_spell_checker_check_word
+					(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gssize length);
+GList *		gtkhtml_spell_checker_get_suggestions
+					(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gssize length);
+void		gtkhtml_spell_checker_store_replacement
+					(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gssize word_length,
+					 const gchar *replacement,
+					 gssize replacement_length);
+void		gtkhtml_spell_checker_add_word
+					(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gssize length);
+void		gtkhtml_spell_checker_add_word_to_session
+					(GtkhtmlSpellChecker *checker,
+					 const gchar *word,
+					 gssize length);
+void		gtkhtml_spell_checker_clear_session
+					(GtkhtmlSpellChecker *checker);
+gint		gtkhtml_spell_checker_compare
+					(GtkhtmlSpellChecker *checker_a,
+					 GtkhtmlSpellChecker *checker_b);
+
+G_END_DECLS
+
+#endif /* GTKHTML_SPELL_CHECKER_H */
Index: components/editor/gtkhtml-editor-signals.h
===================================================================
--- components/editor/gtkhtml-editor-signals.h	(revision 0)
+++ components/editor/gtkhtml-editor-signals.h	(revision 0)
@@ -0,0 +1,119 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-signals.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* This file is for widget signal handlers, primarily for property dialogs.
+ * Most of these handlers will be auto-connected by libglade.  GtkAction
+ * callbacks belong in gtkhtml-editor-actions.c. */
+
+#ifndef GTKHTML_EDITOR_SIGNALS_H
+#define GTKHTML_EDITOR_SIGNALS_H
+
+#include "gtkhtml-editor-common.h"
+
+G_BEGIN_DECLS
+
+/*****************************************************************************
+ * Find Window
+ *****************************************************************************/
+
+void	gtkhtml_editor_find_backwards_toggled_cb
+						(GtkWidget *window,
+						 GtkToggleButton *button);
+void	gtkhtml_editor_find_case_sensitive_toggled_cb
+						(GtkWidget *window,
+						 GtkToggleButton *button);
+void	gtkhtml_editor_find_entry_activate_cb	(GtkWidget *window,
+						 GtkEntry *entry);
+void	gtkhtml_editor_find_entry_changed_cb	(GtkWidget *window,
+						 GtkEntry *entry);
+void	gtkhtml_editor_find_regular_expression_toggled_cb
+						(GtkWidget *window,
+						 GtkToggleButton *button);
+
+/*****************************************************************************
+ * Insert Link Window
+ *****************************************************************************/
+
+void	gtkhtml_editor_insert_link_description_changed_cb
+						(GtkWidget *window);
+void	gtkhtml_editor_insert_link_url_changed_cb
+						(GtkWidget *window);
+void	gtkhtml_editor_insert_link_show_window_cb
+						(GtkWidget *window);
+
+/*****************************************************************************
+ * Insert Rule Window
+ *****************************************************************************/
+
+void	gtkhtml_editor_insert_rule_alignment_changed_cb
+						(GtkWidget *window,
+						 GtkComboBox *combo_box);
+void	gtkhtml_editor_insert_rule_shaded_toggled_cb
+						(GtkWidget *window,
+						 GtkToggleButton *button);
+void	gtkhtml_editor_insert_rule_size_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_rule_show_window_cb
+						(GtkWidget *window);
+void	gtkhtml_editor_insert_rule_width_changed_cb
+						(GtkWidget *window);
+
+/*****************************************************************************
+ * Insert Table Window
+ *****************************************************************************/
+
+void	gtkhtml_editor_insert_table_alignment_changed_cb
+						(GtkWidget *window,
+						 GtkComboBox *combo_box);
+void	gtkhtml_editor_insert_table_border_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_table_cols_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_table_image_changed_cb
+						(GtkWidget *window,
+						 GtkFileChooser *file_chooser);
+void	gtkhtml_editor_insert_table_padding_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_table_spacing_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_table_rows_changed_cb
+						(GtkWidget *window,
+						 GtkSpinButton *button);
+void	gtkhtml_editor_insert_table_show_window_cb
+						(GtkWidget *window);
+void	gtkhtml_editor_insert_table_width_changed_cb
+						(GtkWidget *window);
+
+/*****************************************************************************
+ * Replace Confirmation Window
+ *****************************************************************************/
+
+gboolean gtkhtml_editor_replace_confirmation_delete_event_cb
+						(GtkWidget *window,
+						 GdkEvent *event);
+
+G_END_DECLS
+
+#endif /* GTKHTML_EDITOR_SIGNALS_H */
Index: components/editor/gtkhtml-color-state.c
===================================================================
--- components/editor/gtkhtml-color-state.c	(revision 0)
+++ components/editor/gtkhtml-color-state.c	(revision 0)
@@ -0,0 +1,424 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-state.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-color-state.h"
+
+#include <glib/gi18n-lib.h>
+
+#define GTKHTML_COLOR_STATE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_COLOR_STATE, GtkhtmlColorStatePrivate))
+
+enum {
+	PROP_0,
+	PROP_CURRENT_COLOR,
+	PROP_DEFAULT_COLOR,
+	PROP_DEFAULT_LABEL,
+	PROP_PALETTE
+};
+
+enum {
+	PALETTE_CHANGED,
+	LAST_SIGNAL
+};
+
+struct _GtkhtmlColorStatePrivate {
+	GdkColor *current_color;
+	GdkColor *default_color;
+	gchar *default_label;
+	GtkhtmlColorPalette *palette;
+	gulong palette_handler_id;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+static GdkColor black = { 0, 0, 0, 0 };
+
+static void
+color_state_palette_changed_cb (GtkhtmlColorState *state)
+{
+	/* Propagate the signal. */
+	g_signal_emit (state, signals[PALETTE_CHANGED], 0);
+}
+
+static void
+color_state_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_COLOR:
+			gtkhtml_color_state_set_current_color (
+				GTKHTML_COLOR_STATE (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_DEFAULT_COLOR:
+			gtkhtml_color_state_set_default_color (
+				GTKHTML_COLOR_STATE (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_DEFAULT_LABEL:
+			gtkhtml_color_state_set_default_label (
+				GTKHTML_COLOR_STATE (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_PALETTE:
+			gtkhtml_color_state_set_palette (
+				GTKHTML_COLOR_STATE (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_state_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
+{
+	GdkColor color;
+
+	switch (property_id) {
+		case PROP_CURRENT_COLOR:
+			gtkhtml_color_state_get_current_color (
+				GTKHTML_COLOR_STATE (object), &color);
+			g_value_set_boxed (value, &color);
+			return;
+
+		case PROP_DEFAULT_COLOR:
+			gtkhtml_color_state_get_default_color (
+				GTKHTML_COLOR_STATE (object), &color);
+			g_value_set_boxed (value, &color);
+			return;
+
+		case PROP_DEFAULT_LABEL:
+			g_value_set_string (
+				value, gtkhtml_color_state_get_default_label (
+				GTKHTML_COLOR_STATE (object)));
+			return;
+
+		case PROP_PALETTE:
+			g_value_set_object (
+				value, gtkhtml_color_state_get_palette (
+				GTKHTML_COLOR_STATE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_state_dispose (GObject *object)
+{
+	GtkhtmlColorStatePrivate *priv;
+
+	priv = GTKHTML_COLOR_STATE_GET_PRIVATE (object);
+
+	if (priv->palette != NULL) {
+		g_signal_handler_disconnect (
+			priv->palette,
+			priv->palette_handler_id);
+		g_object_unref (priv->palette);
+		priv->palette = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+color_state_finalize (GObject *object)
+{
+	GtkhtmlColorStatePrivate *priv;
+
+	priv = GTKHTML_COLOR_STATE_GET_PRIVATE (object);
+
+	if (priv->current_color != NULL)
+		gdk_color_free (priv->current_color);
+
+	if (priv->default_color != NULL)
+		gdk_color_free (priv->default_color);
+
+	g_free (priv->default_label);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+color_state_class_init (GtkhtmlColorStateClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlColorStatePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = color_state_set_property;
+	object_class->get_property = color_state_get_property;
+	object_class->dispose = color_state_dispose;
+	object_class->finalize = color_state_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_COLOR,
+		g_param_spec_boxed (
+			"current-color",
+			_("Current color"),
+			_("The current color"),
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_COLOR,
+		g_param_spec_boxed (
+			"default-color",
+			_("Default color"),
+			_("The default color"),
+			GDK_TYPE_COLOR,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_LABEL,
+		g_param_spec_string (
+			"default-label",
+			_("Default label"),
+			_("Description of the default color"),
+			_("Default"),
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PALETTE,
+		g_param_spec_object (
+			"palette",
+			_("Color palette"),
+			_("Custom color palette"),
+			GTKHTML_TYPE_COLOR_PALETTE,
+			G_PARAM_READWRITE));
+
+	signals[PALETTE_CHANGED] = g_signal_new (
+		"palette-changed",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+color_state_init (GtkhtmlColorState *state)
+{
+	GtkhtmlColorPalette *palette;
+
+	state->priv = GTKHTML_COLOR_STATE_GET_PRIVATE (state);
+
+	palette = gtkhtml_color_palette_new ();
+	gtkhtml_color_state_set_palette (state, palette);
+	g_object_unref (palette);
+}
+
+GType
+gtkhtml_color_state_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlColorStateClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) color_state_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlColorState),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) color_state_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "GtkhtmlColorState", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkhtmlColorState *
+gtkhtml_color_state_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_COLOR_STATE, NULL);
+}
+
+GtkhtmlColorState *
+gtkhtml_color_state_new_default (GdkColor *default_color,
+                                 const gchar *default_label)
+{
+	g_return_val_if_fail (default_color != NULL, NULL);
+	g_return_val_if_fail (default_label != NULL, NULL);
+
+	return g_object_new (
+		GTKHTML_TYPE_COLOR_STATE,
+		"default-color", default_color,
+		"default-label", default_label);
+}
+
+gboolean
+gtkhtml_color_state_get_current_color (GtkhtmlColorState *state,
+                                       GdkColor *color)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_STATE (state), FALSE);
+	g_return_val_if_fail (color != NULL, FALSE);
+
+	if (state->priv->current_color != NULL) {
+		color->red   = state->priv->current_color->red;
+		color->green = state->priv->current_color->green;
+		color->blue  = state->priv->current_color->blue;
+		return TRUE;
+	} else {
+		color->red   = state->priv->default_color->red;
+		color->green = state->priv->default_color->green;
+		color->blue  = state->priv->default_color->blue;
+		return FALSE;
+	}
+}
+
+void
+gtkhtml_color_state_set_current_color (GtkhtmlColorState *state,
+                                       const GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+
+	if (state->priv->current_color != NULL) {
+		gdk_color_free (state->priv->current_color);
+		state->priv->current_color = NULL;
+	}
+
+	if (color != NULL)
+		state->priv->current_color = gdk_color_copy (color);
+
+	g_object_notify (G_OBJECT (state), "current-color");
+}
+
+void
+gtkhtml_color_state_get_default_color (GtkhtmlColorState *state,
+                                       GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+	g_return_if_fail (color != NULL);
+
+	color->red   = state->priv->default_color->red;
+	color->green = state->priv->default_color->green;
+	color->blue  = state->priv->default_color->blue;
+}
+
+void
+gtkhtml_color_state_set_default_color (GtkhtmlColorState *state,
+                                       const GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+
+	if (state->priv->default_color != NULL) {
+		gdk_color_free (state->priv->default_color);
+		state->priv->default_color = NULL;
+	}
+
+	/* Default to black. */
+	if (color == NULL)
+		color = &black;
+
+	state->priv->default_color = gdk_color_copy (color);
+
+	g_object_notify (G_OBJECT (state), "default-color");
+
+	/* If the current color is deferring to the default color, then
+	 * changing the default color also changes the current color. */
+	if (state->priv->current_color == NULL)
+		g_object_notify (G_OBJECT (state), "current-color");
+}
+
+const gchar *
+gtkhtml_color_state_get_default_label (GtkhtmlColorState *state)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_STATE (state), NULL);
+
+	return state->priv->default_label;
+}
+
+void
+gtkhtml_color_state_set_default_label (GtkhtmlColorState *state,
+                                       const gchar *text)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+	g_return_if_fail (text != NULL);
+
+	g_free (state->priv->default_label);
+	state->priv->default_label = g_strdup (text);
+
+	g_object_notify (G_OBJECT (state), "default-label");
+}
+
+GtkhtmlColorPalette *
+gtkhtml_color_state_get_palette (GtkhtmlColorState *state)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_STATE (state), NULL);
+
+	return state->priv->palette;
+}
+
+void
+gtkhtml_color_state_set_palette (GtkhtmlColorState *state,
+                                 GtkhtmlColorPalette *palette)
+{
+	gulong handler_id;
+
+	g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+
+	if (palette == NULL)
+		palette = gtkhtml_color_palette_new ();
+	else
+		g_return_if_fail (GTKHTML_IS_COLOR_PALETTE (palette));
+
+	if (state->priv->palette != NULL) {
+		g_signal_handler_disconnect (
+			state->priv->palette,
+			state->priv->palette_handler_id);
+		g_object_unref (state->priv->palette);
+	}
+
+	handler_id = g_signal_connect_swapped (
+		palette, "changed",
+		G_CALLBACK (color_state_palette_changed_cb), state);
+
+	state->priv->palette = g_object_ref (palette);
+	state->priv->palette_handler_id = handler_id;
+
+	g_object_notify (G_OBJECT (state), "palette");
+}
Index: components/editor/gtkhtml-spell-marshal.list
===================================================================
--- components/editor/gtkhtml-spell-marshal.list	(revision 0)
+++ components/editor/gtkhtml-spell-marshal.list	(revision 0)
@@ -0,0 +1 @@
+VOID:STRING,INT
Index: components/editor/gtkhtml-spell-language.c
===================================================================
--- components/editor/gtkhtml-spell-language.c	(revision 0)
+++ components/editor/gtkhtml-spell-language.c	(revision 0)
@@ -0,0 +1,403 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-language.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-spell-language.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <enchant/enchant.h>
+
+#define ISO_639_DOMAIN	"iso_639"
+#define ISO_3166_DOMAIN	"iso_3166"
+
+struct _GtkhtmlSpellLanguage {
+	gchar *code;
+	gchar *name;
+	gchar *ckey;
+};
+
+static GHashTable *iso_639_table = NULL;
+static GHashTable *iso_3166_table = NULL;
+
+#ifdef HAVE_ISO_CODES
+
+#define ISOCODESLOCALEDIR ISO_CODES_PREFIX "/share/locale"
+
+static void
+iso_639_start_element (GMarkupParseContext *context,
+                       const gchar *element_name,
+                       const gchar **attribute_names,
+                       const gchar **attribute_values,
+                       gpointer data,
+                       GError **error)
+{
+	GHashTable *hash_table = data;
+	const gchar *iso_639_1_code = NULL;
+	const gchar *iso_639_2_code = NULL;
+	const gchar *name = NULL;
+	const gchar *code = NULL;
+	gint ii;
+
+	if (strcmp (element_name, "iso_639_entry") != 0)
+		return;
+
+	for (ii = 0; attribute_names[ii] != NULL; ii++) {
+		if (strcmp (attribute_names[ii], "name") == 0)
+			name = attribute_values[ii];
+		else if (strcmp (attribute_names[ii], "iso_639_1_code") == 0)
+			iso_639_1_code = attribute_values[ii];
+		else if (strcmp (attribute_names[ii], "iso_639_2T_code") == 0)
+			iso_639_2_code = attribute_values[ii];
+	}
+
+	code = (iso_639_1_code != NULL) ? iso_639_1_code : iso_639_2_code;
+
+	if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+		g_hash_table_insert (
+			hash_table, g_strdup (code),
+			g_strdup (dgettext (ISO_639_DOMAIN, name)));
+}
+
+static void
+iso_3166_start_element (GMarkupParseContext *context,
+                        const gchar *element_name,
+                        const gchar **attribute_names,
+                        const gchar **attribute_values,
+                        gpointer data,
+                        GError **error)
+{
+	GHashTable *hash_table = data;
+	const gchar *name = NULL;
+	const gchar *code = NULL;
+	gint ii;
+
+	if (strcmp (element_name, "iso_3166_entry") != 0)
+		return;
+
+	for (ii = 0; attribute_names[ii] != NULL; ii++) {
+		if (strcmp (attribute_names[ii], "name") == 0)
+			name = attribute_values[ii];
+		else if (strcmp (attribute_names[ii], "alpha_2_code") == 0)
+			code = attribute_values[ii];
+	}
+
+	if (code != NULL && *code != '\0' && name != NULL && *name != '\0')
+		g_hash_table_insert (
+			hash_table, g_ascii_strdown (code, -1),
+			g_strdup (dgettext (ISO_3166_DOMAIN, name)));
+}
+
+static GMarkupParser iso_639_parser = {
+	iso_639_start_element,
+	NULL, NULL, NULL, NULL
+};
+
+static GMarkupParser iso_3166_parser = {
+	iso_3166_start_element,
+	NULL, NULL, NULL, NULL
+};
+
+static void
+iso_codes_parse (const GMarkupParser *parser,
+                 const gchar *basename,
+		 GHashTable *hash_table)
+{
+	GMappedFile *mapped_file;
+	gchar *filename;
+	GError *error = NULL;
+
+	filename = g_build_filename (
+		ISO_CODES_PREFIX, "share", "xml",
+		"iso-codes", basename, NULL);
+	mapped_file = g_mapped_file_new (filename, FALSE, &error);
+	g_free (filename);
+
+	if (mapped_file != NULL) {
+		GMarkupParseContext *context;
+		const gchar *contents;
+		gsize length;
+
+		context = g_markup_parse_context_new (
+			parser, 0, hash_table, NULL);
+		contents = g_mapped_file_get_contents (mapped_file);
+		length = g_mapped_file_get_length (mapped_file);
+		g_markup_parse_context_parse (
+			context, contents, length, &error);
+		g_markup_parse_context_free (context);
+		g_mapped_file_free (mapped_file);
+	}
+
+	if (error != NULL) {
+		g_warning ("%s: %s", basename, error->message);
+		g_error_free (error);
+	}
+}
+
+#endif /* HAVE_ISO_CODES */
+
+static void
+spell_language_dict_describe_cb (const gchar * const language_code,
+                                 const gchar * const provider_name,
+                                 const gchar * const provider_desc,
+                                 const gchar * const provider_file,
+                                 GTree *tree)
+{
+	const gchar *iso_639_name;
+	const gchar *iso_3166_name;
+	gchar *language_name;
+	gchar *lowercase;
+	gchar **tokens;
+
+	/* Split language code into lowercase tokens. */
+	lowercase = g_ascii_strdown (language_code, -1);
+	tokens = g_strsplit (lowercase, "_", -1);
+	g_free (lowercase);
+
+	g_return_if_fail (tokens != NULL);
+
+	iso_639_name = g_hash_table_lookup (iso_639_table, tokens[0]);
+
+	if (iso_639_name == NULL) {
+		/* Translators: The text before the "|" is context to help
+		 * you decide on the correct translation. You MUST OMIT IT
+		 * in the translated string. */
+		language_name = g_strdup_printf (
+			Q_("language|Unknown (%s)"), language_code);
+		goto exit;
+	}
+
+	if (g_strv_length (tokens) < 2) {
+		language_name = g_strdup (iso_639_name);
+		goto exit;
+	}
+
+	iso_3166_name = g_hash_table_lookup (iso_3166_table, tokens[1]);
+
+	if (iso_3166_name != NULL)
+		/* Translators: The text before the "|" is context to help
+		 * you decide on the correct translation. You MUST OMIT IT
+		 * in the translated string. 
+		 * Translators: The first %s is the language name, and the
+		 * second is the locale name. Example: "French (France)" */
+		language_name = g_strdup_printf (
+			Q_("language|%s (%s)"), iso_639_name, iso_3166_name);
+	else
+		/* Translators: The text before the "|" is context to help
+		 * you decide on the correct translation. You MUST OMIT IT
+		 * in the translated string. 
+		 * Translators: The first %s is the language name, and the
+		 * second is the locale name. Example: "French (France)" */
+		language_name = g_strdup_printf (
+			Q_("language|%s (%s)"), iso_639_name, tokens[1]);
+
+exit:
+	g_strfreev (tokens);
+
+	g_tree_replace (tree, g_strdup (language_code), language_name);
+}
+
+static gint
+spell_language_compare (const GtkhtmlSpellLanguage *a,
+                        const GtkhtmlSpellLanguage *b)
+{
+	return g_utf8_collate (a->name, b->name);
+}
+
+static const GtkhtmlSpellLanguage *
+spell_language_copy (const GtkhtmlSpellLanguage *language)
+{
+	return language;
+}
+
+static void
+spell_language_free (const GtkhtmlSpellLanguage *language)
+{
+	/* do nothing */
+}
+
+static gboolean
+spell_language_traverse_cb (const gchar *code,
+                            const gchar *name,
+                            GList **available_languages)
+{
+	GtkhtmlSpellLanguage *language;
+
+	language = g_slice_new (GtkhtmlSpellLanguage);
+	language->code = g_strdup (code);
+	language->name = g_strdup (name);
+	language->ckey = g_utf8_collate_key (name, -1);
+
+	*available_languages = g_list_insert_sorted (
+		*available_languages, language,
+		(GCompareFunc) spell_language_compare);
+
+	return FALSE;
+}
+
+GType
+gtkhtml_spell_language_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0))
+		type = g_boxed_type_register_static (
+			"GtkhtmlSpellLanguage",
+			(GBoxedCopyFunc) spell_language_copy,
+			(GBoxedFreeFunc) spell_language_free);
+
+	return type;
+}
+
+const GList *
+gtkhtml_spell_language_get_available (void)
+{
+	static gboolean initialized = FALSE;
+	static GList *available_languages = NULL;
+	EnchantBroker *broker;
+	GTree *tree;
+
+	if (initialized)
+		return available_languages;
+
+	initialized = TRUE;
+
+#if defined (ENABLE_NLS) && defined (HAVE_ISO_CODES)
+	bindtextdomain (ISO_639_DOMAIN, ISOCODESLOCALEDIR);
+	bind_textdomain_codeset (ISO_639_DOMAIN, "UTF-8");
+
+	bindtextdomain (ISO_3166_DOMAIN, ISOCODESLOCALEDIR);
+	bind_textdomain_codeset (ISO_3166_DOMAIN, "UTF-8");
+#endif
+
+	iso_639_table = g_hash_table_new_full (
+		g_str_hash, g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_free);
+
+	iso_3166_table = g_hash_table_new_full (
+		g_str_hash, g_str_equal,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_free);
+
+#ifdef HAVE_ISO_CODES
+	iso_codes_parse (&iso_639_parser, "iso_639.xml", iso_639_table);
+	iso_codes_parse (&iso_3166_parser, "iso_3166.xml", iso_3166_table);
+#endif
+
+	tree = g_tree_new_full (
+		(GCompareDataFunc) strcmp, NULL,
+		(GDestroyNotify) g_free,
+		(GDestroyNotify) g_free);
+
+	broker = enchant_broker_init ();
+	enchant_broker_list_dicts (
+		broker, (EnchantDictDescribeFn)
+		spell_language_dict_describe_cb, tree);
+	enchant_broker_free (broker);
+
+	g_tree_foreach (
+		tree, (GTraverseFunc)
+		spell_language_traverse_cb,
+		&available_languages);
+
+	g_tree_destroy (tree);
+
+	return available_languages;
+}
+
+static const GtkhtmlSpellLanguage *
+spell_language_pick_default (void)
+{
+	const GtkhtmlSpellLanguage *language = NULL;
+	const gchar * const *language_names;
+	const GList *available_languages;
+	gint ii;
+
+	language_names = g_get_language_names ();
+	available_languages = gtkhtml_spell_language_get_available ();
+
+	for (ii = 0; language == NULL && language_names[ii] != NULL; ii++)
+		language = gtkhtml_spell_language_lookup (language_names[ii]);
+
+	if (language == NULL)
+		language = gtkhtml_spell_language_lookup ("en_US");
+
+	if (language == NULL && available_languages != NULL)
+		language = available_languages->data;
+
+	return language;
+}
+
+const GtkhtmlSpellLanguage *
+gtkhtml_spell_language_lookup (const gchar *language_code)
+{
+	const GtkhtmlSpellLanguage *closest_match = NULL;
+	const GList *available_languages;
+
+	available_languages = gtkhtml_spell_language_get_available ();
+
+	while (available_languages != NULL && language_code != NULL) {
+		GtkhtmlSpellLanguage *language = available_languages->data;
+		const gchar *code = language->code;
+		gsize length = strlen (code);
+
+		if (g_ascii_strcasecmp (language_code, code) == 0)
+			return language;
+
+		if (g_ascii_strncasecmp (language_code, code, length) == 0)
+			closest_match = language;
+
+		available_languages = g_list_next (available_languages);
+	}
+
+	if (closest_match == NULL)
+		closest_match = spell_language_pick_default ();
+
+	return closest_match;
+}
+
+const gchar *
+gtkhtml_spell_language_get_code (const GtkhtmlSpellLanguage *language)
+{
+	g_return_val_if_fail (language != NULL, NULL);
+
+	return language->code;
+}
+
+const gchar *
+gtkhtml_spell_language_get_name (const GtkhtmlSpellLanguage *language)
+{
+	if (language == NULL)
+		/* Translators: The text before the "|" is context to help
+		 * you decide on the correct translation. You MUST OMIT IT
+		 * in the translated string.
+		 * Translators: This refers to the default language used
+		 * by the spell checker. */
+		return Q_("language|Default");
+
+	return language->name;
+}
+
+gint
+gtkhtml_spell_language_compare (const GtkhtmlSpellLanguage *language_a,
+                                const GtkhtmlSpellLanguage *language_b)
+{
+	return strcmp (language_a->ckey, language_b->ckey);
+}
Index: components/editor/gtkhtml-color-state.h
===================================================================
--- components/editor/gtkhtml-color-state.h	(revision 0)
+++ components/editor/gtkhtml-color-state.h	(revision 0)
@@ -0,0 +1,96 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-state.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_COLOR_STATE_H
+#define GTKHTML_COLOR_STATE_H
+
+/* GtkhtmlColorState is for sharing state between multiple GtkhtmlColorCombo
+ * widgets. This makes it easier to manage the same color value from various
+ * points in a user interface. It embeds a GtkhtmlColorPalette so that
+ * multiple color state objects can share a custom color palette. */
+
+#include "gtkhtml-editor-common.h"
+#include "gtkhtml-color-palette.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_COLOR_STATE \
+	(gtkhtml_color_state_get_type ())
+#define GTKHTML_COLOR_STATE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_COLOR_STATE, GtkhtmlColorState))
+#define GTKHTML_COLOR_STATE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_COLOR_STATE, GtkhtmlColorStateClass))
+#define GTKHTML_IS_COLOR_STATE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_COLOR_STATE))
+#define GTKHTML_IS_COLOR_STATE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_COLOR_STATE))
+#define GTKHTML_COLOR_STATE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_COLOR_STATE, GtkhtmlColorStateClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlColorState GtkhtmlColorState;
+typedef struct _GtkhtmlColorStateClass GtkhtmlColorStateClass;
+typedef struct _GtkhtmlColorStatePrivate GtkhtmlColorStatePrivate;
+
+struct _GtkhtmlColorState {
+	GObject parent;
+	GtkhtmlColorStatePrivate *priv;
+};
+
+struct _GtkhtmlColorStateClass {
+	GObjectClass parent_class;
+};
+
+GType		gtkhtml_color_state_get_type	(void);
+GtkhtmlColorState *
+		gtkhtml_color_state_new		(void);
+GtkhtmlColorState *
+		gtkhtml_color_state_new_default	(GdkColor *default_color,
+						 const gchar *default_label);
+gboolean	gtkhtml_color_state_get_current_color
+						(GtkhtmlColorState *state,
+						 GdkColor *color);
+void		gtkhtml_color_state_set_current_color
+						(GtkhtmlColorState *state,
+						 const GdkColor *color);
+void		gtkhtml_color_state_get_default_color
+						(GtkhtmlColorState *state,
+						 GdkColor *color);
+void		gtkhtml_color_state_set_default_color
+						(GtkhtmlColorState *state,
+						 const GdkColor *color);
+const gchar *	gtkhtml_color_state_get_default_label
+						(GtkhtmlColorState *state);
+void		gtkhtml_color_state_set_default_label
+						(GtkhtmlColorState *state,
+						 const gchar *text);
+GtkhtmlColorPalette *
+		gtkhtml_color_state_get_palette	(GtkhtmlColorState *state);
+void		gtkhtml_color_state_set_palette (GtkhtmlColorState *state,
+						 GtkhtmlColorPalette *palette);
+
+G_END_DECLS
+
+#endif /* GTKHTML_COLOR_STATE_H */
Index: components/editor/gtkhtml-spell-language.h
===================================================================
--- components/editor/gtkhtml-spell-language.h	(revision 0)
+++ components/editor/gtkhtml-spell-language.h	(revision 0)
@@ -0,0 +1,51 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-language.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* Based on Marco Barisione's GSpellLanguage. */
+
+#ifndef GTKHTML_SPELL_LANGUAGE_H
+#define GTKHTML_SPELL_LANGUAGE_H
+
+#include <gtkhtml-editor-common.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlSpellLanguage GtkhtmlSpellLanguage;
+
+#define GTKHTML_TYPE_SPELL_LANGUAGE \
+	(gtkhtml_spell_language_get_type ())
+
+GType		gtkhtml_spell_language_get_type		(void);
+const GList *	gtkhtml_spell_language_get_available	(void);
+
+const GtkhtmlSpellLanguage *
+		gtkhtml_spell_language_lookup
+					(const gchar *language_code);
+const gchar *	gtkhtml_spell_language_get_code
+					(const GtkhtmlSpellLanguage *language);
+const gchar *	gtkhtml_spell_language_get_name
+					(const GtkhtmlSpellLanguage *language);
+gint		gtkhtml_spell_language_compare
+					(const GtkhtmlSpellLanguage *language_a,
+					 const GtkhtmlSpellLanguage *language_b);
+
+G_END_DECLS
+
+#endif /* GTKHTML_SPELL_LANGUAGE_H */
Index: components/editor/gtkhtml-color-swatch.c
===================================================================
--- components/editor/gtkhtml-color-swatch.c	(revision 0)
+++ components/editor/gtkhtml-color-swatch.c	(revision 0)
@@ -0,0 +1,306 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-swatch.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-color-swatch.h"
+
+#include <glib/gi18n-lib.h>
+
+#define GTKHTML_COLOR_SWATCH_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_COLOR_SWATCH, GtkhtmlColorSwatchPrivate))
+
+enum {
+	PROP_0,
+	PROP_COLOR,
+	PROP_SHADOW_TYPE
+};
+
+struct _GtkhtmlColorSwatchPrivate {
+	GtkWidget *drawing_area;
+	GtkWidget *frame;
+};
+
+static gpointer parent_class;
+
+static gboolean
+color_swatch_expose_cb (GtkWidget *drawing_area,
+                        GdkEventExpose *event)
+{
+	GdkColor *color;
+	cairo_t *cr;
+
+	if (drawing_area->window == NULL)
+		return FALSE;
+
+	cr = gdk_cairo_create (drawing_area->window);
+
+	color = &drawing_area->style->bg[GTK_STATE_NORMAL];
+	gdk_cairo_set_source_color (cr, color);
+	gdk_cairo_rectangle (cr, &event->area);
+	cairo_fill (cr);
+
+	cairo_destroy (cr);
+
+	return FALSE;
+}
+
+static void
+color_swatch_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_COLOR:
+			gtkhtml_color_swatch_set_color (
+				GTKHTML_COLOR_SWATCH (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_SHADOW_TYPE:
+			gtkhtml_color_swatch_set_shadow_type (
+				GTKHTML_COLOR_SWATCH (object),
+				g_value_get_enum (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_swatch_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	GdkColor color;
+
+	switch (property_id) {
+		case PROP_COLOR:
+			gtkhtml_color_swatch_get_color (
+				GTKHTML_COLOR_SWATCH (object), &color);
+			g_value_set_boxed (value, &color);
+			return;
+
+		case PROP_SHADOW_TYPE:
+			g_value_set_enum (
+				value, gtkhtml_color_swatch_get_shadow_type (
+				GTKHTML_COLOR_SWATCH (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_swatch_dispose (GObject *object)
+{
+	GtkhtmlColorSwatch *swatch = GTKHTML_COLOR_SWATCH (object);
+
+	if (swatch->priv->drawing_area != NULL) {
+		g_object_unref (swatch->priv->drawing_area);
+		swatch->priv->drawing_area = NULL;
+	}
+
+	if (swatch->priv->frame != NULL) {
+		g_object_unref (swatch->priv->frame);
+		swatch->priv->frame = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+color_swatch_size_request (GtkWidget *widget,
+                           GtkRequisition *requisition)
+{
+	GtkhtmlColorSwatchPrivate *priv;
+
+	priv = GTKHTML_COLOR_SWATCH_GET_PRIVATE (widget);
+
+	gtk_widget_size_request (priv->frame, requisition);
+}
+
+static void
+color_swatch_size_allocate (GtkWidget *widget,
+                            GtkAllocation *allocation)
+{
+	GtkhtmlColorSwatchPrivate *priv;
+
+	priv = GTKHTML_COLOR_SWATCH_GET_PRIVATE (widget);
+
+	widget->allocation = *allocation;
+	gtk_widget_size_allocate (priv->frame, allocation);
+}
+
+static void
+color_swatch_class_init (GtkhtmlColorSwatchClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlColorSwatchPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = color_swatch_set_property;
+	object_class->get_property = color_swatch_get_property;
+	object_class->dispose = color_swatch_dispose;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->size_request = color_swatch_size_request;
+	widget_class->size_allocate = color_swatch_size_allocate;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_COLOR,
+		g_param_spec_boxed (
+			"color",
+			_("Color"),
+			_("The current color"),
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHADOW_TYPE,
+		g_param_spec_enum (
+			"shadow-type",
+			_("Frame Shadow"),
+			_("Appearance of the frame border"),
+			GTK_TYPE_SHADOW_TYPE,
+			GTK_SHADOW_ETCHED_IN,
+			G_PARAM_READWRITE));
+}
+
+static void
+color_swatch_init (GtkhtmlColorSwatch *swatch)
+{
+	GtkWidget *container;
+	GtkWidget *widget;
+
+	swatch->priv = GTKHTML_COLOR_SWATCH_GET_PRIVATE (swatch);
+
+	widget = gtk_frame_new (NULL);
+	gtk_container_add (GTK_CONTAINER (swatch), widget);
+	swatch->priv->frame = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_drawing_area_new ();
+	gtk_widget_set_size_request (widget, 16, 16);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	swatch->priv->drawing_area = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	g_signal_connect (
+		widget, "expose-event",
+		G_CALLBACK (color_swatch_expose_cb), swatch);
+}
+
+GType
+gtkhtml_color_swatch_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlColorSwatchClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) color_swatch_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlColorSwatch),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) color_swatch_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_BIN, "GtkhtmlColorSwatch", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+gtkhtml_color_swatch_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_COLOR_SWATCH, NULL);
+}
+
+void
+gtkhtml_color_swatch_get_color (GtkhtmlColorSwatch *swatch,
+                                GdkColor *color)
+{
+	GtkWidget *drawing_area;
+
+	g_return_if_fail (GTKHTML_IS_COLOR_SWATCH (swatch));
+	g_return_if_fail (color != NULL);
+
+	drawing_area = swatch->priv->drawing_area;
+	color->red   = drawing_area->style->bg[GTK_STATE_NORMAL].red;
+	color->green = drawing_area->style->bg[GTK_STATE_NORMAL].green;
+	color->blue  = drawing_area->style->bg[GTK_STATE_NORMAL].blue;
+}
+
+void
+gtkhtml_color_swatch_set_color (GtkhtmlColorSwatch *swatch,
+                                const GdkColor *color)
+{
+	GtkWidget *drawing_area;
+
+	g_return_if_fail (GTKHTML_IS_COLOR_SWATCH (swatch));
+	g_return_if_fail (color != NULL);
+
+	drawing_area = swatch->priv->drawing_area;
+	gtk_widget_modify_bg (drawing_area, GTK_STATE_NORMAL, color);
+
+	g_object_notify (G_OBJECT (swatch), "color");
+}
+
+GtkShadowType
+gtkhtml_color_swatch_get_shadow_type (GtkhtmlColorSwatch *swatch)
+{
+	GtkFrame *frame;
+
+	g_return_val_if_fail (GTKHTML_IS_COLOR_SWATCH (swatch), 0);
+
+	frame = GTK_FRAME (swatch->priv->frame);
+
+	return gtk_frame_get_shadow_type (frame);
+}
+
+void
+gtkhtml_color_swatch_set_shadow_type (GtkhtmlColorSwatch *swatch,
+                                      GtkShadowType shadow_type)
+{
+	GtkFrame *frame;
+
+	g_return_if_fail (GTKHTML_IS_COLOR_SWATCH (swatch));
+
+	frame = GTK_FRAME (swatch->priv->frame);
+	gtk_frame_set_shadow_type (frame, shadow_type);
+
+	g_object_notify (G_OBJECT (swatch), "shadow-type");
+}
Index: components/editor/gtkhtml-color-palette.c
===================================================================
--- components/editor/gtkhtml-color-palette.c	(revision 0)
+++ components/editor/gtkhtml-color-palette.c	(revision 0)
@@ -0,0 +1,164 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-palette.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-color-palette.h"
+
+/* XXX GtkhtmlColorPalette has a minimal API specifically designed for
+ *     use with GtkhtmlColorCombo, but there's plenty of room to grow if
+ *     this proves useful elsewhere. */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+
+#define GTKHTML_COLOR_PALETTE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_COLOR_PALETTE, GtkhtmlColorPalettePrivate))
+
+enum {
+	CHANGED,
+	LAST_SIGNAL
+};
+
+struct _GtkhtmlColorPalettePrivate {
+	GHashTable *index;
+	GSList *list;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+color_palette_finalize (GObject *object)
+{
+	GtkhtmlColorPalettePrivate *priv;
+
+	priv = GTKHTML_COLOR_PALETTE_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->index);
+	g_slist_free (priv->list);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+color_palette_class_init (GtkhtmlColorPaletteClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlColorPalettePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->finalize = color_palette_finalize;
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+color_palette_init (GtkhtmlColorPalette *palette)
+{
+	GHashTable *index;
+
+	index = g_hash_table_new_full (
+		(GHashFunc) gdk_color_hash,
+		(GEqualFunc) gdk_color_equal,
+		(GDestroyNotify) gdk_color_free,
+		(GDestroyNotify) NULL);
+
+	palette->priv = GTKHTML_COLOR_PALETTE_GET_PRIVATE (palette);
+	palette->priv->index = index;
+}
+
+GType
+gtkhtml_color_palette_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlColorPaletteClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) color_palette_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlColorPalette),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) color_palette_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "GtkhtmlColorPalette", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkhtmlColorPalette *
+gtkhtml_color_palette_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_COLOR_PALETTE, NULL);
+}
+
+void
+gtkhtml_color_palette_add_color (GtkhtmlColorPalette *palette,
+                                 const GdkColor *color)
+{
+	GSList *list, *link;
+
+	g_return_if_fail (GTKHTML_IS_COLOR_PALETTE (palette));
+	g_return_if_fail (color != NULL);
+
+	list = palette->priv->list;
+	link = g_hash_table_lookup (palette->priv->index, color);
+	if (link == NULL) {
+		list = g_slist_prepend (list, gdk_color_copy (color));
+		g_hash_table_insert (palette->priv->index, list->data, list);
+	} else {
+		list = g_slist_remove_link (list, link);
+		list = g_slist_concat (link, list);
+	}
+	palette->priv->list = list;
+
+	g_signal_emit (G_OBJECT (palette), signals[CHANGED], 0);
+}
+
+GSList *
+gtkhtml_color_palette_list_colors (GtkhtmlColorPalette *palette)
+{
+	GSList *list, *iter;
+
+	g_return_val_if_fail (GTKHTML_IS_COLOR_PALETTE (palette), NULL);
+
+	list = g_slist_copy (palette->priv->list);
+
+	for (iter = list; iter != NULL; iter = iter->next)
+		iter->data = gdk_color_copy (iter->data);
+
+	return list;
+}
Index: components/editor/gtkhtml-color-swatch.h
===================================================================
--- components/editor/gtkhtml-color-swatch.h	(revision 0)
+++ components/editor/gtkhtml-color-swatch.h	(revision 0)
@@ -0,0 +1,74 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-swatch.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_COLOR_SWATCH_H
+#define GTKHTML_COLOR_SWATCH_H
+
+#include "gtkhtml-editor-common.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_COLOR_SWATCH \
+	(gtkhtml_color_swatch_get_type ())
+#define GTKHTML_COLOR_SWATCH(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_COLOR_SWATCH, GtkhtmlColorSwatch))
+#define GTKHTML_COLOR_SWATCH_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_COLOR_SWATCH, GtkhtmlColorSwatchClass))
+#define GTKHTML_IS_COLOR_SWATCH(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_COLOR_SWATCH))
+#define GTKHTML_IS_COLOR_SWATCH_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_COLOR_SWATCH))
+#define GTKHTML_COLOR_SWATCH_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_COLOR_SWATCH, GtkhtmlColorSwatchClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlColorSwatch GtkhtmlColorSwatch;
+typedef struct _GtkhtmlColorSwatchClass GtkhtmlColorSwatchClass;
+typedef struct _GtkhtmlColorSwatchPrivate GtkhtmlColorSwatchPrivate;
+
+struct _GtkhtmlColorSwatch {
+	GtkBin parent;
+	GtkhtmlColorSwatchPrivate *priv;
+};
+
+struct _GtkhtmlColorSwatchClass {
+	GtkBinClass parent_class;
+};
+
+GType		gtkhtml_color_swatch_get_type	(void);
+GtkWidget *	gtkhtml_color_swatch_new	(void);
+void		gtkhtml_color_swatch_get_color	(GtkhtmlColorSwatch *swatch,
+						 GdkColor *color);
+void		gtkhtml_color_swatch_set_color	(GtkhtmlColorSwatch *swatch,
+						 const GdkColor *color);
+GtkShadowType	gtkhtml_color_swatch_get_shadow_type
+						(GtkhtmlColorSwatch *swatch);
+void		gtkhtml_color_swatch_set_shadow_type
+						(GtkhtmlColorSwatch *swatch,
+						 GtkShadowType shadow_type);
+
+G_END_DECLS
+
+#endif /* GTKHTML_COLOR_SWATCH_H */
Index: components/editor/gtkhtml-editor.pc.in
===================================================================
--- components/editor/gtkhtml-editor.pc.in	(revision 0)
+++ components/editor/gtkhtml-editor.pc.in	(revision 0)
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+gtkhtml_api_version=@GTKHTML_API_VERSION@
+
+Name: gtkhtml-editor
+Description: HTML editor widget
+Requires: libgtkhtml-@GTKHTML_API_VERSION@
+Version: @VERSION@
+Libs: -L${libdir} -lgtkhtml-editor
+Cflags: -I${includedir}/libgtkhtml-@GTKHTML_API_VERSION@/editor
Index: components/editor/gtkhtml-color-combo.c
===================================================================
--- components/editor/gtkhtml-color-combo.c	(revision 0)
+++ components/editor/gtkhtml-color-combo.c	(revision 0)
@@ -0,0 +1,1130 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-combo.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-color-combo.h"
+
+/* XXX The "combo" aspects of this widget are based heavily on the
+ *     GtkComboBox tree-view implementation.  Consider splitting it
+ *     into a reusable "combo-with-an-empty-window" widget. */
+
+#include <glib/gi18n-lib.h>
+#include <gdk/gdkkeysyms.h>
+#include "gtkhtml-color-swatch.h"
+
+#define NUM_CUSTOM_COLORS	8
+
+#define GTKHTML_COLOR_COMBO_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_COLOR_COMBO, GtkhtmlColorComboPrivate))
+
+enum {
+	PROP_0,
+	PROP_CURRENT_COLOR,
+	PROP_DEFAULT_COLOR,
+	PROP_DEFAULT_LABEL,
+	PROP_PALETTE,
+	PROP_POPUP_SHOWN,
+	PROP_STATE
+};
+
+enum {
+	CHANGED,
+	POPUP,
+	POPDOWN,
+	LAST_SIGNAL
+};
+
+struct _GtkhtmlColorComboPrivate {
+	GtkWidget *color_button;
+	GtkWidget *default_button;
+	GtkWidget *toggle_button;
+	GtkWidget *swatch;
+	GtkWidget *window;
+
+	GtkhtmlColorState *state;
+
+	GtkWidget *custom[NUM_CUSTOM_COLORS];
+
+	guint popup_shown	: 1;
+	guint popup_in_progress	: 1;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+static GdkColor black = { 0, 0, 0, 0 };
+
+static struct {
+	const gchar *color;
+	const gchar *tooltip;
+} default_colors[] = {
+
+	{ "#000000", N_("black") },
+	{ "#993300", N_("light brown") },
+	{ "#333300", N_("brown gold") },
+	{ "#003300", N_("dark green #2") },
+	{ "#003366", N_("navy") },
+	{ "#000080", N_("dark blue") },
+	{ "#333399", N_("purple #2") },
+	{ "#333333", N_("very dark gray") },
+
+	{ "#800000", N_("dark red") },
+	{ "#FF6600", N_("red-orange") },
+	{ "#808000", N_("gold") },
+	{ "#008000", N_("dark green") },
+	{ "#008080", N_("dull blue") },
+	{ "#0000FF", N_("blue") },
+	{ "#666699", N_("dull purple") },
+	{ "#808080", N_("dark grey") },
+
+	{ "#FF0000", N_("red") },
+	{ "#FF9900", N_("orange") },
+	{ "#99CC00", N_("lime") },
+	{ "#339966", N_("dull green") },
+	{ "#33CCCC", N_("dull blue #2") },
+	{ "#3366FF", N_("sky blue #2") },
+	{ "#800080", N_("purple") },
+	{ "#969696", N_("gray") },
+
+	{ "#FF00FF", N_("magenta") },
+	{ "#FFCC00", N_("bright orange") },
+	{ "#FFFF00", N_("yellow") },
+	{ "#00FF00", N_("green") },
+	{ "#00FFFF", N_("cyan") },
+	{ "#00CCFF", N_("bright blue") },
+	{ "#993366", N_("red purple") },
+	{ "#C0C0C0", N_("light grey") },
+
+	{ "#FF99CC", N_("pink") },
+	{ "#FFCC99", N_("light orange") },
+	{ "#FFFF99", N_("light yellow") },
+	{ "#CCFFCC", N_("light green") },
+	{ "#CCFFFF", N_("light cyan") },
+	{ "#99CCFF", N_("light blue") },
+	{ "#CC99FF", N_("light purple") },
+	{ "#FFFFFF", N_("white") }
+};
+
+static void
+color_combo_notify_current_color_cb (GtkhtmlColorCombo *combo)
+{
+	GtkhtmlColorSwatch *swatch;
+	GdkColor color;
+
+	swatch = GTKHTML_COLOR_SWATCH (combo->priv->swatch);
+	gtkhtml_color_combo_get_current_color (combo, &color);
+	gtkhtml_color_swatch_set_color (swatch, &color);
+
+	g_signal_emit (G_OBJECT (combo), signals[CHANGED], 0);
+}
+
+static void
+color_combo_propagate_notify_cb (GtkhtmlColorCombo *combo,
+                                 GParamSpec *pspec)
+{
+	g_object_notify (G_OBJECT (combo), pspec->name);
+}
+
+static void
+color_combo_reposition_window (GtkhtmlColorCombo *combo)
+{
+	GdkScreen *screen;
+	GdkWindow *window;
+	GdkRectangle monitor;
+	gint monitor_num;
+	gint x, y, width, height;
+
+	window = GTK_WIDGET (combo)->window;
+	screen = gtk_widget_get_screen (GTK_WIDGET (combo));
+	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
+	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+	gdk_window_get_origin (window, &x, &y);
+
+	if (GTK_WIDGET_NO_WINDOW (combo)) {
+		x += GTK_WIDGET (combo)->allocation.x;
+		y += GTK_WIDGET (combo)->allocation.y;
+	}
+
+	width = combo->priv->window->allocation.width;
+	height = combo->priv->window->allocation.height;
+
+	x = CLAMP (x, monitor.x, monitor.x + monitor.width - width);
+	y = CLAMP (y, monitor.y, monitor.y + monitor.height - height);
+
+	gtk_window_move (GTK_WINDOW (combo->priv->window), x, y);
+}
+
+static gboolean
+color_combo_button_press_event_cb (GtkhtmlColorCombo *combo,
+                                   GdkEventButton *event)
+{
+	GtkToggleButton *toggle_button;
+	GtkWidget *event_widget;
+
+	toggle_button = GTK_TOGGLE_BUTTON (combo->priv->toggle_button);
+	event_widget = gtk_get_event_widget ((GdkEvent *) event);
+
+	if (event_widget == combo->priv->window)
+		return TRUE;
+
+	if (event_widget != combo->priv->toggle_button)
+		return FALSE;
+
+	if (gtk_toggle_button_get_active (toggle_button))
+		return FALSE;
+
+	gtkhtml_color_combo_popup (combo);
+
+	combo->priv->popup_in_progress = TRUE;
+
+	return TRUE;
+}
+
+static gboolean
+color_combo_button_release_event_cb (GtkhtmlColorCombo *combo,
+                                     GdkEventButton *event)
+{
+	GtkToggleButton *toggle_button;
+	GtkWidget *event_widget;
+	gboolean popup_in_progress;
+
+	toggle_button = GTK_TOGGLE_BUTTON (combo->priv->toggle_button);
+	event_widget = gtk_get_event_widget ((GdkEvent *) event);
+
+	popup_in_progress = combo->priv->popup_in_progress;
+	combo->priv->popup_in_progress = FALSE;
+
+	if (event_widget != combo->priv->toggle_button)
+		goto popdown;
+
+	if (popup_in_progress)
+		return FALSE;
+
+	if (gtk_toggle_button_get_active (toggle_button))
+		goto popdown;
+
+	return FALSE;
+
+popdown:
+	gtkhtml_color_combo_popdown (combo);
+
+	return TRUE;
+}
+
+static void
+color_combo_child_show_cb (GtkhtmlColorCombo *combo)
+{
+	combo->priv->popup_shown = TRUE;
+	g_object_notify (G_OBJECT (combo), "popup-shown");
+}
+
+static void
+color_combo_child_hide_cb (GtkhtmlColorCombo *combo)
+{
+	combo->priv->popup_shown = FALSE;
+	g_object_notify (G_OBJECT (combo), "popup-shown");
+}
+
+static gboolean
+color_combo_child_key_press_event_cb (GtkhtmlColorCombo *combo,
+                                      GdkEventKey *event)
+{
+	GtkWidget *window = combo->priv->window;
+
+	if (!gtk_bindings_activate_event (GTK_OBJECT (window), event))
+		gtk_bindings_activate_event (GTK_OBJECT (combo), event);
+
+	return TRUE;
+}
+
+static void
+color_combo_custom_clicked_cb (GtkhtmlColorCombo *combo)
+{
+	GtkhtmlColorPalette *palette;
+	GtkWidget *dialog;
+	GtkWidget *colorsel;
+	GtkWidget *toplevel;
+	GdkColor color;
+	gint response;
+
+	gtkhtml_color_combo_popdown (combo);
+
+	dialog = gtk_color_selection_dialog_new (_("Choose Custom Color"));
+	colorsel = GTK_COLOR_SELECTION_DIALOG (dialog)->colorsel;
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo));
+
+	if (GTK_WIDGET_TOPLEVEL (toplevel))
+		gtk_window_set_transient_for (
+			GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	if (response != GTK_RESPONSE_OK)
+		goto exit;
+
+	palette = gtkhtml_color_state_get_palette (combo->priv->state);
+
+	gtk_color_selection_get_current_color (
+		GTK_COLOR_SELECTION (colorsel), &color);
+	gtkhtml_color_palette_add_color (palette, &color);
+	gtkhtml_color_combo_set_current_color (combo, &color);
+
+exit:
+	gtk_widget_destroy (dialog);
+}
+
+static gboolean
+color_combo_custom_release_event_cb (GtkhtmlColorCombo *combo,
+                                     GdkEventButton *event,
+                                     GtkButton *button)
+{
+	gtk_button_clicked (button);
+
+	return FALSE;
+}
+
+static void
+color_combo_default_clicked_cb (GtkhtmlColorCombo *combo)
+{
+	gtkhtml_color_combo_set_current_color (combo, NULL);
+	gtkhtml_color_combo_popdown (combo);
+}
+
+static gboolean
+color_combo_default_release_event_cb (GtkhtmlColorCombo *combo,
+                                      GdkEventButton *event,
+                                      GtkButton *button)
+{
+	if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
+		gtk_button_clicked (button);
+
+	return FALSE;
+}
+
+static void
+color_combo_palette_changed_cb (GtkhtmlColorCombo *combo)
+{
+	GtkhtmlColorPalette *palette;
+	GtkhtmlColorSwatch *swatch;
+	GSList *list;
+	guint ii;
+
+	palette = gtkhtml_color_state_get_palette (combo->priv->state);
+	list = gtkhtml_color_palette_list_colors (palette);
+
+	/* Make sure we have at least NUM_CUSTOM_COLORS. */
+	for (ii = g_slist_length (list); ii < NUM_CUSTOM_COLORS; ii++)
+		list = g_slist_append (list, gdk_color_copy (&black));
+
+	/* Pop items off the list and update the custom swatches. */
+	for (ii = 0; ii < NUM_CUSTOM_COLORS; ii++) {
+		swatch = GTKHTML_COLOR_SWATCH (combo->priv->custom[ii]);
+		gtkhtml_color_swatch_set_color (swatch, list->data);
+		gdk_color_free (list->data);
+		list = g_slist_delete_link (list, list);
+	}
+
+	/* Delete any remaining list items. */
+	g_slist_foreach (list, (GFunc) gdk_color_free, NULL);
+	g_slist_free (list);
+}
+
+static void
+color_combo_swatch_clicked_cb (GtkhtmlColorCombo *combo,
+                               GtkButton *button)
+{
+	GtkWidget *swatch;
+	GdkColor color;
+
+	swatch = gtk_bin_get_child (GTK_BIN (button));
+	gtkhtml_color_swatch_get_color (
+		GTKHTML_COLOR_SWATCH (swatch), &color);
+	gtkhtml_color_state_set_current_color (combo->priv->state, &color);
+	gtkhtml_color_combo_popdown (combo);
+}
+
+static gboolean
+color_combo_swatch_release_event_cb (GtkhtmlColorCombo *combo,
+                                     GdkEventButton *event,
+                                     GtkButton *button)
+{
+	if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL)
+		gtk_button_clicked (button);
+
+	return FALSE;
+}
+                                     
+
+static void
+color_combo_toggled_cb (GtkhtmlColorCombo *combo)
+{
+	GtkToggleButton *toggle_button;
+	gboolean active;
+
+	toggle_button = GTK_TOGGLE_BUTTON (combo->priv->toggle_button);
+	active = gtk_toggle_button_get_active (toggle_button);
+
+	if (active)
+		gtkhtml_color_combo_popup (combo);
+	else
+		gtkhtml_color_combo_popdown (combo);
+}
+
+static GtkWidget *
+color_combo_new_swatch_button (GtkhtmlColorCombo *combo,
+                               const gchar *tooltip,
+                               GdkColor *color)
+{
+	GtkWidget *button;
+	GtkWidget *swatch;
+
+	button = gtk_button_new ();
+	gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+	gtk_widget_set_tooltip_text (button, tooltip);
+	gtk_widget_show (button);
+
+	swatch = gtkhtml_color_swatch_new ();
+	gtkhtml_color_swatch_set_color (
+		GTKHTML_COLOR_SWATCH (swatch), color);
+	gtkhtml_color_swatch_set_shadow_type (
+		GTKHTML_COLOR_SWATCH (swatch), GTK_SHADOW_IN);
+	gtk_container_add (GTK_CONTAINER (button), swatch);
+	gtk_widget_show (swatch);
+
+	g_signal_connect_swapped (
+		button, "clicked",
+		G_CALLBACK (color_combo_swatch_clicked_cb), combo);
+	g_signal_connect_swapped (
+		button, "button-release-event",
+		G_CALLBACK (color_combo_swatch_release_event_cb), combo);
+
+	return button;
+}
+
+static void
+color_combo_set_property (GObject *object,
+                          guint property_id,
+                          const GValue *value,
+                          GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_COLOR:
+			gtkhtml_color_combo_set_current_color (
+				GTKHTML_COLOR_COMBO (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_DEFAULT_COLOR:
+			gtkhtml_color_combo_set_default_color (
+				GTKHTML_COLOR_COMBO (object),
+				g_value_get_boxed (value));
+			return;
+
+		case PROP_DEFAULT_LABEL:
+			gtkhtml_color_combo_set_default_label (
+				GTKHTML_COLOR_COMBO (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_PALETTE:
+			gtkhtml_color_combo_set_palette (
+				GTKHTML_COLOR_COMBO (object),
+				g_value_get_object (value));
+			return;
+
+		case PROP_POPUP_SHOWN:
+			if (g_value_get_boolean (value))
+				gtkhtml_color_combo_popup (
+					GTKHTML_COLOR_COMBO (object));
+			else
+				gtkhtml_color_combo_popdown (
+					GTKHTML_COLOR_COMBO (object));
+			return;
+
+		case PROP_STATE:
+			gtkhtml_color_combo_set_state (
+				GTKHTML_COLOR_COMBO (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_combo_get_property (GObject *object,
+                          guint property_id,
+                          GValue *value,
+                          GParamSpec *pspec)
+{
+	GtkhtmlColorComboPrivate *priv;
+	GdkColor color;
+
+	priv = GTKHTML_COLOR_COMBO_GET_PRIVATE (object);
+
+	switch (property_id) {
+		case PROP_CURRENT_COLOR:
+			gtkhtml_color_combo_get_current_color (
+				GTKHTML_COLOR_COMBO (object), &color);
+			g_value_set_boxed (value, &color);
+			return;
+
+		case PROP_DEFAULT_COLOR:
+			gtkhtml_color_combo_get_default_color (
+				GTKHTML_COLOR_COMBO (object), &color);
+			g_value_set_boxed (value, &color);
+			return;
+
+		case PROP_DEFAULT_LABEL:
+			g_value_set_string (
+				value, gtkhtml_color_combo_get_default_label (
+				GTKHTML_COLOR_COMBO (object)));
+			return;
+
+		case PROP_PALETTE:
+			g_value_set_object (
+				value, gtkhtml_color_combo_get_palette (
+				GTKHTML_COLOR_COMBO (object)));
+			return;
+
+		case PROP_POPUP_SHOWN:
+			g_value_set_boolean (value, priv->popup_shown);
+			return;
+
+		case PROP_STATE:
+			g_value_set_object (
+				value, gtkhtml_color_combo_get_state (
+				GTKHTML_COLOR_COMBO (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+color_combo_dispose (GObject *object)
+{
+	GtkhtmlColorComboPrivate *priv;
+	gint ii;
+
+	priv = GTKHTML_COLOR_COMBO_GET_PRIVATE (object);
+
+	if (priv->color_button != NULL) {
+		g_object_unref (priv->color_button);
+		priv->color_button = NULL;
+	}
+
+	if (priv->default_button != NULL) {
+		g_object_unref (priv->default_button);
+		priv->default_button = NULL;
+	}
+
+	if (priv->toggle_button != NULL) {
+		g_object_unref (priv->toggle_button);
+		priv->toggle_button = NULL;
+	}
+
+	if (priv->swatch != NULL) {
+		g_object_unref (priv->swatch);
+		priv->swatch = NULL;
+	}
+
+	if (priv->window != NULL) {
+		g_object_unref (priv->window);
+		priv->window = NULL;
+	}
+
+	if (priv->state != NULL) {
+		g_signal_handlers_disconnect_matched (
+			priv->state, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, object);
+		g_object_unref (priv->state);
+		priv->state = NULL;
+	}
+
+	for (ii = 0; ii < NUM_CUSTOM_COLORS; ii++) {
+		if (priv->custom[ii] != NULL) {
+			g_object_unref (priv->custom[ii]);
+			priv->custom[ii] = NULL;
+		}
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+color_combo_size_request (GtkWidget *widget,
+                          GtkRequisition *requisition)
+{
+	GtkhtmlColorComboPrivate *priv;
+
+	priv = GTKHTML_COLOR_COMBO_GET_PRIVATE (widget);
+
+	gtk_widget_size_request (priv->toggle_button, requisition);
+}
+
+static void
+color_combo_size_allocate (GtkWidget *widget,
+                           GtkAllocation *allocation)
+{
+	GtkhtmlColorComboPrivate *priv;
+
+	priv = GTKHTML_COLOR_COMBO_GET_PRIVATE (widget);
+
+	widget->allocation = *allocation;
+	gtk_widget_size_allocate (priv->toggle_button, allocation);
+}
+
+static void
+color_combo_popup (GtkhtmlColorCombo *combo)
+{
+	GtkToggleButton *toggle_button;
+	GtkButton *button;
+	GdkWindow *window;
+	GdkGrabStatus status;
+	const gchar *label;
+
+	if (!GTK_WIDGET_REALIZED (combo))
+		return;
+
+	if (combo->priv->popup_shown)
+		return;
+
+	/* Update the default button label. */
+	button = GTK_BUTTON (combo->priv->default_button);
+	label = gtkhtml_color_state_get_default_label (combo->priv->state);
+	gtk_button_set_label (button, label);
+
+	/* Position the window over the button. */
+	color_combo_reposition_window (combo);
+
+	/* Show the pop-up. */
+	gtk_widget_show (combo->priv->window);
+	gtk_widget_grab_focus (combo->priv->window);
+
+	/* Activate the toggle button. */
+	toggle_button = GTK_TOGGLE_BUTTON (combo->priv->toggle_button);
+	gtk_toggle_button_set_active (toggle_button, TRUE);
+
+	/* Try to grab the pointer and keyboard. */
+	window = combo->priv->window->window;
+	status = gdk_pointer_grab (
+		window, TRUE,
+		GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+		GDK_POINTER_MOTION_MASK, NULL, NULL, GDK_CURRENT_TIME);
+	if (status == GDK_GRAB_SUCCESS) {
+		status = gdk_keyboard_grab (window, TRUE, GDK_CURRENT_TIME);
+		if (status != GDK_GRAB_SUCCESS)
+			gdk_display_pointer_ungrab (
+				gdk_drawable_get_display (window),
+				GDK_CURRENT_TIME);
+	}
+
+	if (status == GDK_GRAB_SUCCESS)
+		gtk_grab_add (combo->priv->window);
+	else
+		gtk_widget_hide (combo->priv->window);
+}
+
+static void
+color_combo_popdown (GtkhtmlColorCombo *combo)
+{
+	GtkToggleButton *toggle_button;
+
+	if (!GTK_WIDGET_REALIZED (combo))
+		return;
+
+	if (!combo->priv->popup_shown)
+		return;
+
+	/* Hide the pop-up. */
+	gtk_grab_remove (combo->priv->window);
+	gtk_widget_hide (combo->priv->window);
+
+	/* Deactivate the toggle button. */
+	toggle_button = GTK_TOGGLE_BUTTON (combo->priv->toggle_button);
+	gtk_toggle_button_set_active (toggle_button, FALSE);
+}
+
+static void
+color_combo_class_init (GtkhtmlColorComboClass *class)
+{
+	GObjectClass *object_class;
+	GtkWidgetClass *widget_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlColorComboPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = color_combo_set_property;
+	object_class->get_property = color_combo_get_property;
+	object_class->dispose = color_combo_dispose;
+
+	widget_class = GTK_WIDGET_CLASS (class);
+	widget_class->size_request = color_combo_size_request;
+	widget_class->size_allocate = color_combo_size_allocate;
+
+	class->popup = color_combo_popup;
+	class->popdown = color_combo_popdown;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_COLOR,
+		g_param_spec_boxed (
+			"current-color",
+			_("Current color"),
+			_("The currently selected color"),
+			GDK_TYPE_COLOR,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_COLOR,
+		g_param_spec_boxed (
+			"default-color",
+			_("Default color"),
+			_("The color associated with the default button"),
+			GDK_TYPE_COLOR,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_DEFAULT_LABEL,
+		g_param_spec_string (
+			"default-label",
+			_("Default label"),
+			_("The label for the default button"),
+			_("Default"),
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_PALETTE,
+		g_param_spec_object (
+			"palette",
+			_("Color palette"),
+			_("Custom color palette"),
+			GTKHTML_TYPE_COLOR_PALETTE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_POPUP_SHOWN,
+		g_param_spec_boolean (
+			"popup-shown",
+			_("Popup shown"),
+			_("Whether the combo's dropdown is shown"),
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_STATE,
+		g_param_spec_object (
+			"state",
+			_("Color state"),
+			_("State of the color combo"),
+			GTKHTML_TYPE_COLOR_STATE,
+			G_PARAM_READWRITE));
+
+	signals[CHANGED] = g_signal_new (
+		"changed",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[POPUP] = g_signal_new (
+		"popup",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		G_STRUCT_OFFSET (GtkhtmlColorComboClass, popup),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[POPDOWN] = g_signal_new (
+		"popdown",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		G_STRUCT_OFFSET (GtkhtmlColorComboClass, popdown),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	gtk_binding_entry_add_signal (
+		gtk_binding_set_by_class (class),
+		GDK_Down, GDK_MOD1_MASK, "popup", 0);
+	gtk_binding_entry_add_signal (
+		gtk_binding_set_by_class (class),
+		GDK_KP_Down, GDK_MOD1_MASK, "popup", 0);
+
+	gtk_binding_entry_add_signal (
+		gtk_binding_set_by_class (class),
+		GDK_Up, GDK_MOD1_MASK, "popdown", 0);
+	gtk_binding_entry_add_signal (
+		gtk_binding_set_by_class (class),
+		GDK_KP_Up, GDK_MOD1_MASK, "popdown", 0);
+	gtk_binding_entry_add_signal (
+		gtk_binding_set_by_class (class),
+		GDK_Escape, 0, "popdown", 0);
+}
+
+static void
+color_combo_init (GtkhtmlColorCombo *combo)
+{
+	GtkhtmlColorState *state;
+	GtkWidget *toplevel;
+	GtkWidget *container;
+	GtkWidget *widget;
+	GtkWidget *window;
+	guint ii;
+
+	combo->priv = GTKHTML_COLOR_COMBO_GET_PRIVATE (combo);
+
+	state = gtkhtml_color_state_new ();
+	gtkhtml_color_combo_set_state (combo, state);
+	g_object_unref (state);
+
+	/* Build the combo button. */
+
+	widget = gtk_toggle_button_new ();
+	gtk_container_add (GTK_CONTAINER (combo), widget);
+	combo->priv->toggle_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_hbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtkhtml_color_swatch_new ();
+	gtkhtml_color_swatch_set_shadow_type (
+		GTKHTML_COLOR_SWATCH (widget), GTK_SHADOW_ETCHED_OUT);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	combo->priv->swatch = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_vseparator_new ();
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 3);
+	gtk_widget_show (widget);
+
+	widget = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
+	gtk_widget_show (widget);
+
+	g_signal_connect_swapped (
+		combo->priv->toggle_button, "button-press-event",
+		G_CALLBACK (color_combo_button_press_event_cb), combo);
+
+	g_signal_connect_swapped (
+		combo->priv->toggle_button, "toggled",
+		G_CALLBACK (color_combo_toggled_cb), combo);
+
+	/* Build the pop-up window. */
+
+	window = gtk_window_new (GTK_WINDOW_POPUP);
+	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combo));	
+	gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+	gtk_window_set_type_hint (
+		GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_COMBO);
+	if (GTK_WIDGET_TOPLEVEL (toplevel)) {
+		gtk_window_group_add_window (
+			gtk_window_get_group (GTK_WINDOW (toplevel)),
+			GTK_WINDOW (window));
+		gtk_window_set_transient_for (
+			GTK_WINDOW (window), GTK_WINDOW (toplevel));
+	}
+	combo->priv->window = g_object_ref (window);
+
+	g_signal_connect_swapped (
+		window, "show",
+		G_CALLBACK (color_combo_child_show_cb), combo);
+	g_signal_connect_swapped (
+		window, "hide",
+		G_CALLBACK (color_combo_child_hide_cb), combo);
+	g_signal_connect_swapped (
+		window, "button-press-event",
+		G_CALLBACK (color_combo_button_press_event_cb), combo);
+	g_signal_connect_swapped (
+		window, "button-release-event",
+		G_CALLBACK (color_combo_button_release_event_cb), combo);
+	g_signal_connect_swapped (
+		window, "key-press-event",
+		G_CALLBACK (color_combo_child_key_press_event_cb), combo);
+
+	/* Build the pop-up window contents. */
+
+	widget = gtk_frame_new (NULL);
+	gtk_frame_set_shadow_type (GTK_FRAME (widget), GTK_SHADOW_OUT);
+	gtk_container_add (GTK_CONTAINER (window), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_table_new (5, 8, TRUE);
+	gtk_table_set_row_spacings (GTK_TABLE (widget), 0);
+	gtk_table_set_col_spacings (GTK_TABLE (widget), 0);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = gtk_button_new ();
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		0, 8, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
+	combo->priv->default_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (color_combo_default_clicked_cb), combo);
+	g_signal_connect_swapped (
+		widget, "button-release-event",
+		G_CALLBACK (color_combo_default_release_event_cb), combo);
+
+	for (ii = 0; ii < G_N_ELEMENTS (default_colors); ii++) {
+		guint left = ii % 8;
+		guint top = ii / 8 + 1;
+		GdkColor color;
+		const gchar *tooltip;
+
+		tooltip = gettext (default_colors[ii].tooltip);
+		gdk_color_parse (default_colors[ii].color, &color);
+		widget = color_combo_new_swatch_button (
+			combo, tooltip, &color);
+		gtk_table_attach (
+			GTK_TABLE (container), widget,
+			left, left + 1, top, top + 1, 0, 0, 0, 0);
+	}
+
+	for (ii = 0; ii < NUM_CUSTOM_COLORS; ii++) {
+		widget = color_combo_new_swatch_button (
+			combo, _("custom"), &black);
+		gtk_table_attach (
+			GTK_TABLE (container), widget,
+			ii, ii + 1, 6, 7, 0, 0, 0, 0);
+		combo->priv->custom[ii] = g_object_ref (
+			gtk_bin_get_child (GTK_BIN (widget)));
+	}
+
+	widget = gtk_button_new_with_label (_("Custom Color..."));
+	gtk_button_set_image (
+		GTK_BUTTON (widget), gtk_image_new_from_stock (
+		GTK_STOCK_SELECT_COLOR, GTK_ICON_SIZE_BUTTON));
+	gtk_table_attach (
+		GTK_TABLE (container), widget,
+		0, 8, 7, 8, GTK_FILL, 0, 0, 0);
+	combo->priv->color_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (color_combo_custom_clicked_cb), combo);
+	g_signal_connect_swapped (
+		widget, "button-release-event",
+		G_CALLBACK (color_combo_custom_release_event_cb), combo);
+}
+
+GType
+gtkhtml_color_combo_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlColorComboClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) color_combo_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlColorCombo),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) color_combo_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_BIN, "GtkhtmlColorCombo", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+gtkhtml_color_combo_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_COLOR_COMBO, NULL);
+}
+
+GtkWidget *
+gtkhtml_color_combo_new_defaults (GdkColor *default_color,
+                                  const gchar *default_label)
+{
+	g_return_val_if_fail (default_color != NULL, NULL);
+	g_return_val_if_fail (default_label != NULL, NULL);
+
+	return g_object_new (
+		GTKHTML_TYPE_COLOR_COMBO,
+		"default-color", default_color,
+		"default-label", default_label,
+		NULL);
+}
+
+void
+gtkhtml_color_combo_popup (GtkhtmlColorCombo *combo)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	g_signal_emit (combo, signals[POPUP], 0);
+}
+
+void
+gtkhtml_color_combo_popdown (GtkhtmlColorCombo *combo)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	g_signal_emit (combo, signals[POPDOWN], 0);
+}
+
+gboolean
+gtkhtml_color_combo_get_current_color (GtkhtmlColorCombo *combo,
+                                       GdkColor *color)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_COMBO (combo), FALSE);
+
+	return gtkhtml_color_state_get_current_color (
+		combo->priv->state, color);
+}
+
+void
+gtkhtml_color_combo_set_current_color (GtkhtmlColorCombo *combo,
+                                       GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	gtkhtml_color_state_set_current_color (combo->priv->state, color);
+}
+
+void
+gtkhtml_color_combo_get_default_color (GtkhtmlColorCombo *combo,
+                                       GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	gtkhtml_color_state_get_default_color (combo->priv->state, color);
+}
+
+void
+gtkhtml_color_combo_set_default_color (GtkhtmlColorCombo *combo,
+                                       GdkColor *color)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	gtkhtml_color_state_set_default_color (combo->priv->state, color);
+}
+
+const gchar *
+gtkhtml_color_combo_get_default_label (GtkhtmlColorCombo *combo)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_COMBO (combo), NULL);
+
+	return gtkhtml_color_state_get_default_label (combo->priv->state);
+}
+
+void
+gtkhtml_color_combo_set_default_label (GtkhtmlColorCombo *combo,
+                                       const gchar *text)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	gtkhtml_color_state_set_default_label (combo->priv->state, text);
+}
+
+GtkhtmlColorPalette *
+gtkhtml_color_combo_get_palette (GtkhtmlColorCombo *combo)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_COMBO (combo), NULL);
+
+	return gtkhtml_color_state_get_palette (combo->priv->state);
+}
+
+void
+gtkhtml_color_combo_set_palette (GtkhtmlColorCombo *combo,
+                                 GtkhtmlColorPalette *palette)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	gtkhtml_color_state_set_palette (combo->priv->state, palette);
+}
+
+GtkhtmlColorState *
+gtkhtml_color_combo_get_state (GtkhtmlColorCombo *combo)
+{
+	g_return_val_if_fail (GTKHTML_IS_COLOR_COMBO (combo), NULL);
+
+	return combo->priv->state;
+}
+
+void
+gtkhtml_color_combo_set_state (GtkhtmlColorCombo *combo,
+                               GtkhtmlColorState *state)
+{
+	g_return_if_fail (GTKHTML_IS_COLOR_COMBO (combo));
+
+	if (state == NULL)
+		state = gtkhtml_color_state_new ();
+	else
+		g_return_if_fail (GTKHTML_IS_COLOR_STATE (state));
+
+	if (combo->priv->state != NULL) {
+		g_signal_handlers_disconnect_matched (
+			combo->priv->state, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, combo);
+		g_object_unref (combo->priv->state);
+	}
+
+	combo->priv->state = g_object_ref (state);
+
+	/* Listen and respond to changes in the state object. */
+
+	g_signal_connect_swapped (
+		combo->priv->state, "notify::current-color",
+		G_CALLBACK (color_combo_notify_current_color_cb), combo);
+
+	g_signal_connect_swapped (
+		combo->priv->state, "palette-changed",
+		G_CALLBACK (color_combo_palette_changed_cb), combo);
+
+	/* Propagate all "notify" signals through our own properties. */
+
+	g_signal_connect_swapped (
+		combo->priv->state, "notify",
+		G_CALLBACK (color_combo_propagate_notify_cb), combo);
+}
Index: components/editor/gtkhtml-color-palette.h
===================================================================
--- components/editor/gtkhtml-color-palette.h	(revision 0)
+++ components/editor/gtkhtml-color-palette.h	(revision 0)
@@ -0,0 +1,71 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-palette.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_COLOR_PALETTE_H
+#define GTKHTML_COLOR_PALETTE_H
+
+#include "gtkhtml-editor-common.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_COLOR_PALETTE \
+	(gtkhtml_color_palette_get_type ())
+#define GTKHTML_COLOR_PALETTE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_COLOR_PALETTE, GtkhtmlColorPalette))
+#define GTKHTML_COLOR_PALETTE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_COLOR_PALETTE, GtkhtmlColorPaletteClass))
+#define GTKHTML_IS_COLOR_PALETTE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_COLOR_PALETTE))
+#define GTKHTML_IS_COLOR_PALETTE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_COLOR_PALETTE))
+#define GTKHTML_COLOR_PALETTE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_COLOR_PALETTE, GtkhtmlColorPaletteClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlColorPalette GtkhtmlColorPalette;
+typedef struct _GtkhtmlColorPaletteClass GtkhtmlColorPaletteClass;
+typedef struct _GtkhtmlColorPalettePrivate GtkhtmlColorPalettePrivate;
+
+struct _GtkhtmlColorPalette {
+	GObject parent;
+	GtkhtmlColorPalettePrivate *priv;
+};
+
+struct _GtkhtmlColorPaletteClass {
+	GObjectClass parent_class;
+};
+
+GType		gtkhtml_color_palette_get_type	(void);
+GtkhtmlColorPalette *
+		gtkhtml_color_palette_new	(void);
+void		gtkhtml_color_palette_add_color
+						(GtkhtmlColorPalette *palette,
+						 const GdkColor *color);
+GSList *	gtkhtml_color_palette_list_colors
+						(GtkhtmlColorPalette *palette);
+
+G_END_DECLS
+
+#endif /* GTKHTML_COLOR_PALETTE_H */
Index: components/editor/gtkhtml-color-combo.h
===================================================================
--- components/editor/gtkhtml-color-combo.h	(revision 0)
+++ components/editor/gtkhtml-color-combo.h	(revision 0)
@@ -0,0 +1,100 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-color-combo.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_COLOR_COMBO_H
+#define GTKHTML_COLOR_COMBO_H
+
+#include "gtkhtml-editor-common.h"
+#include "gtkhtml-color-palette.h"
+#include "gtkhtml-color-state.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_COLOR_COMBO \
+	(gtkhtml_color_combo_get_type ())
+#define GTKHTML_COLOR_COMBO(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_COLOR_COMBO, GtkhtmlColorCombo))
+#define GTKHTML_COLOR_COMBO_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_COLOR_COMBO, GtkhtmlColorComboClass))
+#define GTKHTML_IS_COLOR_COMBO(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_COLOR_COMBO))
+#define GTKHTML_IS_COLOR_COMBO_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_COLOR_COMBO))
+#define GTKHTML_COLOR_COMBO_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_COLOR_COMBO, GtkhtmlColorComboClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlColorCombo GtkhtmlColorCombo;
+typedef struct _GtkhtmlColorComboClass GtkhtmlColorComboClass;
+typedef struct _GtkhtmlColorComboPrivate GtkhtmlColorComboPrivate;
+
+struct _GtkhtmlColorCombo {
+	GtkBin parent;
+	GtkhtmlColorComboPrivate *priv;
+};
+
+struct _GtkhtmlColorComboClass {
+	GtkBinClass parent_class;
+
+	void		(*popup)		(GtkhtmlColorCombo *combo);
+	void		(*popdown)		(GtkhtmlColorCombo *combo);
+};
+
+GType		gtkhtml_color_combo_get_type	(void);
+GtkWidget *	gtkhtml_color_combo_new		(void);
+GtkWidget *	gtkhtml_color_combo_new_defaults
+						(GdkColor *default_color,
+						 const gchar *default_label);
+void		gtkhtml_color_combo_popup	(GtkhtmlColorCombo *combo);
+void		gtkhtml_color_combo_popdown	(GtkhtmlColorCombo *combo);
+gboolean	gtkhtml_color_combo_get_current_color
+						(GtkhtmlColorCombo *combo,
+						 GdkColor *color);
+void		gtkhtml_color_combo_set_current_color
+						(GtkhtmlColorCombo *combo,
+						 GdkColor *color);
+void		gtkhtml_color_combo_get_default_color
+						(GtkhtmlColorCombo *combo,
+						 GdkColor *color);
+void		gtkhtml_color_combo_set_default_color
+						(GtkhtmlColorCombo *combo,
+						 GdkColor *default_color);
+const gchar *	gtkhtml_color_combo_get_default_label
+						(GtkhtmlColorCombo *combo);
+void		gtkhtml_color_combo_set_default_label
+						(GtkhtmlColorCombo *combo,
+						 const gchar *text);
+GtkhtmlColorPalette *
+		gtkhtml_color_combo_get_palette	(GtkhtmlColorCombo *combo);
+void		gtkhtml_color_combo_set_palette	(GtkhtmlColorCombo *combo,
+						 GtkhtmlColorPalette *palette);
+GtkhtmlColorState *
+		gtkhtml_color_combo_get_state	(GtkhtmlColorCombo *combo);
+void		gtkhtml_color_combo_set_state	(GtkhtmlColorCombo *combo,
+						 GtkhtmlColorState *state);
+
+G_END_DECLS
+
+#endif /* GTKHTML_COLOR_COMBO_H */
Index: components/editor/gtkhtml-editor-common.h
===================================================================
--- components/editor/gtkhtml-editor-common.h	(revision 0)
+++ components/editor/gtkhtml-editor-common.h	(revision 0)
@@ -0,0 +1,31 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-common.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_EDITOR_COMMON_H
+#define GTKHTML_EDITOR_COMMON_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#endif /* GTKHTML_EDITOR_COMMON_H */
Index: components/editor/gtkhtml-editor.ui
===================================================================
--- components/editor/gtkhtml-editor.ui	(revision 0)
+++ components/editor/gtkhtml-editor.ui	(revision 0)
@@ -0,0 +1,180 @@
+<ui>
+  <menubar name='main-menu'>
+    <placeholder name='pre-file-menu'/>
+    <menu action='file-menu'/>
+    <placeholder name='pre-edit-menu'/>
+    <menu action='edit-menu'>
+      <menuitem action='undo'/>
+      <menuitem action='redo'/>
+      <separator/>
+      <menuitem action='cut'/>
+      <menuitem action='copy'/>
+      <menuitem action='paste'/>
+      <menuitem action='paste-quote'/>
+      <separator/>
+      <menuitem action='select-all'/>
+      <separator/>
+      <menuitem action='show-find'/>
+      <menuitem action='find-again'/>
+      <menuitem action='show-replace'/>
+      <separator/>
+      <menuitem action='spell-check'/>
+      <menu action='language-menu'/>
+    </menu>
+    <placeholder name='pre-view-menu'/>
+    <menu action='view-menu'/>
+    <placeholder name='pre-insert-menu'/>
+    <menu action='insert-menu'>
+      <menuitem action='insert-image'/>
+      <menuitem action='insert-link'/>
+      <menuitem action='insert-rule'/>
+      <menuitem action='insert-table'/>
+      <menuitem action='insert-text-file'/>
+      <menuitem action='insert-html-file'/>
+      <menu action='insert-face-menu'>
+        <menuitem action='insert-face-smile'/>
+        <menuitem action='insert-face-surprise'/>
+        <menuitem action='insert-face-wink'/>
+        <menuitem action='insert-face-sad'/>
+        <menuitem action='insert-face-smile-big'/>
+        <menuitem action='insert-face-plain'/>
+        <menuitem action='insert-smiley-9'/>
+        <menuitem action='insert-face-raspberry'/>
+        <menuitem action='insert-face-crying'/>
+        <menuitem action='insert-smiley-26'/>
+      </menu>
+    </menu>
+    <placeholder name='pre-format-menu'/>
+    <menu action='format-menu'>
+      <menuitem action='html-mode'/>
+      <separator/>
+      <menu action='font-style-menu'>
+        <menuitem action='monospaced'/>
+        <separator/>
+        <menuitem action='bold'/>
+        <menuitem action='italic'/>
+        <menuitem action='underline'/>
+        <menuitem action='strikethrough'/>
+      </menu>
+      <menu action='font-size-menu'>
+        <menuitem action='size-minus-two'/>
+        <menuitem action='size-minus-one'/>
+        <menuitem action='size-plus-zero'/>
+        <menuitem action='size-plus-one'/>
+        <menuitem action='size-plus-two'/>
+        <menuitem action='size-plus-three'/>
+        <menuitem action='size-plus-four'/>
+      </menu>
+      <menuitem action='properties-text'/>
+      <separator/>
+      <menu action='heading-menu'>
+        <menuitem action='style-normal'/>
+        <separator/>
+        <menuitem action='style-h1'/>
+        <menuitem action='style-h2'/>
+        <menuitem action='style-h3'/>
+        <menuitem action='style-h4'/>
+        <menuitem action='style-h5'/>
+        <menuitem action='style-h6'/>
+        <separator/>
+        <menuitem action='style-list-bullet'/>
+        <menuitem action='style-list-roman'/>
+        <menuitem action='style-list-number'/>
+        <menuitem action='style-list-alpha'/>
+        <separator/>
+        <menuitem action='style-address'/>
+        <menuitem action='style-preformat'/>
+      </menu>
+      <menu action='justify-menu'>
+        <menuitem action='justify-left'/>
+        <menuitem action='justify-center'/>
+        <menuitem action='justify-right'/>
+      </menu>
+      <menuitem action='properties-paragraph'/>
+      <separator/>
+      <menuitem action='indent'/>
+      <menuitem action='unindent'/>
+      <menuitem action='wrap-lines'/>
+      <separator/>
+      <menuitem action='properties-page'/>
+    </menu>
+  </menubar>
+  <toolbar name='main-toolbar'>
+    <placeholder name='pre-main-toolbar'/>
+    <toolitem action='undo'/>
+    <toolitem action='redo'/>
+    <separator/>
+    <toolitem action='cut'/>
+    <toolitem action='copy'/>
+    <toolitem action='paste'/>
+    <separator/>
+    <toolitem action='show-find'/>
+    <toolitem action='show-replace'/>
+    <separator/>
+    <toolitem action='insert-image'/>
+    <toolitem action='insert-link'/>
+    <toolitem action='insert-rule'/>
+    <toolitem action='insert-table'/>
+  </toolbar>
+  <toolbar name='edit-toolbar'>
+    <toolitem action='monospaced'/>
+    <toolitem action='bold'/>
+    <toolitem action='italic'/>
+    <toolitem action='underline'/>
+    <toolitem action='strikethrough'/>
+    <separator/>
+    <toolitem action='justify-left'/>
+    <toolitem action='justify-center'/>
+    <toolitem action='justify-right'/>
+    <separator/>
+    <toolitem action='unindent'/>
+    <toolitem action='indent'/>
+  </toolbar>
+  <popup name='context-menu'>
+    <menuitem action='undo'/>
+    <menuitem action='redo'/>
+    <separator/>
+    <menuitem action='cut'/>
+    <menuitem action='copy'/>
+    <menuitem action='paste'/>
+    <menuitem action='paste-quote'/>
+    <separator/>
+    <menuitem action='context-insert-link'/>
+    <menuitem action='context-remove-link'/>
+    <separator/>
+    <menu action='context-properties-menu'>
+      <menuitem action='context-properties-text'/>
+      <menuitem action='context-properties-link'/>
+      <menuitem action='context-properties-rule'/>
+      <menuitem action='context-properties-image'/>
+      <menuitem action='context-properties-paragraph'/>
+      <menuitem action='context-properties-cell'/>
+      <menuitem action='context-properties-table'/>
+      <menuitem action='context-properties-page'/>
+    </menu>
+    <separator/>
+    <menu action='context-insert-table-menu'>
+      <menuitem action='context-insert-table'/>
+      <separator/>
+      <menuitem action='context-insert-row-above'/>
+      <menuitem action='context-insert-row-below'/>
+      <separator/>
+      <menuitem action='context-insert-column-before'/>
+      <menuitem action='context-insert-column-after'/>
+    </menu>
+    <menu action='context-delete-table-menu'>
+      <menuitem action='context-delete-table'/>
+      <menuitem action='context-delete-row'/>
+      <menuitem action='context-delete-column'/>
+      <menuitem action='context-delete-cell'/>
+    </menu>
+    <separator/>
+    <placeholder name='context-spell-suggest'/>
+    <separator/>
+    <menuitem action='context-spell-ignore'/>
+    <menu action='context-spell-add-menu'/>
+    <menuitem action='context-spell-add'/>
+    <separator/>
+    <menu action='context-input-methods-menu'/>
+  </popup>
+</ui>
Index: components/editor/gtkhtml-editor-actions.c
===================================================================
--- components/editor/gtkhtml-editor-actions.c	(revision 0)
+++ components/editor/gtkhtml-editor-actions.c	(revision 0)
@@ -0,0 +1,2385 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-actions.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-editor-private.h"
+
+#include <libgnome/gnome-url.h>
+
+/******************************************************************************
+ * Action Group Quick Reference
+ *
+ * Action callbacks are usually named after their actions.
+ * e.g. "frobnicate-text" -> action_frobnicate_text_cb()
+ *
+ * Core Actions
+ * ------------
+ * "confirm-replace"
+ * "confirm-replace-all"
+ * "confirm-replace-cancel"
+ * "confirm-replace-next"
+ * "copy"
+ * "cut"
+ * "find"
+ * "find-again"
+ * "find-and-replace"
+ * "html-mode"		(toggle)
+ * "indent"
+ * "insert-html-file"
+ * "insert-smiley-1"
+ * "insert-smiley-10"
+ * "insert-smiley-11"
+ * "insert-smiley-2"
+ * "insert-smiley-26"
+ * "insert-smiley-3"
+ * "insert-smiley-4"
+ * "insert-smiley-5"
+ * "insert-smiley-6"
+ * "insert-smiley-8"
+ * "insert-smiley-9"
+ * "insert-table"
+ * "insert-text-file"
+ * "justify-center"	(radio)
+ * "justify-left"	(radio)
+ * "justify-right"	(radio)
+ * "paste"
+ * "paste-quote"
+ * "properties-paragraph"
+ * "redo"
+ * "select-all"
+ * "show-find"
+ * "show-replace"
+ * "spell-check"
+ * "style-address"	(radio)
+ * "style-h1"		(radio)
+ * "style-h2"		(radio)
+ * "style-h3"		(radio)
+ * "style-h4"		(radio)
+ * "style-h5"		(radio)
+ * "style-h6"		(radio)
+ * "style-list-alpha"	(radio)
+ * "style-list-bullet"	(radio)
+ * "style-list-number"	(radio)
+ * "style-list-roman"	(radio)
+ * "style-normal"	(radio)
+ * "style-preformat"	(radio)
+ * "test-url"
+ * "undo"
+ * "unindent"
+ * "wrap-lines"
+ *
+ * Core Actions (HTML Only)
+ * ------------------------
+ * "bold"		(toggle)
+ * "properties-page"
+ * "properties-text"
+ * "insert-image"
+ * "insert-link"
+ * "insert-rule"
+ * "insert-table"
+ * "italic"		(toggle)
+ * "monospaced"		(toggle)
+ * "size-minus-one"	(radio)
+ * "size-minus-two"	(radio)
+ * "size-plus-four"	(radio)
+ * "size-plus-one"	(radio)
+ * "size-plus-three"	(radio)
+ * "size-plus-two"	(radio)
+ * "size-plus-zero"	(radio)
+ * "strikethrough"	(toggle)
+ * "underline"		(toggle)
+ *
+ * Context Menu Actions
+ * --------------------
+ * "context-delete-cell"
+ * "context-delete-column"
+ * "context-delete-row"
+ * "context-delete-table"
+ *
+ * Context Menu Actions (HTML only)
+ * --------------------------------
+ * "context-insert-column-after"
+ * "context-insert-column-before"
+ * "context-insert-link"
+ * "context-insert-row-above"
+ * "context-insert-row-below"
+ * "context-insert-table"
+ * "context-properties-cell"
+ * "context-properties-image"
+ * "context-properties-link"
+ * "context-properties-page"
+ * "context-properties-paragraph"
+ * "context-properties-rule"
+ * "context-properties-table"
+ * "context-properties-text"
+ * "context-remove-link"
+ *
+ * Context Menu Actions (spell check only)
+ * ---------------------------------------
+ * "context-spell-add"
+ * "context-spell-ignore"
+ *
+ *****************************************************************************/
+
+static void
+insert_image_response_cb (GtkFileChooser *file_chooser,
+                          gint response,
+                          GtkhtmlEditor *editor)
+{
+	HTMLObject *image;
+	GtkHTML *html;
+	gchar *uri;
+
+	if (response != GTK_RESPONSE_OK)
+		return;
+
+	html = gtkhtml_editor_get_html (editor);
+	uri = gtk_file_chooser_get_uri (file_chooser);
+	image = html_image_new (
+		html_engine_get_image_factory (html->engine), uri,
+		NULL, NULL, 0, 0, 0, 0, 0, NULL, HTML_VALIGN_NONE, FALSE);
+	html_engine_paste_object (html->engine, image, 1);
+	g_free (uri);
+}
+
+static void
+insert_html_file_response_cb (GtkFileChooser *file_chooser,
+                              gint response,
+                              GtkhtmlEditor *editor)
+{
+	gchar *filename;
+	gchar *contents;
+	gsize length;
+	GError *error = NULL;
+
+	if (response != GTK_RESPONSE_OK)
+		return;
+
+	filename = gtk_file_chooser_get_filename (file_chooser);
+
+	/* Assume the file encoding is UTF-8. */
+	gtkhtml_editor_get_file_contents (
+		filename, NULL, &contents, &length, &error);
+
+	/* If we get a conversion error, look for a charset and try again. */
+	if (error != NULL && g_error_matches (error, G_CONVERT_ERROR,
+		G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) {
+
+		gchar *charset;
+
+		charset = gtkhtml_editor_get_file_charset (filename);
+		if (charset != NULL) {
+			g_clear_error (&error);
+			gtkhtml_editor_get_file_contents (
+				filename, charset, &contents, &length, &error);
+			g_free (charset);
+		}
+	}
+
+	if (error == NULL) {
+		GtkHTML *html;
+		GtkHTMLStream *stream;
+
+		html = GTK_HTML (gtk_html_new ());
+		stream = gtk_html_begin_content (
+			html, "text/html; charset=utf-8");
+		gtk_html_write (html, stream, contents, length);
+		gtk_html_end (html, stream, GTK_HTML_STREAM_OK);
+		gtk_html_insert_gtk_html (
+			gtkhtml_editor_get_html (editor), html);
+		g_free (contents);
+	} else {
+		/* XXX Show an error dialog. */
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+
+	g_free (filename);
+}
+
+static void
+insert_emoticon (GtkhtmlEditor *editor,
+                 GtkAction *action,
+                 const gchar *alt)
+{
+	GtkHTML *html;
+	HTMLObject *image;
+	GtkIconInfo *icon_info;
+	const gchar *filename;
+	gchar *icon_name;
+	gchar *uri = NULL;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	g_object_get (action, "icon-name", &icon_name, NULL);
+	icon_info = gtk_icon_theme_lookup_icon (
+		gtk_icon_theme_get_default (), icon_name, 16, 0);
+	g_free (icon_name);
+	g_return_if_fail (icon_info != NULL);
+
+	filename = gtk_icon_info_get_filename (icon_info);
+	if (filename != NULL)
+		uri = g_filename_to_uri (filename, NULL, NULL);
+	gtk_icon_info_free (icon_info);
+	g_return_if_fail (uri != NULL);
+
+	image = html_image_new (
+		html_engine_get_image_factory (html->engine),
+		uri, NULL, NULL, -1, -1, FALSE, FALSE, 0, NULL,
+		HTML_VALIGN_MIDDLE, FALSE);
+	html_image_set_alt (HTML_IMAGE (image), alt);
+	html_engine_paste_object (
+		html->engine, image, html_object_get_length (image));
+
+	g_free (uri);
+}
+
+static void
+insert_text_file_response_cb (GtkFileChooser *file_chooser,
+                              gint response,
+                              GtkhtmlEditor *editor)
+{
+	gchar *contents;
+	gchar *filename;
+	gsize length;
+	GError *error = NULL;
+
+	if (response != GTK_RESPONSE_OK)
+		return;
+
+	filename = gtk_file_chooser_get_filename (file_chooser);
+
+	/* Assume the file encoding is UTF-8. */
+	gtkhtml_editor_get_file_contents (
+		filename, NULL, &contents, &length, &error);
+
+	/* If we get a conversion error, look for a charset and try again. */
+	if (error != NULL && g_error_matches (error, G_CONVERT_ERROR,
+		G_CONVERT_ERROR_ILLEGAL_SEQUENCE)) {
+
+		gchar *charset;
+
+		charset = gtkhtml_editor_get_file_charset (filename);
+		if (charset != NULL) {
+			g_clear_error (&error);
+			gtkhtml_editor_get_file_contents (
+				filename, charset, &contents, &length, &error);
+			g_free (charset);
+		}
+	}
+
+	if (error == NULL) {
+		GtkHTML *html;
+
+		html = gtkhtml_editor_get_html (editor);
+		html_engine_paste_text (html->engine, contents, length);
+		g_free (contents);
+	} else {
+		/* XXX Show an error dialog. */
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+
+	g_free (filename);
+}
+
+static void
+replace_ask_cb (HTMLEngine *engine,
+                gpointer data)
+{
+	GtkhtmlEditor *editor = data;
+
+	gtk_window_present (GTK_WINDOW (WIDGET (REPLACE_CONFIRMATION_WINDOW)));
+}
+
+static void
+replace_answer (GtkhtmlEditor *editor,
+                HTMLReplaceQueryAnswer answer)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	if (html_engine_replace_do (html->engine, answer))
+		gtk_widget_hide (WIDGET (REPLACE_CONFIRMATION_WINDOW));
+}
+
+/*****************************************************************************
+ * Action Callbacks
+ *****************************************************************************/
+
+static void
+action_bold_cb (GtkToggleAction *action,
+                GtkhtmlEditor *editor)
+{
+	const gchar *command;
+
+	if (gtk_toggle_action_get_active (action))
+		command = "bold-on";
+	else
+		command = "bold-off";
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_confirm_replace_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	replace_answer (editor, RQA_Replace);
+}
+
+static void
+action_confirm_replace_all_cb (GtkAction *action,
+                               GtkhtmlEditor *editor)
+{
+	replace_answer (editor, RQA_ReplaceAll);
+}
+
+static void
+action_confirm_replace_cancel_cb (GtkAction *action,
+                                  GtkhtmlEditor *editor)
+{
+	replace_answer (editor, RQA_Cancel);
+}
+
+static void
+action_confirm_replace_next_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	replace_answer (editor, RQA_Next);
+}
+
+static void
+action_context_delete_cell_cb (GtkAction *action,
+                               GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_command (html, "delete-cell-contents");
+}
+
+static void
+action_context_delete_column_cb (GtkAction *action,
+                                 GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_command (html, "delete-table-column");
+}
+
+static void
+action_context_delete_row_cb (GtkAction *action,
+                              GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_command (html, "delete-table-row");
+}
+
+static void
+action_context_delete_table_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_command (html, "delete-table");
+}
+
+static void
+action_context_insert_column_after_cb (GtkAction *action,
+                                       GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_insert_table_column (html->engine, TRUE);
+}
+
+static void
+action_context_insert_column_before_cb (GtkAction *action,
+                                        GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_insert_table_column (html->engine, FALSE);
+}
+
+static void
+action_context_insert_row_above_cb (GtkAction *action,
+                                    GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_insert_table_row (html->engine, FALSE);
+}
+
+static void
+action_context_insert_row_below_cb (GtkAction *action,
+                                    GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_insert_table_row (html->engine, TRUE);
+}
+
+static void
+action_context_remove_link_cb (GtkAction *action,
+                               GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_selection_push (html->engine);
+	if (!html_engine_is_selection_active (html->engine))
+		html_engine_select_word_editable (html->engine);
+	html_engine_set_link (html->engine, NULL);
+	html_engine_selection_pop (html->engine);
+}
+
+static void
+action_context_spell_add_cb (GtkAction *action,
+                             GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	GtkhtmlSpellChecker *checker;
+	GList *active_spell_checkers;
+	const gchar *action_name;
+	gchar *word;
+
+	/* XXX This is messy.  We have to extract the language code from
+	 *     the action's name to know which dictionary to add the word
+	 *     to.  The action's name is either "context-spell-add-CODE"
+	 *     or "context-spell-add" if only one language is selected. */
+
+	html = gtkhtml_editor_get_html (editor);
+	action_name = gtk_action_get_name (action);
+	active_spell_checkers = editor->priv->active_spell_checkers;
+	g_return_if_fail (active_spell_checkers != NULL);
+
+	/* Note: len("context-spell-add-") == 18 */
+	if (g_str_equal (action_name, "context-spell-add-")) {
+		const gchar *language_code = action_name + 18;
+
+		checker = g_hash_table_lookup (
+			editor->priv->available_spell_checkers,
+			gtkhtml_spell_language_lookup (language_code));
+	} else
+		checker = active_spell_checkers->data;
+	g_return_if_fail (checker != NULL);
+
+	word = html_engine_get_spell_word (html->engine);
+	g_return_if_fail (word != NULL);
+
+	gtkhtml_spell_checker_add_word (checker, word, -1);
+	html_engine_spell_check (html->engine);
+
+	g_free (word);
+}
+
+static void
+action_context_spell_ignore_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	GtkhtmlSpellChecker *checker;
+	GList *active_spell_checkers;
+	GtkHTML *html;
+	gchar *word;
+
+	/* XXX This action gets fired by choosing "Ignore Misspelled Word"
+	 *     through the pop-up context menu.  Problem is, if multiple
+	 *     languages are enabled we don't know which dictionary to
+	 *     add the word to (for this session).  A reasonable heuristic
+	 *     is to first see if the dictionary for the current locale is
+	 *     enabled.  If not, then pick the first enabled dictionary. */
+
+	active_spell_checkers = editor->priv->active_spell_checkers;
+	g_return_if_fail (active_spell_checkers != NULL);
+
+	/* Find a spell checker to add the word to. */
+	if (g_list_length (active_spell_checkers) == 1)
+		checker = active_spell_checkers->data;
+	else {
+		checker = g_hash_table_lookup (
+			editor->priv->available_spell_checkers,
+			gtkhtml_spell_language_lookup (NULL));
+		if (g_list_find (active_spell_checkers, checker) == NULL)
+			checker = active_spell_checkers->data;
+	}
+
+	html = gtkhtml_editor_get_html (editor);
+	word = html_engine_get_spell_word (html->engine);
+	g_return_if_fail (word != NULL);
+
+	gtkhtml_spell_checker_add_word_to_session (checker, word, -1);
+	html_engine_spell_check (html->engine);
+
+	g_free (word);
+}
+
+static void
+action_copy_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorClass *class;
+
+	class = GTKHTML_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->copy_clipboard != NULL);
+	class->copy_clipboard (editor);
+}
+
+static void
+action_cut_cb (GtkAction *action,
+               GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorClass *class;
+
+	class = GTKHTML_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->cut_clipboard != NULL);
+	class->cut_clipboard (editor);
+}
+
+static void
+action_find_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	gboolean found;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	found = html_engine_search (
+		html->engine,
+		gtk_entry_get_text (GTK_ENTRY (WIDGET (FIND_ENTRY))),
+		gtk_toggle_button_get_active (
+			GTK_TOGGLE_BUTTON (WIDGET (FIND_CASE_SENSITIVE))),
+		!gtk_toggle_button_get_active (
+			GTK_TOGGLE_BUTTON (WIDGET (FIND_BACKWARDS))),
+		gtk_toggle_button_get_active (
+			GTK_TOGGLE_BUTTON (WIDGET (FIND_REGULAR_EXPRESSION))));
+
+	gtk_action_set_sensitive (ACTION (FIND), found);
+}
+
+static void
+action_find_again_cb (GtkAction *action,
+                      GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	if (html->engine->search_info != NULL)
+		html_engine_search_next (html->engine);
+	else
+		gtk_action_activate (ACTION (SHOW_FIND));
+}
+
+static void
+action_find_and_replace_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	gtk_widget_hide (WIDGET (REPLACE_WINDOW));
+
+	html_engine_replace (
+		html->engine,
+		gtk_entry_get_text (GTK_ENTRY (WIDGET (REPLACE_ENTRY))),
+		gtk_entry_get_text (GTK_ENTRY (WIDGET (REPLACE_WITH_ENTRY))),
+		gtk_toggle_button_get_active (
+			GTK_TOGGLE_BUTTON (WIDGET (REPLACE_CASE_SENSITIVE))),
+		!gtk_toggle_button_get_active (
+			GTK_TOGGLE_BUTTON (WIDGET (REPLACE_BACKWARDS))),
+		FALSE, replace_ask_cb, editor);
+}
+
+static void
+action_html_mode_cb (GtkToggleAction *action,
+                     GtkhtmlEditor *editor)
+{
+	GtkActionGroup *action_group;
+	HTMLPainter *new_painter;
+	HTMLPainter *old_painter;
+	GtkHTML *html;
+	gboolean active;
+
+	html = gtkhtml_editor_get_html (editor);
+	active = gtk_toggle_action_get_active (action);
+
+	action_group = editor->priv->html_actions;
+	gtk_action_group_set_sensitive (action_group, active);
+
+	action_group = editor->priv->html_context_actions;
+	gtk_action_group_set_visible (action_group, active);
+
+	/* Certain paragraph styles are HTML-only. */
+	gtk_action_set_sensitive (ACTION (STYLE_H1), active);
+	gtk_action_set_sensitive (ACTION (STYLE_H2), active);
+	gtk_action_set_sensitive (ACTION (STYLE_H3), active);
+	gtk_action_set_sensitive (ACTION (STYLE_H4), active);
+	gtk_action_set_sensitive (ACTION (STYLE_H5), active);
+	gtk_action_set_sensitive (ACTION (STYLE_H6), active);
+	gtk_action_set_sensitive (ACTION (STYLE_ADDRESS), active);
+
+	/* Swap painters. */
+
+	if (active) {
+		new_painter = editor->priv->html_painter;
+		old_painter = editor->priv->plain_painter;
+	} else {
+		new_painter = editor->priv->plain_painter;
+		old_painter = editor->priv->html_painter;
+	}
+
+	/* Might be true during initialization. */
+	if (html->engine->painter == new_painter)
+		return;
+
+	html_gdk_painter_unrealize (HTML_GDK_PAINTER (old_painter));
+	if (html->engine->window != NULL)
+		html_gdk_painter_realize (
+			HTML_GDK_PAINTER (new_painter),
+			html->engine->window);
+
+	html_font_manager_set_default (
+		&new_painter->font_manager,
+		old_painter->font_manager.variable.face,
+		old_painter->font_manager.fixed.face,
+		old_painter->font_manager.var_size,
+		old_painter->font_manager.var_points,
+		old_painter->font_manager.fix_size,
+		old_painter->font_manager.fix_points);
+
+	html_engine_set_painter (html->engine, new_painter);
+	html_engine_schedule_redraw (html->engine);
+}
+
+static void
+action_indent_cb (GtkAction *action,
+                  GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "indent-more");
+}
+
+static void
+action_insert_html_file_cb (GtkToggleAction *action,
+                            GtkhtmlEditor *editor)
+{
+	gtkhtml_editor_insert_file (
+		editor, _("Insert HTML File"),
+		G_CALLBACK (insert_html_file_response_cb));
+}
+
+static void
+action_insert_image_cb (GtkAction *action,
+                        GtkhtmlEditor *editor)
+{
+	gtkhtml_editor_insert_file (
+		editor, _("Insert Image"),
+		G_CALLBACK (insert_image_response_cb));
+}
+
+static void
+action_insert_link_cb (GtkAction *action,
+                       GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (LINK_PROPERTIES_WINDOW)));
+}
+
+static void
+action_insert_rule_cb (GtkAction *action,
+                       GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	/* Defaults: Width: 100%  Size: 2  Unshaded  Left-Aligned */
+	html_engine_insert_rule (
+		html->engine, 0, 100, 2, FALSE, HTML_HALIGN_LEFT);
+
+	gtk_action_activate (ACTION (PROPERTIES_RULE));
+}
+
+static void
+action_insert_face_angel_cb (GtkAction *action,
+                             GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, "O:-)");
+}
+
+static void
+action_insert_face_cool_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, "B-)");
+}
+
+static void
+action_insert_face_crying_cb (GtkAction *action,
+                              GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":'(");
+}
+
+static void
+action_insert_face_devilish_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ">:-)");
+}
+
+static void
+action_insert_face_embarrassed_cb (GtkAction *action,
+                                   GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":\"-)");
+}
+
+static void
+action_insert_face_kiss_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-*");
+}
+
+static void
+action_insert_face_monkey_cb (GtkAction *action,
+                              GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-(|)");
+}
+
+static void
+action_insert_face_plain_cb (GtkAction *action,
+                             GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-|");
+}
+
+static void
+action_insert_face_raspberry_cb (GtkAction *action,
+                                 GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-P");
+}
+
+static void
+action_insert_face_sad_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-(");
+}
+
+static void
+action_insert_face_smile_cb (GtkAction *action,
+                             GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-)");
+}
+
+static void
+action_insert_face_smile_big_cb (GtkAction *action,
+                                 GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-D");
+}
+
+static void
+action_insert_face_smirk_cb (GtkAction *action,
+                             GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-!");
+}
+
+static void
+action_insert_face_surprise_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-O");
+}
+
+static void
+action_insert_face_wink_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ";-)");
+}
+
+static void
+action_insert_smiley_9_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-/");
+}
+
+static void
+action_insert_smiley_26_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	insert_emoticon (editor, action, ":-Q");
+}
+
+static void
+action_insert_table_cb (GtkAction *action,
+                        GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	/* Default: 3 x 3 table */
+	html_engine_insert_table_1_1 (html->engine);
+	html_engine_table_set_cols (html->engine, 3);
+	html_engine_table_set_rows (html->engine, 3);
+
+	gtk_action_activate (ACTION (PROPERTIES_TABLE));
+}
+
+static void
+action_insert_text_file_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	gtkhtml_editor_insert_file (
+		editor, _("Insert Text File"),
+		G_CALLBACK (insert_text_file_response_cb));
+}
+
+static void
+action_italic_cb (GtkToggleAction *action,
+                  GtkhtmlEditor *editor)
+{
+	const gchar *command;
+
+	if (gtk_toggle_action_get_active (action))
+		command = "italic-on";
+	else
+		command = "italic-off";
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_justify_cb (GtkRadioAction *action,
+                   GtkRadioAction *current,
+                   GtkhtmlEditor *editor)
+{
+	const gchar *command = NULL;
+
+	switch (gtk_radio_action_get_current_value (current))
+	{
+		case GTK_HTML_PARAGRAPH_ALIGNMENT_CENTER:
+			command = "align-center";
+			break;
+
+		case GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT:
+			command = "align-left";
+			break;
+
+		case GTK_HTML_PARAGRAPH_ALIGNMENT_RIGHT:
+			command = "align-right";
+			break;
+	}
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_language_cb (GtkToggleAction *action,
+                    GtkhtmlEditor *editor)
+{
+	const GtkhtmlSpellLanguage *language;
+	GtkhtmlSpellChecker *checker;
+	const gchar *language_code;
+	GtkAction *add_action;
+	GList *list;
+	guint length;
+	gchar *action_name;
+	gboolean active;
+
+	active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+	language_code = gtk_action_get_name (GTK_ACTION (action));
+	language = gtkhtml_spell_language_lookup (language_code);
+
+	checker = g_hash_table_lookup (
+		editor->priv->available_spell_checkers, language);
+	g_return_if_fail (checker != NULL);
+
+	/* Update the list of active spell checkers. */
+	list = editor->priv->active_spell_checkers;
+	if (active)
+		list = g_list_insert_sorted (
+			list, g_object_ref (checker),
+			(GCompareFunc) gtkhtml_spell_checker_compare);
+	else {
+		GList *link;
+
+		link = g_list_find (list, checker);
+		g_return_if_fail (link != NULL);
+		list = g_list_delete_link (list, link);
+		g_object_unref (checker);
+	}
+	editor->priv->active_spell_checkers = list;
+	length = g_list_length (list);
+
+	/* Update "Add Word To" context menu item visibility. */
+	action_name = g_strdup_printf ("context-spell-add-%s", language_code);
+	add_action = gtkhtml_editor_get_action (editor, action_name);
+	gtk_action_set_visible (add_action, active);
+	g_free (action_name);
+
+	gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD), length == 1);
+	gtk_action_set_visible (ACTION (CONTEXT_SPELL_ADD_MENU), length > 1);
+	gtk_action_set_visible (ACTION (CONTEXT_SPELL_IGNORE), length > 0);
+
+	gtk_action_set_sensitive (ACTION (SPELL_CHECK), length > 0);
+}
+
+static void
+action_monospaced_cb (GtkToggleAction *action,
+                      GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	GtkHTMLFontStyle and_mask;
+	GtkHTMLFontStyle or_mask;
+
+	if (gtk_toggle_action_get_active (action)) {
+		and_mask = GTK_HTML_FONT_STYLE_MAX;
+		or_mask = GTK_HTML_FONT_STYLE_FIXED;
+	} else {
+		and_mask = ~GTK_HTML_FONT_STYLE_FIXED;
+		or_mask = 0;
+	}
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_set_font_style (html, and_mask, or_mask);
+}
+
+static void
+action_paste_cb (GtkAction *action,
+                 GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorClass *class;
+
+	class = GTKHTML_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->paste_clipboard != NULL);
+	class->paste_clipboard (editor);
+}
+
+static void
+action_paste_quote_cb (GtkAction *action,
+                       GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_paste (html, TRUE);
+}
+
+static void
+action_properties_cell_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (CELL_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_image_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (IMAGE_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_link_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (LINK_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_page_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (PAGE_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_paragraph_cb (GtkAction *action,
+                                GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (PARAGRAPH_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_rule_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (RULE_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_table_cb (GtkAction *action,
+                            GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (TABLE_PROPERTIES_WINDOW)));
+}
+
+static void
+action_properties_text_cb (GtkAction *action,
+                           GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (TEXT_PROPERTIES_WINDOW)));
+}
+
+static void
+action_style_cb (GtkRadioAction *action,
+                 GtkRadioAction *current,
+                 GtkhtmlEditor *editor)
+{
+	const gchar *command = NULL;
+
+	switch (gtk_radio_action_get_current_value (current)) {
+		case GTK_HTML_PARAGRAPH_STYLE_NORMAL:
+			command = "style-normal";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H1:
+			command = "style-header1";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H2:
+			command = "style-header2";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H3:
+			command = "style-header3";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H4:
+			command = "style-header4";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H5:
+			command = "style-header5";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_H6:
+			command = "style-header6";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_ADDRESS:
+			command = "style-address";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_PRE:
+			command = "style-pre";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED:
+			command = "style-itemdot";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_ITEMROMAN:
+			command = "style-itemroman";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_ITEMDIGIT:
+			command = "style-itemdigit";
+			break;
+		case GTK_HTML_PARAGRAPH_STYLE_ITEMALPHA:
+			command = "style-itemalpha";
+			break;
+	}
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_redo_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "redo");
+}
+
+static void
+action_select_all_cb (GtkAction *action,
+                      GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorClass *class;
+
+	class = GTKHTML_EDITOR_GET_CLASS (editor);
+	g_return_if_fail (class->select_all != NULL);
+	class->select_all (editor);
+}
+
+static void
+action_show_find_cb (GtkAction *action,
+                     GtkhtmlEditor *editor)
+{
+	gtk_widget_set_sensitive (WIDGET (FIND_BUTTON), TRUE);
+
+	gtk_window_present (GTK_WINDOW (WIDGET (FIND_WINDOW)));
+}
+
+static void
+action_show_replace_cb (GtkAction *action,
+                        GtkhtmlEditor *editor)
+{
+	gtk_window_present (GTK_WINDOW (WIDGET (REPLACE_WINDOW)));
+}
+
+static void
+action_size_cb (GtkRadioAction *action,
+                GtkRadioAction *current,
+                GtkhtmlEditor *editor)
+{
+	const gchar *command = NULL;
+
+	switch (gtk_radio_action_get_current_value (current)) {
+		case GTK_HTML_FONT_STYLE_SIZE_1:
+			command = "size-minus-2";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_2:
+			command = "size-minus-1";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_3:
+			command = "size-plus-0";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_4:
+			command = "size-plus-1";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_5:
+			command = "size-plus-2";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_6:
+			command = "size-plus-3";
+			break;
+		case GTK_HTML_FONT_STYLE_SIZE_7:
+			command = "size-plus-4";
+			break;
+	}
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_spell_check_cb (GtkAction *action,
+                       GtkhtmlEditor *editor)
+{
+	gtkhtml_editor_spell_check (editor, TRUE);
+}
+
+static void
+action_strikethrough_cb (GtkToggleAction *action,
+                         GtkhtmlEditor *editor)
+{
+	const gchar *command;
+
+	if (gtk_toggle_action_get_active (action))
+		command = "strikeout-on";
+	else
+		command = "strikeout-off";
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_test_url_cb (GtkAction *action,
+                    GtkhtmlEditor *editor)
+{
+	const gchar *text;
+
+	text = gtk_entry_get_text (
+		GTK_ENTRY (WIDGET (LINK_PROPERTIES_URL_ENTRY)));
+
+	if (text != NULL && *text != '\0')
+		gnome_url_show (text, NULL);
+}
+
+static void
+action_underline_cb (GtkToggleAction *action,
+                     GtkhtmlEditor *editor)
+{
+	const gchar *command;
+
+	if (gtk_toggle_action_get_active (action))
+		command = "underline-on";
+	else
+		command = "underline-off";
+
+	gtk_html_command (gtkhtml_editor_get_html (editor), command);
+}
+
+static void
+action_undo_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "undo");
+}
+
+static void
+action_unindent_cb (GtkAction *action,
+                    GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "indent-less");
+}
+
+static void
+action_wrap_lines_cb (GtkAction *action,
+                      GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "indent-paragraph");
+}
+
+/*****************************************************************************
+ * Core Actions
+ *
+ * These actions are always enabled.
+ *****************************************************************************/
+
+static GtkActionEntry core_entries[] = {
+
+	{ "confirm-replace",
+	  NULL,
+	  N_("_Replace"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_confirm_replace_cb) },
+
+	{ "confirm-replace-all",
+	  NULL,
+	  N_("Replace _All"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_confirm_replace_all_cb) },
+
+	{ "confirm-replace-cancel",
+	  GTK_STOCK_CLOSE,
+	  NULL,
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_confirm_replace_cancel_cb) },
+
+	{ "confirm-replace-next",
+	  NULL,
+	  N_("_Next"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_confirm_replace_next_cb) },
+
+	{ "copy",
+	  GTK_STOCK_COPY,
+	  N_("_Copy"),
+	  "<Control>c",
+	  NULL,
+	  G_CALLBACK (action_copy_cb) },
+
+	{ "cut",
+	  GTK_STOCK_CUT,
+	  N_("Cu_t"),
+	  "<Control>x",
+	  NULL,
+	  G_CALLBACK (action_cut_cb) },
+
+	{ "find",
+	  GTK_STOCK_FIND,
+	  NULL,
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_find_cb) },
+
+	{ "find-again",
+	  NULL,
+	  N_("Find A_gain"),
+	  "<Control>g",
+	  NULL,
+	  G_CALLBACK (action_find_again_cb) },
+
+	{ "find-and-replace",
+	  GTK_STOCK_FIND_AND_REPLACE,
+	  NULL,
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_find_and_replace_cb) },
+
+	{ "indent",
+	  GTK_STOCK_INDENT,
+	  N_("_Increase Indent"),
+	  "<Control>bracketleft",
+	  NULL,
+	  G_CALLBACK (action_indent_cb) },
+
+	{ "insert-html-file",
+	  NULL,
+	  N_("_HTML File..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_html_file_cb) },
+
+	{ "insert-face-angel",
+	  "face-angel",
+	  N_("_Angel"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_angel_cb) },
+
+	{ "insert-face-cool",
+	  "face-cool",
+	  N_("_Cool"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_cool_cb) },
+
+	{ "insert-face-crying",
+	  "face-crying",
+	  N_("Cr_ying"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_crying_cb) },
+
+	{ "insert-face-devilish",
+	  "face-devilish",
+	  N_("_Devilish"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_devilish_cb) },
+
+	{ "insert-face-embarrassed",
+	  "face-embarrassed",
+	  N_("_Embarrassed"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_embarrassed_cb) },
+
+	{ "insert-face-kiss",
+	  "face-kiss",
+	  N_("_Kiss"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_kiss_cb) },
+
+	{ "insert-face-monkey",
+	  "face-monkey",
+	  N_("_Monkey"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_monkey_cb) },
+
+	{ "insert-face-plain",
+	  "face-plain",
+	  N_("_Indifferent"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_plain_cb) },
+
+	{ "insert-face-raspberry",
+	  "face-raspberry",
+	  N_("_Tongue"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_raspberry_cb) },
+
+	{ "insert-face-sad",
+	  "face-sad",
+	  N_("_Frown"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_sad_cb) },
+
+	{ "insert-face-smile",
+	  "face-smile",
+	  N_("_Smile"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_smile_cb) },
+
+	{ "insert-face-smile-big",
+	  "face-smile-big",
+	  N_("_Laughing"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_smile_big_cb) },
+
+	{ "insert-face-smirk",
+	  "face-smirk",
+	  N_("Smi_rk"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_smirk_cb) },
+
+	{ "insert-face-surprise",
+	  "face-surprise",
+	  N_("Sur_prised"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_surprise_cb) },
+
+	{ "insert-face-wink",
+	  "face-wink",
+	  N_("_Wink"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_face_wink_cb) },
+
+	{ "insert-smiley-9",
+	  "stock_smiley-9",
+	  N_("_Undecided"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_smiley_9_cb) },
+
+	{ "insert-smiley-26",
+	  "stock_smiley-26",
+	  N_("S_ick"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_smiley_26_cb) },
+
+	{ "insert-text-file",
+	  NULL,
+	  N_("Te_xt File..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_text_file_cb) },
+
+	{ "paste",
+	  GTK_STOCK_PASTE,
+	  N_("_Paste"),
+	  "<Control>v",
+	  NULL,
+	  G_CALLBACK (action_paste_cb) },
+
+	{ "paste-quote",
+	  NULL,
+	  N_("Paste _Quotation"),
+	  "<Shift><Control>v",
+	  NULL,
+	  G_CALLBACK (action_paste_quote_cb) },
+
+	{ "properties-paragraph",
+	  NULL,
+	  N_("_Paragraph..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_paragraph_cb) },
+
+	{ "redo",
+	  GTK_STOCK_REDO,
+	  N_("_Redo"),
+	  "<Shift><Control>z",
+	  NULL,
+	  G_CALLBACK (action_redo_cb) },
+
+	{ "select-all",
+	  GTK_STOCK_SELECT_ALL,
+	  N_("Select _All"),
+	  "<Control>a",
+	  NULL,
+	  G_CALLBACK (action_select_all_cb) },
+
+	{ "show-find",
+	  GTK_STOCK_FIND,
+	  N_("_Find..."),
+	  "<Control>f",
+	  NULL,
+	  G_CALLBACK (action_show_find_cb) },
+
+	{ "show-replace",
+	  GTK_STOCK_FIND_AND_REPLACE,
+	  N_("Re_place..."),
+	  "<Control>h",
+	  NULL,
+	  G_CALLBACK (action_show_replace_cb) },
+
+	{ "spell-check",
+	  GTK_STOCK_SPELL_CHECK,
+	  N_("Check _Spelling..."),
+	  "F7",
+	  NULL,
+	  G_CALLBACK (action_spell_check_cb) },
+
+	{ "test-url",
+	  NULL,
+	  N_("_Test URL..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_test_url_cb) },
+
+	{ "undo",
+	  GTK_STOCK_UNDO,
+	  N_("_Undo"),
+	  "<Control>z",
+	  NULL,
+	  G_CALLBACK (action_undo_cb) },
+
+	{ "unindent",
+	  GTK_STOCK_UNINDENT,
+	  N_("_Decrease Indent"),
+	  "<Control>bracketright",
+	  NULL,
+	  G_CALLBACK (action_unindent_cb) },
+
+	{ "wrap-lines",
+	  NULL,
+	  N_("_Wrap Lines"),
+	  "<Control>l",
+	  NULL,
+	  G_CALLBACK (action_wrap_lines_cb) },
+
+	/* Menus */
+
+	{ "edit-menu",
+	  NULL,
+	  N_("_Edit"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "file-menu",
+	  NULL,
+	  N_("_File"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "format-menu",
+	  NULL,
+	  N_("_Format"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "heading-menu",
+	  NULL,
+	  N_("_Heading"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "insert-face-menu",
+	  NULL,
+	  N_("_Emoticon"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "insert-menu",
+	  NULL,
+	  N_("_Insert"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "justify-menu",
+	  NULL,
+	  N_("_Alignment"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "language-menu",
+	  NULL,
+	  N_("_Current Languages"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "view-menu",
+	  NULL,
+	  N_("_View"),
+	  NULL,
+	  NULL,
+	  NULL }
+};
+
+static GtkToggleActionEntry core_toggle_entries[] = {
+
+	{ "html-mode",
+	  NULL,
+	  N_("HTML Mode"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_html_mode_cb),
+	  TRUE },
+};
+
+static GtkRadioActionEntry core_justify_entries[] = {
+
+	{ "justify-center",
+	  GTK_STOCK_JUSTIFY_CENTER,
+	  N_("_Center"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_ALIGNMENT_CENTER },
+
+	{ "justify-left",
+	  GTK_STOCK_JUSTIFY_LEFT,
+	  N_("_Left"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT },
+
+	{ "justify-right",
+	  GTK_STOCK_JUSTIFY_RIGHT,
+	  N_("_Right"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_ALIGNMENT_RIGHT }
+};
+
+static GtkRadioActionEntry core_style_entries[] = {
+
+	{ "style-normal",
+	  NULL,
+	  N_("_Normal"),
+	  "<Control>0",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_NORMAL },
+
+	{ "style-h1",
+	  NULL,
+	  N_("Header _1"),
+	  "<Control>1",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H1 },
+
+	{ "style-h2",
+	  NULL,
+	  N_("Header _2"),
+	  "<Control>2",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H2 },
+
+	{ "style-h3",
+	  NULL,
+	  N_("Header _3"),
+	  "<Control>3",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H3 },
+
+	{ "style-h4",
+	  NULL,
+	  N_("Header _4"),
+	  "<Control>4",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H4 },
+
+	{ "style-h5",
+	  NULL,
+	  N_("Header 5"),
+	  "<Control>5",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H5 },
+
+	{ "style-h6",
+	  NULL,
+	  N_("Header 6"),
+	  "<Control>6",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_H6 },
+
+	{ "style-address",
+	  NULL,
+	  N_("A_ddress"),
+	  "<Control>8",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_ADDRESS },
+
+	{ "style-preformat",
+	  NULL,
+	  N_("_Preformatted"),
+	  "<Control>7",
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_PRE },
+
+	{ "style-list-bullet",
+	  NULL,
+	  N_("_Bulleted List"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_ITEMDOTTED },
+
+	{ "style-list-roman",
+	  NULL,
+	  N_("_Roman Numeral List"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_ITEMROMAN },
+
+	{ "style-list-number",
+	  NULL,
+	  N_("Numbered _List"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_ITEMDIGIT },
+
+	{ "style-list-alpha",
+	  NULL,
+	  N_("_Alphabetical List"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_PARAGRAPH_STYLE_ITEMALPHA }
+};
+
+/*****************************************************************************
+ * Core Actions (HTML only)
+ *
+ * These actions are only enabled in HTML mode.
+ *****************************************************************************/
+
+static GtkActionEntry html_entries[] = {
+
+	{ "insert-image",
+	  "insert-image",
+	  N_("_Image..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_image_cb) },
+
+	{ "insert-link",
+	  "insert-link",
+	  N_("_Link..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_link_cb) },
+
+	{ "insert-rule",
+	  "stock_insert-rule",
+	  N_("_Rule..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_rule_cb) },
+
+	{ "insert-table",
+	  "stock_insert-table",
+	  N_("_Table..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_table_cb) },
+
+	{ "properties-cell",
+	  NULL,
+	  N_("_Cell..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_cell_cb) },
+
+	{ "properties-image",
+	  NULL,
+	  N_("_Image..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_image_cb) },
+
+	{ "properties-link",
+	  NULL,
+	  N_("_Link..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_link_cb) },
+
+	{ "properties-page",
+	  NULL,
+	  N_("_Page..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_page_cb) },
+
+	{ "properties-rule",
+	  NULL,
+	  N_("_Rule..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_rule_cb) },
+
+	{ "properties-table",
+	  NULL,
+	  N_("_Table..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_table_cb) },
+
+	{ "properties-text",
+	  NULL,
+	  N_("_Text..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_text_cb) },
+
+	/* Menus */
+
+	{ "font-size-menu",
+	  NULL,
+	  N_("_Font Size"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "font-style-menu",
+	  NULL,
+	  N_("_Style"),
+	  NULL,
+	  NULL,
+	  NULL },
+};
+
+static GtkToggleActionEntry html_toggle_entries[] = {
+
+	{ "bold",
+	  GTK_STOCK_BOLD,
+	  N_("_Bold"),
+	  "<Control>b",
+	  NULL,
+	  G_CALLBACK (action_bold_cb),
+	  FALSE },
+
+	{ "italic",
+	  GTK_STOCK_ITALIC,
+	  N_("_Italic"),
+	  "<Control>i",
+	  NULL,
+	  G_CALLBACK (action_italic_cb),
+	  FALSE },
+
+	{ "monospaced",
+	  "stock_text-monospaced",
+	  N_("_Plain Text"),
+	  "<Control>t",
+	  NULL,
+	  G_CALLBACK (action_monospaced_cb),
+	  FALSE },
+
+	{ "strikethrough",
+	  GTK_STOCK_STRIKETHROUGH,
+	  N_("_Strikethrough"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_strikethrough_cb),
+	  FALSE },
+
+	{ "underline",
+	  GTK_STOCK_UNDERLINE,
+	  N_("_Underline"),
+	  "<Control>u",
+	  NULL,
+	  G_CALLBACK (action_underline_cb),
+	  FALSE }
+};
+
+static GtkRadioActionEntry html_size_entries[] = {
+
+	{ "size-minus-two",
+	  NULL,
+	  N_("-2"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_1 },
+
+	{ "size-minus-one",
+	  NULL,
+	  N_("-1"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_2 },
+
+	{ "size-plus-zero",
+	  NULL,
+	  N_("+0"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_3 },
+
+	{ "size-plus-one",
+	  NULL,
+	  N_("+1"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_4 },
+
+	{ "size-plus-two",
+	  NULL,
+	  N_("+2"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_5 },
+
+	{ "size-plus-three",
+	  NULL,
+	  N_("+3"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_6 },
+
+	{ "size-plus-four",
+	  NULL,
+	  N_("+4"),
+	  NULL,
+	  NULL,
+	  GTK_HTML_FONT_STYLE_SIZE_7 }
+};
+
+/*****************************************************************************
+ * Context Menu Actions
+ *
+ * These require separate action entries so we can toggle their visiblity
+ * rather than their sensitivity as we do with main menu / toolbar actions.
+ * Note that some of these actions use the same callback function as their
+ * non-context sensitive counterparts.
+ *****************************************************************************/
+
+static GtkActionEntry context_entries[] = {
+
+	{ "context-delete-cell",
+	  NULL,
+	  N_("Cell Contents"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_delete_cell_cb) },
+
+	{ "context-delete-column",
+	  NULL,
+	  N_("Column"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_delete_column_cb) },
+
+	{ "context-delete-row",
+	  NULL,
+	  N_("Row"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_delete_row_cb) },
+
+	{ "context-delete-table",
+	  NULL,
+	  N_("Table"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_delete_table_cb) },
+
+	/* Menus */
+
+	{ "context-delete-table-menu",
+	  NULL,
+	  N_("Table Delete"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "context-input-methods-menu",
+	  NULL,
+	  N_("Input Methods"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "context-insert-table-menu",
+	  NULL,
+	  N_("Table Insert"),
+	  NULL,
+	  NULL,
+	  NULL },
+
+	{ "context-properties-menu",
+	  NULL,
+	  N_("Properties"),
+	  NULL,
+	  NULL,
+	  NULL },
+};
+
+/*****************************************************************************
+ * Context Menu Actions (HTML only)
+ *
+ * These actions are never visible in plain-text mode.  Note that some
+ * of them use the same callback function as their non-context sensitive
+ * counterparts.
+ *****************************************************************************/
+
+static GtkActionEntry html_context_entries[] = {
+
+	{ "context-insert-column-after",
+	  NULL,
+	  N_("Column After"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_insert_column_after_cb) },
+
+	{ "context-insert-column-before",
+	  NULL,
+	  N_("Column Before"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_insert_column_before_cb) },
+
+	{ "context-insert-link",
+	  NULL,
+	  N_("Insert _Link"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_link_cb) },
+
+	{ "context-insert-row-above",
+	  NULL,
+	  N_("Row Above"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_insert_row_above_cb) },
+
+	{ "context-insert-row-below",
+	  NULL,
+	  N_("Row Below"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_insert_row_below_cb) },
+
+	{ "context-insert-table",
+	  NULL,
+	  N_("Table"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_insert_table_cb) },
+
+	{ "context-properties-cell",
+	  NULL,
+	  N_("Cell..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_cell_cb) },
+
+	{ "context-properties-image",
+	  NULL,
+	  N_("Image..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_image_cb) },
+
+	{ "context-properties-link",
+	  NULL,
+	  N_("Link..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_link_cb) },
+
+	{ "context-properties-page",
+	  NULL,
+	  N_("Page..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_page_cb) },
+
+	{ "context-properties-paragraph",
+	  NULL,
+	  N_("Paragraph..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_paragraph_cb) },
+
+	{ "context-properties-rule",
+	  NULL,
+	  N_("Rule..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_rule_cb) },
+
+	{ "context-properties-table",
+	  NULL,
+	  N_("Table..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_table_cb) },
+
+	{ "context-properties-text",
+	  NULL,
+	  N_("Text..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_properties_text_cb) },
+
+	{ "context-remove-link",
+	  NULL,
+	  N_("Remove Link"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_remove_link_cb) }
+};
+
+/*****************************************************************************
+ * Context Menu Actions (spell checking only)
+ *
+ * These actions are only visible when the word underneath the cursor is
+ * misspelled.
+ *****************************************************************************/
+
+static GtkActionEntry spell_context_entries[] = {
+
+	{ "context-spell-add",
+	  NULL,
+	  N_("Add Word to Dictionary"),
+	  NULL,
+	  NULL,
+          G_CALLBACK (action_context_spell_add_cb) },
+
+	{ "context-spell-ignore",
+	  NULL,
+	  N_("Ignore Misspelled Word"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_context_spell_ignore_cb) },
+
+	{ "context-spell-add-menu",
+	  NULL,
+	  N_("Add Word To"),
+	  NULL,
+	  NULL,
+	  NULL }
+};
+
+static void
+editor_actions_setup_languages_menu (GtkhtmlEditor *editor)
+{
+	GtkUIManager *manager;
+	GtkActionGroup *action_group;
+	const GList *available_languages;
+	guint merge_id;
+
+	manager = editor->priv->manager;
+	action_group = editor->priv->language_actions;
+	available_languages = gtkhtml_spell_language_get_available ();
+	merge_id = gtk_ui_manager_new_merge_id (manager);
+
+	while (available_languages != NULL) {
+		GtkhtmlSpellLanguage *language = available_languages->data;
+		GtkhtmlSpellChecker *checker;
+		GtkToggleAction *action;
+
+		checker = gtkhtml_spell_checker_new (language);
+
+		g_hash_table_insert (
+			editor->priv->available_spell_checkers,
+			language, checker);
+
+		action = gtk_toggle_action_new (
+			gtkhtml_spell_language_get_code (language),
+			gtkhtml_spell_language_get_name (language),
+			NULL, NULL);
+
+		g_signal_connect (
+			action, "toggled",
+			G_CALLBACK (action_language_cb), editor);
+
+		gtk_action_group_add_action (
+			action_group, GTK_ACTION (action));
+
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (
+			manager, merge_id,
+			"/main-menu/edit-menu/language-menu",
+			gtkhtml_spell_language_get_code (language),
+			gtkhtml_spell_language_get_code (language),
+			GTK_UI_MANAGER_AUTO, FALSE);
+
+		available_languages = g_list_next (available_languages);
+	}
+}
+
+static void
+editor_actions_setup_spell_check_menu (GtkhtmlEditor *editor)
+{
+	GtkUIManager *manager;
+	GtkActionGroup *action_group;
+	const GList *available_languages;
+	guint merge_id;
+
+	manager = editor->priv->manager;
+	action_group = editor->priv->spell_check_actions;;
+	available_languages = gtkhtml_spell_language_get_available ();
+	merge_id = gtk_ui_manager_new_merge_id (manager);
+
+	while (available_languages != NULL) {
+		GtkhtmlSpellLanguage *language = available_languages->data;
+		GtkAction *action;
+		const gchar *code;
+		const gchar *name;
+		gchar *action_label;
+		gchar *action_name;
+
+		code = gtkhtml_spell_language_get_code (language);
+		name = gtkhtml_spell_language_get_name (language);
+
+		/* Add a suggestion menu. */
+
+		action_name = g_strdup_printf (
+			"context-spell-suggest-%s-menu", code);
+
+		action = gtk_action_new (action_name, name, NULL, NULL);
+		gtk_action_group_add_action (action_group, action);
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (
+			manager, merge_id,
+			"/context-menu/context-spell-suggest",
+			action_name, action_name,
+			GTK_UI_MANAGER_MENU, FALSE);
+
+		g_free (action_name);
+
+		/* Add an item to the "Add Word To" menu. */
+
+		action_label = g_strdup_printf ("%s Dictionary", name);
+		action_name = g_strdup_printf ("context-spell-add-%s", code);
+
+		action = gtk_action_new (
+			action_name, action_label, NULL, NULL);
+
+		g_signal_connect (
+			action, "activate",
+			G_CALLBACK (action_context_spell_add_cb), editor);
+
+		/* Visibility is dependent on whether the
+		 * corresponding language action is active. */
+		gtk_action_set_visible (action, FALSE);
+
+		gtk_action_group_add_action (action_group, action);
+
+		g_object_unref (action);
+
+		gtk_ui_manager_add_ui (
+			manager, merge_id,
+			"/context-menu/context-spell-add-menu",
+			action_name, action_name,
+			GTK_UI_MANAGER_AUTO, FALSE);
+
+		g_free (action_label);
+		g_free (action_name);
+
+		available_languages = g_list_next (available_languages);
+	}
+}
+
+void
+gtkhtml_editor_actions_init (GtkhtmlEditor *editor)
+{
+	GtkActionGroup *action_group;
+	GtkUIManager *manager;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	manager = gtkhtml_editor_get_ui_manager (editor);
+
+	/* Core Actions */
+	action_group = editor->priv->core_actions;
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, core_entries,
+		G_N_ELEMENTS (core_entries), editor);
+	gtk_action_group_add_toggle_actions (
+		action_group, core_toggle_entries,
+		G_N_ELEMENTS (core_toggle_entries), editor);
+	gtk_action_group_add_radio_actions (
+		action_group, core_justify_entries,
+		G_N_ELEMENTS (core_justify_entries),
+		GTK_HTML_PARAGRAPH_ALIGNMENT_LEFT,
+		G_CALLBACK (action_justify_cb), editor);
+	gtk_action_group_add_radio_actions (
+		action_group, core_style_entries,
+		G_N_ELEMENTS (core_style_entries),
+		GTK_HTML_PARAGRAPH_STYLE_NORMAL,
+		G_CALLBACK (action_style_cb), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Core Actions (HTML only) */
+	action_group = editor->priv->html_actions;
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, html_entries,
+		G_N_ELEMENTS (html_entries), editor);
+	gtk_action_group_add_toggle_actions (
+		action_group, html_toggle_entries,
+		G_N_ELEMENTS (html_toggle_entries), editor);
+	gtk_action_group_add_radio_actions (
+		action_group, html_size_entries,
+		G_N_ELEMENTS (html_size_entries),
+		GTK_HTML_FONT_STYLE_SIZE_3,
+		G_CALLBACK (action_size_cb), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Context Menu Actions */
+	action_group = editor->priv->context_actions;
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, context_entries,
+		G_N_ELEMENTS (context_entries), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Context Menu Actions (HTML only) */
+	action_group = editor->priv->html_context_actions;
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, html_context_entries,
+		G_N_ELEMENTS (html_context_entries), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Context Menu Actions (spell check only) */
+	action_group = editor->priv->spell_check_actions;
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, spell_context_entries,
+		G_N_ELEMENTS (spell_context_entries), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Language actions are generated dynamically. */
+	editor_actions_setup_languages_menu (editor);
+	action_group = editor->priv->language_actions;
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Some spell check actions are generated dynamically. */
+	action_group = editor->priv->suggestion_actions;
+	editor_actions_setup_spell_check_menu (editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	/* Fine Tuning */
+
+	g_object_set (
+		G_OBJECT (ACTION (FIND)),
+		"short-label", _("_Find"), NULL);
+	g_object_set (
+		G_OBJECT (ACTION (FIND_AND_REPLACE)),
+		"short-label", _("Re_place"), NULL);
+	g_object_set (
+		G_OBJECT (ACTION (INSERT_IMAGE)),
+		"short-label", _("_Image"), NULL);
+	g_object_set (
+		G_OBJECT (ACTION (INSERT_LINK)),
+		"short-label", _("_Link"), NULL);
+	g_object_set (
+		G_OBJECT (ACTION (INSERT_RULE)),
+		"short-label", _("_Rule"), NULL);
+	g_object_set (
+		G_OBJECT (ACTION (INSERT_TABLE)),
+		"short-label", _("_Table"), NULL);
+
+	gtk_action_set_sensitive (ACTION (UNINDENT), FALSE);
+}
Index: components/editor/gtkhtml-combo-box.c
===================================================================
--- components/editor/gtkhtml-combo-box.c	(revision 0)
+++ components/editor/gtkhtml-combo-box.c	(revision 0)
@@ -0,0 +1,488 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-combo-box.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-combo-box.h"
+
+#include <glib/gi18n-lib.h>
+
+#define GTKHTML_COMBO_BOX_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_COMBO_BOX, GtkhtmlComboBoxPrivate))
+
+enum {
+	PROP_0,
+	PROP_ACTION
+};
+
+struct _GtkhtmlComboBoxPrivate {
+	GtkRadioAction *action;
+	GtkActionGroup *action_group;
+	GHashTable *index;
+	guint changed_handler_id;		/* action::changed */
+	guint group_sensitive_handler_id;	/* action-group::sensitive */
+	guint group_visible_handler_id;		/* action-group::visible */
+};
+
+static gpointer parent_class;
+
+static void
+combo_box_action_changed_cb (GtkRadioAction *action,
+                             GtkRadioAction *current,
+                             GtkhtmlComboBox *combo_box)
+{
+	GtkTreeRowReference *reference;
+	GtkTreeModel *model;
+	GtkTreePath *path;
+	GtkTreeIter iter;
+	gboolean valid;
+
+	reference = g_hash_table_lookup (
+		combo_box->priv->index, GINT_TO_POINTER (
+		gtk_radio_action_get_current_value (current)));
+	g_return_if_fail (reference != NULL);
+
+	model = gtk_tree_row_reference_get_model (reference);
+	path = gtk_tree_row_reference_get_path (reference);
+	valid = gtk_tree_model_get_iter (model, &iter, path);
+	gtk_tree_path_free (path);
+	g_return_if_fail (valid);
+
+	gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo_box), &iter);
+}
+
+static void
+combo_box_action_group_notify_cb (GtkActionGroup *action_group,
+                                  GParamSpec *pspec,
+                                  GtkhtmlComboBox *combo_box)
+{
+	g_object_set (
+		combo_box, "sensitive",
+		gtk_action_group_get_sensitive (action_group), "visible",
+		gtk_action_group_get_visible (action_group), NULL);
+}
+
+static void
+combo_box_active_changed_cb (GtkComboBox *combo_box)
+{
+	GtkRadioAction *action;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gint value;
+
+	if (!gtk_combo_box_get_active_iter (combo_box, &iter))
+		return;
+
+	model = gtk_combo_box_get_model (combo_box);
+	gtk_tree_model_get (model, &iter, 0, &action, -1);
+	g_object_get (G_OBJECT (action), "value", &value, NULL);
+	gtk_radio_action_set_current_value (action, value);
+}
+
+static void
+combo_box_render_pixbuf (GtkhtmlComboBox *combo_box,
+                         GtkCellRenderer *renderer,
+                         GtkTreeModel *model,
+                         GtkTreeIter *iter)
+{
+	GtkRadioAction *action;
+	gchar *icon_name;
+	gchar *stock_id;
+	gboolean sensitive;
+	gboolean visible;
+
+	gtk_tree_model_get (model, iter, 0, &action, -1);
+
+	g_object_get (
+		G_OBJECT (action),
+		"icon-name", &icon_name,
+		"sensitive", &sensitive,
+		"stock-id", &stock_id,
+		"visible", &visible,
+		NULL);
+
+	g_object_set (
+		G_OBJECT (renderer),
+		"icon-name", icon_name,
+		"sensitive", sensitive,
+		"stock-id", stock_id,
+		"stock-size", GTK_ICON_SIZE_MENU,
+		"visible", visible,
+		NULL);
+
+	g_free (icon_name);
+	g_free (stock_id);
+}
+
+static void
+combo_box_render_text (GtkhtmlComboBox *combo_box,
+                       GtkCellRenderer *renderer,
+                       GtkTreeModel *model,
+                       GtkTreeIter *iter)
+{
+	GtkRadioAction *action;
+	gchar **strv;
+	gchar *label;
+	gboolean sensitive;
+	gboolean visible;
+
+	gtk_tree_model_get (model, iter, 0, &action, -1);
+
+	g_object_get (
+		G_OBJECT (action),
+		"label", &label,
+		"sensitive", &sensitive,
+		"visible", &visible,
+		NULL);
+
+	/* Strip out underscores. */
+	strv = g_strsplit (label, "_", -1);
+	g_free (label);
+	label = g_strjoinv (NULL, strv);
+	g_strfreev (strv);
+
+	g_object_set (
+		G_OBJECT (renderer),
+		"sensitive", sensitive,
+		"text", label,
+		"visible", visible,
+		NULL);
+
+	g_free (label);
+}
+
+static void
+combo_box_update_model (GtkhtmlComboBox *combo_box)
+{
+	GtkListStore *list_store;
+	GSList *list;
+
+	g_hash_table_remove_all (combo_box->priv->index);
+
+	if (combo_box->priv->action == NULL) {
+		gtk_combo_box_set_model (GTK_COMBO_BOX (combo_box), NULL);
+		return;
+	}
+
+	list_store = gtk_list_store_new (
+		2, GTK_TYPE_RADIO_ACTION, G_TYPE_INT);
+
+	list = gtk_radio_action_get_group (combo_box->priv->action);
+
+	while (list != NULL) {
+		GtkTreeRowReference *reference;
+		GtkRadioAction *action = list->data;
+		GtkTreePath *path;
+		GtkTreeIter iter;
+		gint value;
+
+		gtk_list_store_append (list_store, &iter);
+		g_object_get (G_OBJECT (action), "value", &value, NULL);
+		gtk_list_store_set (
+			list_store, &iter, 0, list->data, 1, value, -1);
+
+		path = gtk_tree_model_get_path (
+			GTK_TREE_MODEL (list_store), &iter);
+		reference = gtk_tree_row_reference_new (
+			GTK_TREE_MODEL (list_store), path);
+		g_hash_table_insert (
+			combo_box->priv->index,
+			GINT_TO_POINTER (value), reference);
+		gtk_tree_path_free (path);
+
+		list = g_slist_next (list);
+	}
+
+	gtk_tree_sortable_set_sort_column_id (
+		GTK_TREE_SORTABLE (list_store), 1, GTK_SORT_ASCENDING);
+	gtk_combo_box_set_model (
+		GTK_COMBO_BOX (combo_box), GTK_TREE_MODEL (list_store));
+
+	combo_box_action_changed_cb (
+		combo_box->priv->action,
+		combo_box->priv->action,
+		combo_box);
+}
+
+static GObject *
+combo_box_constructor (GType type,
+                       guint n_construct_properties,
+                       GObjectConstructParam *construct_properties)
+{
+	GObject *object;
+
+	/* Chain up to parent's constructor() method. */
+	object = G_OBJECT_CLASS (parent_class)->constructor (
+		type, n_construct_properties, construct_properties);
+
+	g_signal_connect (
+		object, "changed",
+		G_CALLBACK (combo_box_active_changed_cb), NULL);
+
+	return object;
+}
+
+static void
+combo_box_set_property (GObject *object,
+                        guint property_id,
+                        const GValue *value,
+                        GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ACTION:
+			gtkhtml_combo_box_set_action (
+				GTKHTML_COMBO_BOX (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+combo_box_get_property (GObject *object,
+                        guint property_id,
+                        GValue *value,
+                        GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_ACTION:
+			g_value_set_object (
+				value, gtkhtml_combo_box_get_action (
+				GTKHTML_COMBO_BOX (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+combo_box_dispose (GObject *object)
+{
+	GtkhtmlComboBoxPrivate *priv = GTKHTML_COMBO_BOX_GET_PRIVATE (object);
+
+	if (priv->action != NULL)
+	{
+		g_object_unref (priv->action);
+		priv->action = NULL;
+	}
+
+	if (priv->action_group != NULL)
+	{
+		g_object_unref (priv->action_group);
+		priv->action_group = NULL;
+	}
+
+	g_hash_table_remove_all (priv->index);
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+combo_box_finalize (GObject *object)
+{
+	GtkhtmlComboBoxPrivate *priv = GTKHTML_COMBO_BOX_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->index);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+combo_box_class_init (GtkhtmlComboBoxClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlComboBoxPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructor = combo_box_constructor;
+	object_class->set_property = combo_box_set_property;
+	object_class->get_property = combo_box_get_property;
+	object_class->dispose = combo_box_dispose;
+	object_class->finalize = combo_box_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ACTION,
+		g_param_spec_object (
+			"action",
+			_("Action"),
+			_("A GtkRadioAction"),
+			GTK_TYPE_RADIO_ACTION,
+			G_PARAM_READWRITE));
+}
+
+static void
+combo_box_init (GtkhtmlComboBox *combo_box)
+{
+	GtkCellRenderer *renderer;
+
+	combo_box->priv = GTKHTML_COMBO_BOX_GET_PRIVATE (combo_box);
+
+	renderer = gtk_cell_renderer_pixbuf_new ();
+	gtk_cell_layout_pack_start (
+		GTK_CELL_LAYOUT (combo_box), renderer, FALSE);
+	gtk_cell_layout_set_cell_data_func (
+		GTK_CELL_LAYOUT (combo_box), renderer,
+		(GtkCellLayoutDataFunc) combo_box_render_pixbuf,
+		NULL, NULL);
+
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (
+		GTK_CELL_LAYOUT (combo_box), renderer, TRUE);
+	gtk_cell_layout_set_cell_data_func (
+		GTK_CELL_LAYOUT (combo_box), renderer,
+		(GtkCellLayoutDataFunc) combo_box_render_text,
+		NULL, NULL);
+
+	combo_box->priv->index = g_hash_table_new_full (
+		g_direct_hash, g_direct_equal,
+		(GDestroyNotify) NULL,
+		(GDestroyNotify) gtk_tree_row_reference_free);
+}
+
+GType
+gtkhtml_combo_box_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlComboBoxClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) combo_box_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlComboBox),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) combo_box_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_COMBO_BOX, "GtkhtmlComboBox",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+gtkhtml_combo_box_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_COMBO_BOX, NULL);
+}
+
+GtkWidget *
+gtkhtml_combo_box_new_with_action (GtkRadioAction *action)
+{
+	GtkWidget *widget;
+
+	widget = gtkhtml_combo_box_new ();
+	gtkhtml_combo_box_set_action (GTKHTML_COMBO_BOX (widget), action);
+
+	return widget;
+}
+
+GtkRadioAction *
+gtkhtml_combo_box_get_action (GtkhtmlComboBox *combo_box)
+{
+	g_return_val_if_fail (GTKHTML_IS_COMBO_BOX (combo_box), NULL);
+
+	return combo_box->priv->action;
+}
+
+void
+gtkhtml_combo_box_set_action (GtkhtmlComboBox *combo_box,
+                              GtkRadioAction *action)
+{
+	g_return_if_fail (GTKHTML_IS_COMBO_BOX (combo_box));
+
+	if (action != NULL)
+		g_return_if_fail (GTK_IS_RADIO_ACTION (action));
+
+	if (combo_box->priv->action != NULL) {
+		g_signal_handler_disconnect (
+			combo_box->priv->action,
+			combo_box->priv->changed_handler_id);
+		g_object_unref (combo_box->priv->action);
+	}
+
+	if (combo_box->priv->action_group != NULL) {
+		g_signal_handler_disconnect (
+			combo_box->priv->action_group,
+			combo_box->priv->group_sensitive_handler_id);
+		g_signal_handler_disconnect (
+			combo_box->priv->action_group,
+			combo_box->priv->group_visible_handler_id);
+		g_object_unref (combo_box->priv->action_group);
+		combo_box->priv->action_group = NULL;
+	}
+
+	if (action != NULL)
+		g_object_get (
+			g_object_ref (action), "action-group",
+			&combo_box->priv->action_group, NULL);
+	combo_box->priv->action = action;
+	combo_box_update_model (combo_box);
+
+	combo_box->priv->changed_handler_id = g_signal_connect (
+		combo_box->priv->action, "changed",
+		G_CALLBACK (combo_box_action_changed_cb), combo_box);
+
+	if (combo_box->priv->action_group != NULL) {
+		combo_box->priv->group_sensitive_handler_id =
+			g_signal_connect (
+				combo_box->priv->action_group,
+				"notify::sensitive",
+				G_CALLBACK (combo_box_action_group_notify_cb),
+				combo_box);
+		combo_box->priv->group_visible_handler_id =
+			g_signal_connect (
+				combo_box->priv->action_group,
+				"notify::visible",
+				G_CALLBACK (combo_box_action_group_notify_cb),
+				combo_box);
+	}
+}
+
+gint
+gtkhtml_combo_box_get_current_value (GtkhtmlComboBox *combo_box)
+{
+	g_return_val_if_fail (GTKHTML_IS_COMBO_BOX (combo_box), 0);
+	g_return_val_if_fail (combo_box->priv->action != NULL, 0);
+
+	return gtk_radio_action_get_current_value (combo_box->priv->action);
+}
+
+void
+gtkhtml_combo_box_set_current_value (GtkhtmlComboBox *combo_box,
+                                     gint current_value)
+{
+	g_return_if_fail (GTKHTML_IS_COMBO_BOX (combo_box));
+	g_return_if_fail (combo_box->priv->action != NULL);
+
+	gtk_radio_action_set_current_value (
+		combo_box->priv->action, current_value);
+}
Index: components/editor/gtkhtml-editor.c
===================================================================
--- components/editor/gtkhtml-editor.c	(revision 0)
+++ components/editor/gtkhtml-editor.c	(revision 0)
@@ -0,0 +1,1424 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-editor.h"
+
+#include <string.h>
+
+#include "gtkhtml-editor-private.h"
+
+enum {
+	PROP_0,
+	PROP_CURRENT_FOLDER,
+	PROP_FILENAME,
+	PROP_HTML_MODE,
+	PROP_INLINE_SPELLING,
+	PROP_MAGIC_LINKS,
+	PROP_MAGIC_SMILEYS
+};
+
+enum {
+	URL_REQUESTED,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+editor_alignment_changed_cb (GtkhtmlEditor *editor,
+                             GtkHTMLParagraphAlignment alignment)
+{
+	gtk_radio_action_set_current_value (
+		GTK_RADIO_ACTION (ACTION (JUSTIFY_CENTER)), alignment);
+}
+
+static gboolean
+editor_button_press_event_cb (GtkhtmlEditor *editor,
+                              GdkEventButton *event)
+{
+	GtkHTML *html;
+	GtkWidget *menu;
+	HTMLObject *object;
+	gboolean in_selection;
+	guint offset;
+
+	html = gtkhtml_editor_get_html (editor);
+	menu = gtkhtml_editor_get_managed_widget (editor, "/context-menu");
+
+	object = html_engine_get_object_at (
+		html->engine, event->x, event->y, &offset, FALSE);
+
+	if (event->type != GDK_BUTTON_PRESS)
+		return FALSE;
+
+	if (event->button != 3)
+		return FALSE;
+
+	/* Did we right-click in a selection? */
+	in_selection =
+		html_engine_is_selection_active (html->engine) &&
+		html_engine_point_in_selection (html->engine, object, offset);
+
+	if (!in_selection) {
+		html_engine_disable_selection (html->engine);
+		html_engine_jump_at (html->engine, event->x, event->y);
+		gtkhtml_editor_update_context (editor);
+	}
+
+	gtk_menu_popup (
+		GTK_MENU (menu), NULL, NULL, NULL, NULL,
+		event->button, event->time);
+
+	return FALSE;
+}
+
+static void
+editor_font_style_changed_cb (GtkhtmlEditor *editor,
+                              GtkHTMLFontStyle style)
+{
+	GtkHTMLFontStyle size;
+
+	gtk_toggle_action_set_active (
+		GTK_TOGGLE_ACTION (ACTION (BOLD)),
+		style & GTK_HTML_FONT_STYLE_BOLD);
+
+	gtk_toggle_action_set_active (
+		GTK_TOGGLE_ACTION (ACTION (MONOSPACED)),
+		style & GTK_HTML_FONT_STYLE_FIXED);
+
+	gtk_toggle_action_set_active (
+		GTK_TOGGLE_ACTION (ACTION (ITALIC)),
+		style & GTK_HTML_FONT_STYLE_ITALIC);
+
+	gtk_toggle_action_set_active (
+		GTK_TOGGLE_ACTION (ACTION (STRIKETHROUGH)),
+		style & GTK_HTML_FONT_STYLE_STRIKEOUT);
+
+	gtk_toggle_action_set_active (
+		GTK_TOGGLE_ACTION (ACTION (UNDERLINE)),
+		style & GTK_HTML_FONT_STYLE_UNDERLINE);
+
+	size = style & GTK_HTML_FONT_STYLE_SIZE_MASK;
+	if (size == GTK_HTML_FONT_STYLE_DEFAULT)
+		size = GTK_HTML_FONT_STYLE_SIZE_3;
+
+	gtk_radio_action_set_current_value (
+		GTK_RADIO_ACTION (ACTION (SIZE_PLUS_ZERO)), size);
+}
+
+static void
+editor_indentation_changed_cb (GtkhtmlEditor *editor,
+                               guint indentation_level)
+{
+	gtk_action_set_sensitive (ACTION (UNINDENT), indentation_level > 0);
+}
+
+static void
+editor_paragraph_style_changed_cb (GtkhtmlEditor *editor,
+                                   GtkHTMLParagraphStyle style)
+{
+	gtk_radio_action_set_current_value (
+		GTK_RADIO_ACTION (ACTION (STYLE_NORMAL)), style);
+}
+
+static void
+editor_text_color_changed_cb (GtkhtmlEditor *editor)
+{
+	GtkhtmlColorState *state;
+	GdkColor gdk_color;
+	GtkHTML *html;
+
+	state = editor->priv->text_color;
+	html = gtkhtml_editor_get_html (editor);
+
+	if (gtkhtml_color_state_get_current_color (state, &gdk_color)) {
+		HTMLColor *color;
+
+		color = html_color_new_from_gdk_color (&gdk_color);
+		gtk_html_set_color (html, color);
+		html_color_unref (color);
+	} else
+		gtk_html_set_color (html, NULL);
+}
+
+static void
+editor_url_requested_cb (GtkhtmlEditor *editor,
+                         const gchar *url,
+                         GtkHTMLStream *stream)
+{
+	GtkHTML *html;
+	GMappedFile *mapped_file;
+	GtkHTMLStreamStatus status;
+	gchar *filename = NULL;
+	GError *error = NULL;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	/* We can only handle local URLs here. */
+	if (g_ascii_strncasecmp (url, "file:/", 6) != 0) {
+		g_signal_emit (editor, signals[URL_REQUESTED], 0, url, stream);
+		return;
+	}
+
+	filename = g_filename_from_uri (url, NULL, &error);
+	if (filename == NULL)
+		goto exit;
+
+	mapped_file = g_mapped_file_new (filename, FALSE, &error);
+	if (mapped_file == NULL)
+		goto exit;
+
+	gtk_html_write (
+		html, stream,
+		g_mapped_file_get_contents (mapped_file),
+		g_mapped_file_get_length (mapped_file));
+
+	g_mapped_file_free (mapped_file);
+
+exit:
+	if (error == NULL)
+		status = GTK_HTML_STREAM_OK;
+	else {
+		status = GTK_HTML_STREAM_ERROR;
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+
+	gtk_html_end (html, stream, status);
+
+	g_free (filename);
+}
+
+static void
+editor_command_popup_menu (GtkhtmlEditor *editor)
+{
+}
+
+static void
+editor_command_properties_dialog (GtkhtmlEditor *editor)
+{
+}
+
+static void
+editor_command_text_color_apply (GtkhtmlEditor *editor)
+{
+}
+
+static gboolean
+editor_method_check_word (GtkHTML *html,
+                          const gchar *word,
+                          gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+	gboolean correct = TRUE;
+	GList *list;
+
+	list = editor->priv->active_spell_checkers;
+
+	while (list != NULL && correct) {
+		GtkhtmlSpellChecker *checker = list->data;
+
+		correct = gtkhtml_spell_checker_check_word (checker, word, -1);
+		list = g_list_next (list);
+	}
+
+	return correct;
+}
+
+static void
+editor_method_suggestion_request (GtkHTML *html,
+                                  gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+}
+
+static void
+editor_method_add_to_session (GtkHTML *html,
+                              const gchar *word,
+                              gpointer user_data)
+{
+	/* TODO - I guess just add it to the first active spell checker? */
+}
+
+static void
+editor_method_add_to_personal (GtkHTML *html,
+                               const gchar *word,
+                               const gchar *language_code,
+                               gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+	const GtkhtmlSpellLanguage *language;
+	GtkhtmlSpellChecker *checker;
+	GHashTable *hash_table;
+
+	language = gtkhtml_spell_language_lookup (language_code);
+	g_return_if_fail (language != NULL);
+
+	hash_table = editor->priv->available_spell_checkers;
+	checker = g_hash_table_lookup (hash_table, language);
+	g_return_if_fail (checker != NULL);
+
+	gtkhtml_spell_checker_add_word (checker, word, -1);
+}
+
+static gboolean
+editor_method_command (GtkHTML *html,
+                       GtkHTMLCommandType command,
+                       gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+	gboolean handled = TRUE;
+
+	switch (command) {
+		case GTK_HTML_COMMAND_POPUP_MENU:
+			editor_command_popup_menu (editor);
+			break;
+
+		case GTK_HTML_COMMAND_PROPERTIES_DIALOG:
+			editor_command_properties_dialog (editor);
+			break;
+
+		case GTK_HTML_COMMAND_TEXT_COLOR_APPLY:
+			editor_command_text_color_apply (editor);
+			break;
+
+		default:
+			handled = FALSE;
+			break;
+	}
+
+	return handled;
+}
+
+static GValue *
+editor_method_event (GtkHTML *html,
+                     GtkHTMLEditorEventType event,
+                     GValue *args,
+                     gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+	GValue *value = NULL;
+
+	switch (event) {
+		case GTK_HTML_EDITOR_EVENT_COMMAND_BEFORE:
+			break;
+
+		case GTK_HTML_EDITOR_EVENT_COMMAND_AFTER:
+			break;
+
+		case GTK_HTML_EDITOR_EVENT_IMAGE_URL:
+			break;
+
+		case GTK_HTML_EDITOR_EVENT_DELETE:
+			break;
+
+		case GTK_HTML_EDITOR_EVENT_LINK_CLICKED:
+			break;
+	}
+
+	return value;
+}
+
+static GtkWidget *
+editor_method_create_input_line (GtkHTML *html,
+                                 gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+}
+
+static void
+editor_method_set_language (GtkHTML *html,
+                            const gchar *language,
+                            gpointer user_data)
+{
+	GtkhtmlEditor *editor = user_data;
+	GtkActionGroup *action_group;
+	GtkAction *action;
+	gchar *action_name;
+
+	action_group = editor->priv->language_actions;
+	action_name = g_strdelimit (g_strdup (language), "-", '_');
+	action = gtk_action_group_get_action (action_group, action_name);
+	g_free (action_name);
+
+	if (action != NULL)
+		gtk_action_activate (action);
+	else
+		g_warning ("%s: No such language", language);
+}
+
+static GtkHTMLEditorAPI editor_api = {
+	editor_method_check_word,
+	editor_method_suggestion_request,
+	editor_method_add_to_session,
+	editor_method_add_to_personal,
+	editor_method_command,
+	editor_method_event,
+	editor_method_create_input_line,
+	editor_method_set_language
+};
+
+static void
+editor_cut_clipboard (GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "cut");
+}
+
+static void
+editor_copy_clipboard (GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "copy");
+}
+
+static void
+editor_paste_clipboard (GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "paste");
+}
+
+static void
+editor_select_all (GtkhtmlEditor *editor)
+{
+	gtk_html_command (gtkhtml_editor_get_html (editor), "select-all");
+}
+
+static GObject *
+editor_constructor (GType type,
+                    guint n_construct_properties,
+                    GObjectConstructParam *construct_properties)
+{
+	GtkhtmlEditor *editor;
+	GObject *object;
+
+	/* Chain up to parent's constructor() method. */
+	object = G_OBJECT_CLASS (parent_class)->constructor (
+		type, n_construct_properties, construct_properties);
+
+	editor = GTKHTML_EDITOR (object);
+
+	gtk_container_add (GTK_CONTAINER (object), editor->vbox);
+	gtk_window_set_default_size (GTK_WINDOW (object), 600, 440);
+
+	gtk_action_connect_proxy (
+		ACTION (BOLD),
+		WIDGET (TEXT_PROPERTIES_BOLD_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (CONFIRM_REPLACE),
+		WIDGET (REPLACE_CONFIRMATION_REPLACE_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (CONFIRM_REPLACE_ALL),
+		WIDGET (REPLACE_CONFIRMATION_REPLACE_ALL_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (CONFIRM_REPLACE_CANCEL),
+		WIDGET (REPLACE_CONFIRMATION_CLOSE_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (CONFIRM_REPLACE_NEXT),
+		WIDGET (REPLACE_CONFIRMATION_NEXT_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (FIND),
+		WIDGET (FIND_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (FIND_AND_REPLACE),
+		WIDGET (REPLACE_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (ITALIC),
+		WIDGET (TEXT_PROPERTIES_ITALIC_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (JUSTIFY_CENTER),
+		WIDGET (PARAGRAPH_PROPERTIES_CENTER_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (JUSTIFY_LEFT),
+		WIDGET (PARAGRAPH_PROPERTIES_LEFT_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (JUSTIFY_RIGHT),
+		WIDGET (PARAGRAPH_PROPERTIES_RIGHT_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (STRIKETHROUGH),
+		WIDGET (TEXT_PROPERTIES_STRIKETHROUGH_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (TEST_URL),
+		WIDGET (LINK_PROPERTIES_TEST_BUTTON));
+	gtk_action_connect_proxy (
+		ACTION (UNDERLINE),
+		WIDGET (TEXT_PROPERTIES_UNDERLINE_BUTTON));
+
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (CELL_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (FIND_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (IMAGE_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (LINK_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (PAGE_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (PARAGRAPH_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (REPLACE_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (REPLACE_CONFIRMATION_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (RULE_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (TABLE_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+	gtk_window_set_transient_for (
+		GTK_WINDOW (WIDGET (TEXT_PROPERTIES_WINDOW)),
+		GTK_WINDOW (object));
+
+	/* Initialize various GtkhtmlComboBox instances. */
+	g_object_set (
+		WIDGET (PARAGRAPH_PROPERTIES_STYLE_COMBO_BOX),
+		"action", ACTION (STYLE_NORMAL), NULL);
+	g_object_set (
+		WIDGET (TEXT_PROPERTIES_SIZE_COMBO_BOX),
+		"action", ACTION (SIZE_PLUS_ZERO), NULL);
+
+	g_signal_connect_swapped (
+		editor->priv->text_color, "notify::current-color",
+		G_CALLBACK (editor_text_color_changed_cb), editor);
+
+	gtkhtml_editor_set_html_mode (editor, TRUE);
+
+	return object;
+}
+
+static void
+editor_set_property (GObject *object,
+                     guint property_id,
+                     const GValue *value,
+                     GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_FOLDER:
+			gtkhtml_editor_set_current_folder (
+				GTKHTML_EDITOR (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_FILENAME:
+			gtkhtml_editor_set_filename (
+				GTKHTML_EDITOR (object),
+				g_value_get_string (value));
+			return;
+
+		case PROP_HTML_MODE:
+			gtkhtml_editor_set_html_mode (
+				GTKHTML_EDITOR (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_INLINE_SPELLING:
+			gtkhtml_editor_set_inline_spelling (
+				GTKHTML_EDITOR (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_MAGIC_LINKS:
+			gtkhtml_editor_set_magic_links (
+				GTKHTML_EDITOR (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_MAGIC_SMILEYS:
+			gtkhtml_editor_set_magic_smileys (
+				GTKHTML_EDITOR (object),
+				g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+editor_get_property (GObject *object,
+                     guint property_id,
+                     GValue *value,
+                     GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_CURRENT_FOLDER:
+			g_value_set_string (
+				value, gtkhtml_editor_get_current_folder (
+				GTKHTML_EDITOR (object)));
+			return;
+
+		case PROP_FILENAME:
+			g_value_set_string (
+				value, gtkhtml_editor_get_filename (
+				GTKHTML_EDITOR (object)));
+			return;
+
+		case PROP_HTML_MODE:
+			g_value_set_boolean (
+				value, gtkhtml_editor_get_html_mode (
+				GTKHTML_EDITOR (object)));
+			return;
+
+		case PROP_INLINE_SPELLING:
+			g_value_set_boolean (
+				value, gtkhtml_editor_get_inline_spelling (
+				GTKHTML_EDITOR (object)));
+			return;
+
+		case PROP_MAGIC_LINKS:
+			g_value_set_boolean (
+				value, gtkhtml_editor_get_magic_links (
+				GTKHTML_EDITOR (object)));
+			return;
+
+		case PROP_MAGIC_SMILEYS:
+			g_value_set_boolean (
+				value, gtkhtml_editor_get_magic_smileys (
+				GTKHTML_EDITOR (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+editor_dispose (GObject *object)
+{
+	GtkhtmlEditor *editor = GTKHTML_EDITOR (object);
+
+	DISPOSE (editor->vbox);
+
+	gtkhtml_editor_private_dispose (editor);
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+editor_finalize (GObject *object)
+{
+	GtkhtmlEditor *editor = GTKHTML_EDITOR (object);
+
+	gtkhtml_editor_private_finalize (editor);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+editor_class_init (GtkhtmlEditorClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlEditorPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructor = editor_constructor;
+	object_class->set_property = editor_set_property;
+	object_class->get_property = editor_get_property;
+	object_class->dispose = editor_dispose;
+	object_class->finalize = editor_finalize;
+
+	class->cut_clipboard = editor_cut_clipboard;
+	class->copy_clipboard = editor_copy_clipboard;
+	class->paste_clipboard = editor_paste_clipboard;
+	class->select_all = editor_select_all;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CURRENT_FOLDER,
+		g_param_spec_string (
+			"current-folder",
+			_("Current Folder"),
+			_("The initial folder for file chooser dialogs"),
+			g_get_home_dir (),
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FILENAME,
+		g_param_spec_string (
+			"filename",
+			_("Filename"),
+			_("The filename to use when saving"),
+			NULL,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_HTML_MODE,
+		g_param_spec_boolean (
+			"html-mode",
+			_("HTML Mode"),
+			_("Edit HTML or plain text"),
+			TRUE,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_INLINE_SPELLING,
+		g_param_spec_boolean (
+			"inline-spelling",
+			_("Inline Spelling"),
+			_("Check your spelling as you type"),
+			TRUE,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MAGIC_LINKS,
+		g_param_spec_boolean (
+			"magic-links",
+			_("Magic Links"),
+			_("Make URIs clickable as you type"),
+			TRUE,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MAGIC_SMILEYS,
+		g_param_spec_boolean (
+			"magic-smileys",
+			_("Magic Smileys"),
+			_("Convert emoticons to images as you type"),
+			TRUE,
+			G_PARAM_CONSTRUCT |
+			G_PARAM_READWRITE));
+
+	signals[URL_REQUESTED] = g_signal_new (
+		"url-requested",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		gtkhtml_editor_marshal_VOID__STRING_POINTER,
+		G_TYPE_NONE,
+		2,
+		G_TYPE_STRING,
+		G_TYPE_POINTER);
+}
+
+static void
+editor_init (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	editor->priv = GTKHTML_EDITOR_GET_PRIVATE (editor);
+	editor->vbox = g_object_ref_sink (gtk_vbox_new (FALSE, 0));
+	gtk_widget_show (editor->vbox);
+
+	gtkhtml_editor_private_init (editor);
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_set_editor_api (html, &editor_api, editor);
+
+	/* Listen for events from core and update the UI accordingly. */
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"button_press_event",
+		G_CALLBACK (editor_button_press_event_cb), editor);
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"current_paragraph_alignment_changed",
+		G_CALLBACK (editor_alignment_changed_cb), editor);
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"current_paragraph_indentation_changed",
+		G_CALLBACK (editor_indentation_changed_cb), editor);
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"current_paragraph_style_changed",
+		G_CALLBACK (editor_paragraph_style_changed_cb), editor);
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"insertion_font_style_changed",
+		G_CALLBACK (editor_font_style_changed_cb), editor);
+
+	g_signal_connect_swapped (
+		gtkhtml_editor_get_html (editor),
+		"url_requested",
+		G_CALLBACK (editor_url_requested_cb), editor);
+}
+
+GType
+gtkhtml_editor_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlEditorClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) editor_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlEditor),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) editor_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_WINDOW, "GtkhtmlEditor", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+gtkhtml_editor_new (void)
+{
+	return g_object_new (GTKHTML_TYPE_EDITOR, NULL);
+}
+
+GtkHTML *
+gtkhtml_editor_get_html (GtkhtmlEditor *editor)
+{
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	return GTK_HTML (editor->priv->edit_area);
+}
+
+GtkUIManager *
+gtkhtml_editor_get_ui_manager (GtkhtmlEditor *editor)
+{
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	return editor->priv->manager;
+}
+
+GtkAction *
+gtkhtml_editor_get_action (GtkhtmlEditor *editor,
+                           const gchar *action_name)
+{
+	GtkAction *action = NULL;
+	GList *iter;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (action_name != NULL, NULL);
+
+	iter = gtk_ui_manager_get_action_groups (editor->priv->manager);
+	while (iter != NULL && action == NULL) {
+		GtkActionGroup *action_group = iter->data;
+
+		action = gtk_action_group_get_action (
+			action_group, action_name);
+		iter = g_list_next (iter);
+	}
+	g_assert (action != NULL);
+
+	return action;
+}
+
+GtkWidget *
+gtkhtml_editor_get_widget (GtkhtmlEditor *editor,
+                           const gchar *widget_name)
+{
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (widget_name != NULL, NULL);
+
+	widget = glade_xml_get_widget (editor->priv->glade_xml, widget_name);
+	g_assert (widget != NULL);
+
+	return widget;
+}
+
+GtkWidget *
+gtkhtml_editor_get_managed_widget (GtkhtmlEditor *editor,
+                                   const gchar *widget_path)
+{
+	GtkUIManager *manager;
+	GtkWidget *widget;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (widget_path != NULL, NULL);
+
+	manager = gtkhtml_editor_get_ui_manager (editor);
+	widget = gtk_ui_manager_get_widget (manager, widget_path);
+	g_assert (widget != NULL);
+
+	return widget;
+}
+
+const gchar *
+gtkhtml_editor_get_current_folder (GtkhtmlEditor *editor)
+{
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	return editor->priv->current_folder;
+}
+
+void
+gtkhtml_editor_set_current_folder (GtkhtmlEditor *editor,
+                                   const gchar *current_folder)
+{
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	if (current_folder == NULL)
+		current_folder = g_get_home_dir ();
+
+	g_free (editor->priv->current_folder);
+	editor->priv->current_folder = g_strdup (current_folder);
+
+	g_object_notify (G_OBJECT (editor), "current-folder");
+}
+
+const gchar *
+gtkhtml_editor_get_filename (GtkhtmlEditor *editor)
+{
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	return editor->priv->filename;
+}
+
+void
+gtkhtml_editor_set_filename (GtkhtmlEditor *editor,
+                             const gchar *filename)
+{
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	g_free (editor->priv->filename);
+	editor->priv->filename = g_strdup (filename);
+
+	g_object_notify (G_OBJECT (editor), "filename");
+}
+
+gboolean
+gtkhtml_editor_get_html_mode (GtkhtmlEditor *editor)
+{
+	GtkToggleAction *action;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	action = GTK_TOGGLE_ACTION (ACTION (HTML_MODE));
+
+	return gtk_toggle_action_get_active (action);
+}
+
+void
+gtkhtml_editor_set_html_mode (GtkhtmlEditor *editor,
+                              gboolean html_mode)
+{
+	GtkToggleAction *action;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	action = GTK_TOGGLE_ACTION (ACTION (HTML_MODE));
+	gtk_toggle_action_set_active (action, html_mode);
+
+	g_object_notify (G_OBJECT (editor), "html-mode");
+}
+
+gboolean
+gtkhtml_editor_get_inline_spelling (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	return gtk_html_get_inline_spelling (html);
+}
+
+void
+gtkhtml_editor_set_inline_spelling (GtkhtmlEditor *editor,
+                                    gboolean inline_spelling)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_set_inline_spelling (html, inline_spelling);
+
+	g_object_notify (G_OBJECT (editor), "inline-spelling");
+}
+
+gboolean
+gtkhtml_editor_get_magic_links (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	return gtk_html_get_magic_links (html);
+}
+
+void
+gtkhtml_editor_set_magic_links (GtkhtmlEditor *editor,
+                                gboolean magic_links)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_set_magic_links (html, magic_links);
+
+	g_object_notify (G_OBJECT (editor), "magic-links");
+}
+
+gboolean
+gtkhtml_editor_get_magic_smileys (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	return gtk_html_get_magic_smileys (html);
+}
+
+void
+gtkhtml_editor_set_magic_smileys (GtkhtmlEditor *editor,
+                                  gboolean magic_smileys)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_html_set_magic_smileys (html, magic_smileys);
+
+	g_object_notify (G_OBJECT (editor), "magic-smileys");
+}
+
+gint
+gtkhtml_editor_file_chooser_dialog_run (GtkhtmlEditor *editor,
+                                        GtkWidget *dialog)
+{
+	gint response = GTK_RESPONSE_NONE;
+	gboolean save_folder;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), response);
+	g_return_val_if_fail (GTK_IS_FILE_CHOOSER_DIALOG (dialog), response);
+
+	gtk_file_chooser_set_current_folder (
+		GTK_FILE_CHOOSER (dialog),
+		gtkhtml_editor_get_current_folder (editor));
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	save_folder =
+		(response == GTK_RESPONSE_ACCEPT) ||
+		(response == GTK_RESPONSE_OK) ||
+		(response == GTK_RESPONSE_YES) ||
+		(response == GTK_RESPONSE_APPLY);
+
+	if (save_folder) {
+		gchar *folder;
+
+		folder = gtk_file_chooser_get_current_folder (
+			GTK_FILE_CHOOSER (dialog));
+		gtkhtml_editor_set_current_folder (editor, folder);
+		g_free (folder);
+	}
+
+	return response;
+}
+
+/* Helper for gtkhtml_editor_get_text_[html/plain]() */
+static gboolean
+editor_save_receiver (HTMLEngine *engine,
+                      const gchar *data,
+                      guint length,
+                      GString *contents)
+{
+	g_string_append_len (contents, data, length);
+
+	return TRUE;
+}
+
+gchar *
+gtkhtml_editor_get_text_html (GtkhtmlEditor *editor,
+                              gsize *length)
+{
+	GString *string;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	string = g_string_sized_new (4096);
+
+	gtk_html_export (
+		gtkhtml_editor_get_html (editor), "text/html",
+		(GtkHTMLSaveReceiverFn) editor_save_receiver, string);
+
+	if (length != NULL)
+		*length = string->len;
+
+	return g_string_free (string, FALSE);
+}
+
+gchar *
+gtkhtml_editor_get_text_plain (GtkhtmlEditor *editor,
+                               gsize *length)
+{
+	GString *string;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+
+	string = g_string_sized_new (4096);
+
+	gtk_html_export (
+		gtkhtml_editor_get_html (editor), "text/plain",
+		(GtkHTMLSaveReceiverFn) editor_save_receiver, string);
+
+	if (length != NULL)
+		*length = string->len;
+
+	return g_string_free (string, FALSE);
+}
+
+void
+gtkhtml_editor_set_text_html (GtkhtmlEditor *editor,
+                              const gchar *text,
+                              gssize length)
+{
+	GtkHTML *html;
+	GtkHTMLStream *stream;
+	gboolean editable;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+	g_return_if_fail (text != NULL);
+
+	/* XXX gtk_html_write() should really do this. */
+	if (length < 0)
+		length = strlen (text);
+
+	html = gtkhtml_editor_get_html (editor);
+	editable = gtk_html_get_editable (html);
+	gtk_html_set_editable (html, FALSE);
+
+	stream = gtk_html_begin_content (html, "text/html; charset=utf-8");
+
+	/* XXX gtk_html_write() requires length > 0, which is
+	 *     unnecessary.  Zero length should be a no-op. */
+	if (length > 0)
+		gtk_html_write (html, stream, text, length);
+
+	gtk_html_end (html, stream, GTK_HTML_STREAM_OK);
+
+	gtk_html_set_editable (html, editable);
+}
+
+gboolean
+gtkhtml_editor_save (GtkhtmlEditor *editor,
+                     const gchar *filename,
+                     gboolean as_html,
+                     GError **error)
+{
+	gchar *contents;
+	gsize length;
+	gboolean success;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+	g_return_val_if_fail (filename != NULL, FALSE);
+
+	if (as_html)
+		contents = gtkhtml_editor_get_text_html (editor, &length);
+	else
+		contents = gtkhtml_editor_get_text_plain (editor, &length);
+
+	success = g_file_set_contents (filename, contents, length, error);
+
+	g_free (contents);
+
+	if (success) {
+		GtkHTML *html;
+
+		html = gtkhtml_editor_get_html (editor);
+		html->engine->saved_step_count =
+			html_undo_get_step_count (html->engine->undo);
+		gtkhtml_editor_run_command (editor, "saved");
+	}
+
+	return success;
+}
+
+const gchar *
+gtkhtml_editor_get_paragraph_data (GtkhtmlEditor *editor,
+                                   const gchar *key)
+{
+	GtkHTML *html;
+	HTMLObject *object;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), NULL);
+	g_return_val_if_fail (key != NULL, NULL);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	object = html->engine->cursor->object;
+	if (object == NULL)
+		return NULL;
+
+	object = object->parent;
+	if (object == NULL)
+		return NULL;
+
+	if (!HTML_IS_CLUEFLOW (object))
+		return NULL;
+
+	return html_object_get_data (object, key);
+}
+
+gboolean
+gtkhtml_editor_set_paragraph_data (GtkhtmlEditor *editor,
+                                   const gchar *key,
+                                   const gchar *value)
+{
+	GtkHTML *html;
+	HTMLObject *object;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+	g_return_val_if_fail (key != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	object = html->engine->cursor->object;
+	if (object == NULL)
+		return FALSE;
+
+	object = object->parent;
+	if (object == NULL)
+		return FALSE;
+
+	if (HTML_OBJECT_TYPE (object) != HTML_TYPE_CLUEFLOW)
+		return FALSE;
+
+	html_object_set_data (object, key, value);
+
+	return TRUE;
+}
+
+gboolean
+gtkhtml_editor_run_command (GtkhtmlEditor *editor,
+                            const gchar *command)
+{
+	GtkHTML *html;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+	g_return_val_if_fail (command != NULL, FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	return gtk_html_command (html, command);
+}
+
+gboolean
+gtkhtml_editor_is_paragraph_empty (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	HTMLObject *object;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	object = html->engine->cursor->object;
+	if (object == NULL)
+		return FALSE;
+
+	object = object->parent;
+	if (object == NULL)
+		return FALSE;
+
+	if (HTML_OBJECT_TYPE (object) != HTML_TYPE_CLUEFLOW)
+		return FALSE;
+
+	return html_clueflow_is_empty (HTML_CLUEFLOW (object));
+}
+
+gboolean
+gtkhtml_editor_is_previous_paragraph_empty (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	HTMLObject *object;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	object = html->engine->cursor->object;
+	if (object == NULL)
+		return FALSE;
+
+	object = object->parent;
+	if (object == NULL)
+		return FALSE;
+
+	object = object->prev;
+	if (object == NULL)
+		return FALSE;
+
+	if (HTML_OBJECT_TYPE (object) != HTML_TYPE_CLUEFLOW)
+		return FALSE;
+
+	return html_clueflow_is_empty (HTML_CLUEFLOW (object));
+}
+
+void
+gtkhtml_editor_insert_html (GtkhtmlEditor *editor,
+                            const gchar *html_text)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+
+	gtk_html_insert_html (html, html_text);
+}
+
+gboolean
+gtkhtml_editor_search_by_data (GtkhtmlEditor *editor,
+                               glong level,
+                               const gchar *key,
+                               const gchar *value)
+{
+	GtkHTML *html;
+	HTMLObject *last_object = NULL;
+	HTMLObject *object;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+	g_return_val_if_fail (key != NULL, FALSE);
+	g_return_val_if_fail (value != NULL, FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	do {
+		if (html->engine->cursor->object != last_object) {
+			object = html_object_nth_parent (
+				html->engine->cursor->object, level);
+			if (object != NULL) {
+				const gchar *object_value;
+
+				object_value =
+					html_object_get_data (object, key);
+				if (object_value != NULL &&
+					strcmp (object_value, value) == 0)
+					return TRUE;
+			}
+		}
+		last_object = html->engine->cursor->object;
+	} while (html_cursor_forward (html->engine->cursor, html->engine));
+
+	return FALSE;
+}
+
+void
+gtkhtml_editor_freeze (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_freeze (html->engine);
+}
+
+void
+gtkhtml_editor_thaw (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_thaw (html->engine);
+}
+
+void
+gtkhtml_editor_undo_begin (GtkhtmlEditor *editor,
+                           const gchar *undo_name,
+                           const gchar *redo_name)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+	g_return_if_fail (undo_name != NULL);
+	g_return_if_fail (redo_name != NULL);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_undo_level_begin (html->engine->undo, undo_name, redo_name);
+}
+
+void
+gtkhtml_editor_undo_end (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_undo_level_end (html->engine->undo);
+}
+
+gboolean
+gtkhtml_editor_has_undo (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	return gtk_html_has_undo (html);
+}
+
+void
+gtkhtml_editor_drop_undo (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+
+	gtk_html_drop_undo (html);
+}
Index: components/editor/gtkhtml-editor-actions.h
===================================================================
--- components/editor/gtkhtml-editor-actions.h	(revision 0)
+++ components/editor/gtkhtml-editor-actions.h	(revision 0)
@@ -0,0 +1,150 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-actions.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_EDITOR_ACTIONS_H
+#define GTKHTML_EDITOR_ACTIONS_H
+
+#define GTKHTML_EDITOR_ACTION(editor, name) \
+	(gtkhtml_editor_get_action (GTKHTML_EDITOR (editor), (name)))
+
+#define GTKHTML_EDITOR_ACTION_BOLD(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "bold")
+#define GTKHTML_EDITOR_ACTION_CONFIRM_REPLACE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "confirm-replace")
+#define GTKHTML_EDITOR_ACTION_CONFIRM_REPLACE_ALL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "confirm-replace-all")
+#define GTKHTML_EDITOR_ACTION_CONFIRM_REPLACE_CANCEL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "confirm-replace-cancel")
+#define GTKHTML_EDITOR_ACTION_CONFIRM_REPLACE_NEXT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "confirm-replace-next")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_DELETE_CELL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-delete-cell")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_DELETE_COLUMN(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-delete-column")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_DELETE_ROW(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-delete-row")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_DELETE_TABLE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-delete-table")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_INSERT_COLUMN_AFTER(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-insert-column-after")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_INSERT_COLUMN_BEFORE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-insert-column-before")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_INSERT_ROW_ABOVE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-insert-row-above")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_INSERT_ROW_BELOW(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-insert-row-below")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_INSERT_TABLE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-insert-table")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_CELL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-cell")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_IMAGE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-image")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_LINK(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-link")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_PARAGRAPH(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-paragraph")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_RULE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-rule")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_TABLE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-table")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_PROPERTIES_TEXT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-properties-text")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_REMOVE_LINK(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-remove-link")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_SPELL_ADD(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-spell-add")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_SPELL_ADD_MENU(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-spell-add-menu")
+#define GTKHTML_EDITOR_ACTION_CONTEXT_SPELL_IGNORE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "context-spell-ignore")
+#define GTKHTML_EDITOR_ACTION_COPY(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "copy")
+#define GTKHTML_EDITOR_ACTION_CUT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "cut")
+#define GTKHTML_EDITOR_ACTION_EDIT_MENU(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "edit-menu")
+#define GTKHTML_EDITOR_ACTION_FIND(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "find")
+#define GTKHTML_EDITOR_ACTION_FIND_AND_REPLACE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "find-and-replace")
+#define GTKHTML_EDITOR_ACTION_FORMAT_MENU(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "format-menu")
+#define GTKHTML_EDITOR_ACTION_FORMAT_TEXT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "format-text")
+#define GTKHTML_EDITOR_ACTION_HTML_MODE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "html-mode")
+#define GTKHTML_EDITOR_ACTION_INSERT_IMAGE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "insert-image")
+#define GTKHTML_EDITOR_ACTION_INSERT_LINK(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "insert-link")
+#define GTKHTML_EDITOR_ACTION_INSERT_MENU(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "insert-menu")
+#define GTKHTML_EDITOR_ACTION_INSERT_RULE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "insert-rule")
+#define GTKHTML_EDITOR_ACTION_INSERT_TABLE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "insert-table")
+#define GTKHTML_EDITOR_ACTION_ITALIC(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "italic")
+#define GTKHTML_EDITOR_ACTION_JUSTIFY_CENTER(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "justify-center")
+#define GTKHTML_EDITOR_ACTION_JUSTIFY_LEFT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "justify-left")
+#define GTKHTML_EDITOR_ACTION_JUSTIFY_RIGHT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "justify-right")
+#define GTKHTML_EDITOR_ACTION_MONOSPACED(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "monospaced")
+#define GTKHTML_EDITOR_ACTION_PROPERTIES_RULE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "properties-rule")
+#define GTKHTML_EDITOR_ACTION_PROPERTIES_TABLE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "properties-table")
+#define GTKHTML_EDITOR_ACTION_SHOW_FIND(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "show-find")
+#define GTKHTML_EDITOR_ACTION_SHOW_REPLACE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "show-replace")
+#define GTKHTML_EDITOR_ACTION_SIZE_PLUS_ZERO(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "size-plus-zero")
+#define GTKHTML_EDITOR_ACTION_SPELL_CHECK(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "spell-check")
+#define GTKHTML_EDITOR_ACTION_STRIKETHROUGH(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "strikethrough")
+#define GTKHTML_EDITOR_ACTION_STYLE_ADDRESS(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-address")
+#define GTKHTML_EDITOR_ACTION_STYLE_H1(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h1")
+#define GTKHTML_EDITOR_ACTION_STYLE_H2(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h2")
+#define GTKHTML_EDITOR_ACTION_STYLE_H3(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h3")
+#define GTKHTML_EDITOR_ACTION_STYLE_H4(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h4")
+#define GTKHTML_EDITOR_ACTION_STYLE_H5(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h5")
+#define GTKHTML_EDITOR_ACTION_STYLE_H6(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-h6")
+#define GTKHTML_EDITOR_ACTION_STYLE_NORMAL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "style-normal")
+#define GTKHTML_EDITOR_ACTION_TEST_URL(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "test-url")
+#define GTKHTML_EDITOR_ACTION_UNDERLINE(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "underline")
+#define GTKHTML_EDITOR_ACTION_UNINDENT(editor) \
+	GTKHTML_EDITOR_ACTION ((editor), "unindent")
+
+#endif /* GTKHTML_EDITOR_ACTIONS_H */
Index: components/editor/gtkhtml-combo-box.h
===================================================================
--- components/editor/gtkhtml-combo-box.h	(revision 0)
+++ components/editor/gtkhtml-combo-box.h	(revision 0)
@@ -0,0 +1,78 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-combo-box.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_COMBO_BOX_H
+#define GTKHTML_COMBO_BOX_H
+
+/* This is a GtkComboBox that is driven by a group of GtkRadioActions.
+ * Just plug in a GtkRadioAction and the widget will handle the rest. */
+
+#include "gtkhtml-editor-common.h"
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_COMBO_BOX \
+	(gtkhtml_combo_box_get_type ())
+#define GTKHTML_COMBO_BOX(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_COMBO_BOX, GtkhtmlComboBox))
+#define GTKHTML_COMBO_BOX_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_COMBO_BOX, GtkhtmlComboBoxClass))
+#define GTKHTML_IS_COMBO_BOX(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_COMBO_BOX))
+#define GTKHTML_IS_COMBO_BOX_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_COMBO_BOX))
+#define GTKHTML_COMBO_BOX_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_COMBO_BOX, GtkhtmlComboBoxClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlComboBox GtkhtmlComboBox;
+typedef struct _GtkhtmlComboBoxClass GtkhtmlComboBoxClass;
+typedef struct _GtkhtmlComboBoxPrivate GtkhtmlComboBoxPrivate;
+
+struct _GtkhtmlComboBox {
+	GtkComboBox parent;
+	GtkhtmlComboBoxPrivate *priv;
+};
+
+struct _GtkhtmlComboBoxClass {
+	GtkComboBoxClass parent_class;
+};
+
+GType		gtkhtml_combo_box_get_type	(void);
+GtkWidget *	gtkhtml_combo_box_new		(void);
+GtkWidget *	gtkhtml_combo_box_new_with_action
+						(GtkRadioAction *action);
+GtkRadioAction *gtkhtml_combo_box_get_action	(GtkhtmlComboBox *combo_box);
+void		gtkhtml_combo_box_set_action	(GtkhtmlComboBox *combo_box,
+						 GtkRadioAction *action);
+gint		gtkhtml_combo_box_get_current_value
+						(GtkhtmlComboBox *combo_box);
+void		gtkhtml_combo_box_set_current_value
+						(GtkhtmlComboBox *combo_box,
+						 gint current_value);
+
+G_END_DECLS
+
+#endif /* GTKHTML_COMBO_BOX_H */
Index: components/editor/gtkhtml-editor.h
===================================================================
--- components/editor/gtkhtml-editor.h	(revision 0)
+++ components/editor/gtkhtml-editor.h	(revision 0)
@@ -0,0 +1,157 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_EDITOR_H
+#define GTKHTML_EDITOR_H
+
+#include <gtkhtml/gtkhtml.h>
+
+#include <gtkhtml-editor-common.h>
+#include <gtkhtml-editor-actions.h>
+#include <gtkhtml-editor-widgets.h>
+
+#include <gtkhtml-spell-checker.h>
+#include <gtkhtml-spell-language.h>
+
+#include <stdarg.h>
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_EDITOR \
+	(gtkhtml_editor_get_type ())
+#define GTKHTML_EDITOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_EDITOR, GtkhtmlEditor))
+#define GTKHTML_EDITOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_EDITOR, GtkhtmlEditorClass))
+#define GTKHTML_IS_EDITOR(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_EDITOR))
+#define GTKHTML_IS_EDITOR_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_EDITOR))
+#define GTKHTML_EDITOR_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_EDITOR, GtkhtmlEditorClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlEditor GtkhtmlEditor;
+typedef struct _GtkhtmlEditorClass GtkhtmlEditorClass;
+typedef struct _GtkhtmlEditorPrivate GtkhtmlEditorPrivate;
+
+struct _GtkhtmlEditor {
+	GtkWindow parent;
+	GtkWidget *vbox;
+	GtkhtmlEditorPrivate *priv;
+};
+
+struct _GtkhtmlEditorClass {
+	GtkWindowClass parent_class;
+
+	void		(*cut_clipboard)	(GtkhtmlEditor *editor);
+	void		(*copy_clipboard)	(GtkhtmlEditor *editor);
+	void		(*paste_clipboard)	(GtkhtmlEditor *editor);
+	void		(*select_all)		(GtkhtmlEditor *editor);
+};
+
+GType		gtkhtml_editor_get_type		(void);
+GtkWidget *	gtkhtml_editor_new		(void);
+GtkHTML *	gtkhtml_editor_get_html		(GtkhtmlEditor *editor);
+GtkUIManager *	gtkhtml_editor_get_ui_manager	(GtkhtmlEditor *editor);
+GtkAction *	gtkhtml_editor_get_action	(GtkhtmlEditor *editor,
+						 const gchar *action_name);
+GtkWidget *	gtkhtml_editor_get_widget	(GtkhtmlEditor *editor,
+						 const gchar *widget_name);
+GtkWidget *	gtkhtml_editor_get_managed_widget
+						(GtkhtmlEditor *editor,
+						 const gchar *widget_path);
+const gchar *	gtkhtml_editor_get_current_folder
+						(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_current_folder
+						(GtkhtmlEditor *editor,
+						 const gchar *current_folder);
+const gchar *	gtkhtml_editor_get_filename	(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_filename	(GtkhtmlEditor *editor,
+						 const gchar *filename);
+gboolean	gtkhtml_editor_get_html_mode	(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_html_mode	(GtkhtmlEditor *editor,
+						 gboolean html_mode);
+gboolean	gtkhtml_editor_get_inline_spelling
+						(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_inline_spelling
+						(GtkhtmlEditor *editor,
+						 gboolean inline_spelling);
+gboolean	gtkhtml_editor_get_magic_links	(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_magic_links	(GtkhtmlEditor *editor,
+						 gboolean magic_links);
+gboolean	gtkhtml_editor_get_magic_smileys(GtkhtmlEditor *editor);
+void		gtkhtml_editor_set_magic_smileys(GtkhtmlEditor *editor,
+						 gboolean magic_smileys);
+gint		gtkhtml_editor_file_chooser_dialog_run
+						(GtkhtmlEditor *editor,
+						 GtkWidget *dialog);
+
+/*****************************************************************************
+ * High-Level Editing Interface
+ *****************************************************************************/
+
+gchar *		gtkhtml_editor_get_text_html	(GtkhtmlEditor *editor,
+						 gsize *length);
+gchar *		gtkhtml_editor_get_text_plain	(GtkhtmlEditor *editor,
+						 gsize *length);
+void		gtkhtml_editor_set_text_html	(GtkhtmlEditor *editor,
+						 const gchar *text,
+						 gssize length);
+gboolean	gtkhtml_editor_save		(GtkhtmlEditor *editor,
+						 const gchar *filename,
+						 gboolean as_html,
+						 GError **error);
+const gchar *	gtkhtml_editor_get_paragraph_data
+						(GtkhtmlEditor *editor,
+						 const gchar *key);
+gboolean	gtkhtml_editor_set_paragraph_data
+						(GtkhtmlEditor *editor,
+						 const gchar *key,
+						 const gchar *value);
+gboolean	gtkhtml_editor_run_command	(GtkhtmlEditor *editor,
+						 const gchar *command);
+gboolean	gtkhtml_editor_is_paragraph_empty
+						(GtkhtmlEditor *editor);
+gboolean	gtkhtml_editor_is_previous_paragraph_empty
+						(GtkhtmlEditor *editor);
+void		gtkhtml_editor_insert_html	(GtkhtmlEditor *editor,
+						 const gchar *html_text);
+gboolean	gtkhtml_editor_search_by_data	(GtkhtmlEditor *editor,
+						 glong level,
+						 const gchar *key,
+						 const gchar *value);
+void		gtkhtml_editor_freeze		(GtkhtmlEditor *editor);
+void		gtkhtml_editor_thaw		(GtkhtmlEditor *editor);
+void		gtkhtml_editor_undo_begin	(GtkhtmlEditor *editor,
+						 const gchar *undo_name,
+						 const gchar *redo_name);
+void		gtkhtml_editor_undo_end		(GtkhtmlEditor *editor);
+gboolean	gtkhtml_editor_has_undo		(GtkhtmlEditor *editor);
+void		gtkhtml_editor_drop_undo	(GtkhtmlEditor *editor);
+
+G_END_DECLS
+
+#endif /* GTKHTML_EDITOR_H */
Index: components/editor/gtkhtml-editor-private.c
===================================================================
--- components/editor/gtkhtml-editor-private.c	(revision 0)
+++ components/editor/gtkhtml-editor-private.c	(revision 0)
@@ -0,0 +1,830 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-private.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-editor-private.h"
+
+#include <glade/glade.h>
+#include <glade/glade-build.h>
+
+/* Regular expressions */
+#define CTL	"\\x00-\\x1f\\x7f"
+#define SEP	"\\x09\\x20\\(\\)<>@,;:\\\\\"/\\[\\]\\?=\\{\\}"
+#define TOKEN	"[^" CTL SEP "]+"
+
+/************************ Begin Spell Dialog Callbacks ***********************/
+
+static void
+editor_set_word (GtkhtmlEditor *editor,
+                 GtkhtmlSpellDialog *dialog)
+{
+	GtkHTML *html;
+	gchar *word;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_select_spell_word_editable (html->engine);
+
+	word = html_engine_get_spell_word (html->engine);
+	gtkhtml_spell_dialog_set_word (dialog, word);
+	g_free (word);
+}
+
+static void
+editor_next_word_cb (GtkhtmlEditor *editor,
+                     GtkhtmlSpellDialog *dialog)
+{
+	if (gtkhtml_editor_next_spell_error (editor))
+		editor_set_word (editor, dialog);
+	else
+		gtkhtml_spell_dialog_close (dialog);
+}
+
+static void
+editor_prev_word_cb (GtkhtmlEditor *editor,
+                     GtkhtmlSpellDialog *dialog)
+{
+	if (gtkhtml_editor_prev_spell_error (editor))
+		editor_set_word (editor, dialog);
+	else
+		gtkhtml_spell_dialog_close (dialog);
+}
+
+static void
+editor_recheck_cb (GtkhtmlEditor *editor,
+                   GtkhtmlSpellDialog *dialog)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+	html_engine_spell_check (html->engine);
+}
+
+static void
+editor_replace_cb (GtkhtmlEditor *editor,
+                   const gchar *correction,
+		   GtkhtmlSpellDialog *dialog)
+{
+	GtkHTML *html;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_replace_spell_word_with (html->engine, correction);
+	gtkhtml_spell_dialog_next_word (dialog);
+}
+
+static void
+editor_replace_all_cb (GtkhtmlEditor *editor,
+                       const gchar *correction,
+                       GtkhtmlSpellDialog *dialog)
+{
+	GtkHTML *html;
+	gchar *misspelled;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	/* Replace this occurrence. */
+	misspelled = html_engine_get_spell_word (html->engine);
+	html_engine_replace_spell_word_with (html->engine, correction);
+
+	/* Replace all subsequent occurrences. */
+	while (gtkhtml_editor_next_spell_error (editor)) {
+		gchar *word;
+
+		word = html_engine_get_spell_word (html->engine);
+		if (g_str_equal (word, misspelled))
+			html_engine_replace_spell_word_with (
+				html->engine, correction);
+		g_free (word);
+	}
+
+	/* Jump to beginning of document (XXX is this right?) */
+	html_engine_beginning_of_document (html->engine);
+	gtkhtml_spell_dialog_next_word (dialog);
+
+	g_free (misspelled);
+}
+
+/************************* End Spell Dialog Callbacks ************************/
+
+void
+gtkhtml_editor_private_init (GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorPrivate *priv = editor->priv;
+
+	GtkHTML *html;
+	GtkWidget *widget;
+	GtkToolItem *tool_item;
+	gchar *filename;
+	GError *error = NULL;
+
+	priv->manager = gtk_ui_manager_new ();
+	priv->core_actions = gtk_action_group_new ("core");
+	priv->html_actions = gtk_action_group_new ("html");
+	priv->context_actions = gtk_action_group_new ("core-context");
+	priv->html_context_actions = gtk_action_group_new ("html-context");
+	priv->language_actions = gtk_action_group_new ("language");
+	priv->spell_check_actions = gtk_action_group_new ("spell-check");
+	priv->suggestion_actions = gtk_action_group_new ("suggestion");
+
+	/* GtkhtmlSpellLanguage -> GtkhtmlSpellChecker */
+	priv->available_spell_checkers = g_hash_table_new_full (
+		g_direct_hash, g_direct_equal,
+		(GDestroyNotify) NULL,
+		(GDestroyNotify) g_object_unref);
+
+	/* GtkhtmlSpellLanguage -> UI Merge ID */
+	priv->spell_suggestion_menus =
+		g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	filename = gtkhtml_editor_find_data_file ("gtkhtml-editor.ui");
+	gtk_ui_manager_add_ui_from_file (priv->manager, filename, &error);
+	g_free (filename);
+
+	if (error != NULL) {
+		/* Henceforth, bad things start happening. */
+		g_critical ("%s", error->message);
+		g_clear_error (&error);
+	}
+
+	gtkhtml_editor_actions_init (editor);
+
+	gtk_window_add_accel_group (
+		GTK_WINDOW (editor),
+		gtk_ui_manager_get_accel_group (priv->manager));
+
+	glade_register_widget (
+		GTKHTML_TYPE_COLOR_COMBO,
+		glade_standard_build_widget, NULL, NULL);
+
+	glade_register_widget (
+		GTKHTML_TYPE_COLOR_SWATCH,
+		glade_standard_build_widget, NULL, NULL);
+
+	glade_register_widget (
+		GTKHTML_TYPE_COMBO_BOX,
+		glade_standard_build_widget, NULL, NULL);
+
+	glade_provide ("gtkhtml-editor");
+
+	filename = gtkhtml_editor_find_data_file ("gtkhtml-editor.glade");
+	priv->glade_xml = glade_xml_new (filename, NULL, NULL);
+	glade_xml_signal_autoconnect (priv->glade_xml);
+	g_free (filename);
+
+	/* Construct main window widgets. */
+
+	widget = gtkhtml_editor_get_managed_widget (editor, "/main-menu");
+	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
+	priv->main_menu = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtkhtml_editor_get_managed_widget (editor, "/main-toolbar");
+	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
+	priv->main_toolbar = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtkhtml_editor_get_managed_widget (editor, "/edit-toolbar");
+	gtk_toolbar_set_style (GTK_TOOLBAR (widget), GTK_TOOLBAR_ICONS);
+	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, FALSE, FALSE, 0);
+	priv->edit_toolbar = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_box_pack_start (GTK_BOX (editor->vbox), widget, TRUE, TRUE, 0);
+	priv->scrolled_window = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	widget = gtk_html_new ();
+	gtk_html_load_empty (GTK_HTML (widget));
+	gtk_html_set_editable (GTK_HTML (widget), TRUE);
+	gtk_container_add (GTK_CONTAINER (priv->scrolled_window), widget);
+	priv->edit_area = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Add some combo boxes to the "edit" toolbar. */
+
+	tool_item = gtk_separator_tool_item_new ();
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, 0);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	tool_item = gtk_tool_item_new ();
+	widget = gtkhtml_combo_box_new_with_action (
+		GTK_RADIO_ACTION (ACTION (STYLE_NORMAL)));
+	gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE);
+	gtk_container_add (GTK_CONTAINER (tool_item), widget);
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, 0);
+	priv->style_combo_box = g_object_ref (widget);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	tool_item = gtk_separator_tool_item_new ();
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, 0);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	tool_item = gtk_tool_item_new ();
+	widget = gtkhtml_combo_box_new_with_action (
+		GTK_RADIO_ACTION (ACTION (SIZE_PLUS_ZERO)));
+	gtk_combo_box_set_focus_on_click (GTK_COMBO_BOX (widget), FALSE);
+	gtk_container_add (GTK_CONTAINER (tool_item), widget);
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, 0);
+	priv->size_combo_box = g_object_ref (widget);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	tool_item = gtk_separator_tool_item_new ();
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, -1);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	tool_item = gtk_tool_item_new ();
+	widget = gtkhtml_color_combo_new ();
+	gtk_container_add (GTK_CONTAINER (tool_item), widget);
+	gtk_toolbar_insert (GTK_TOOLBAR (priv->edit_toolbar), tool_item, -1);
+	priv->color_combo_box = g_object_ref (widget);
+	gtk_widget_show_all (GTK_WIDGET (tool_item));
+
+	/* Initialize painters (requires "edit_area"). */
+
+	html = gtkhtml_editor_get_html (editor);
+	gtk_widget_ensure_style (GTK_WIDGET (html));
+	priv->html_painter = g_object_ref (html->engine->painter);
+	priv->plain_painter = html_plain_painter_new (priv->edit_area, TRUE);
+
+	/* Add input methods to the context menu. */
+
+	widget = gtkhtml_editor_get_managed_widget (
+		editor, "/context-menu/context-input-methods-menu");
+	widget = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+	gtk_im_multicontext_append_menuitems (
+		GTK_IM_MULTICONTEXT (html->priv->im_context),
+		GTK_MENU_SHELL (widget));
+
+	/* Configure color stuff. */
+
+	priv->palette = gtkhtml_color_palette_new ();
+	priv->text_color = gtkhtml_color_state_new ();
+
+	gtkhtml_color_state_set_default_label (
+		priv->text_color, _("Automatic"));
+	gtkhtml_color_state_set_palette (
+		priv->text_color, priv->palette);
+
+	/* Text color widgets share state. */
+
+	widget = priv->color_combo_box;
+	gtkhtml_color_combo_set_state (
+		GTKHTML_COLOR_COMBO (widget), priv->text_color);
+
+	widget = WIDGET (TEXT_PROPERTIES_COLOR_COMBO);
+	gtkhtml_color_combo_set_state (
+		GTKHTML_COLOR_COMBO (widget), priv->text_color);
+
+	/* These color widgets share a custom color palette. */
+
+	widget = WIDGET (CELL_PROPERTIES_COLOR_COMBO);
+	gtkhtml_color_combo_set_palette (
+		GTKHTML_COLOR_COMBO (widget), priv->palette);
+
+	widget = WIDGET (PAGE_PROPERTIES_BACKGROUND_COLOR_COMBO);
+	gtkhtml_color_combo_set_palette (
+		GTKHTML_COLOR_COMBO (widget), priv->palette);
+
+	widget = WIDGET (PAGE_PROPERTIES_LINK_COLOR_COMBO);
+	gtkhtml_color_combo_set_palette (
+		GTKHTML_COLOR_COMBO (widget), priv->palette);
+
+	widget = WIDGET (TABLE_PROPERTIES_COLOR_COMBO);
+	gtkhtml_color_combo_set_palette (
+		GTKHTML_COLOR_COMBO (widget), priv->palette);
+}
+
+void
+gtkhtml_editor_private_dispose (GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorPrivate *priv = editor->priv;
+
+	/* Disconnect signal handlers from the color
+	 * state object since it may live on. */
+	if (priv->text_color != NULL) {
+		g_signal_handlers_disconnect_matched (
+			priv->text_color, G_SIGNAL_MATCH_DATA,
+			0, 0, NULL, NULL, editor);
+	}
+
+	DISPOSE (priv->manager);
+	DISPOSE (priv->core_actions);
+	DISPOSE (priv->html_actions);
+	DISPOSE (priv->context_actions);
+	DISPOSE (priv->html_context_actions);
+	DISPOSE (priv->language_actions);
+	DISPOSE (priv->spell_check_actions);
+	DISPOSE (priv->suggestion_actions);
+	DISPOSE (priv->glade_xml);
+
+	DISPOSE (priv->html_painter);
+	DISPOSE (priv->plain_painter);
+
+	g_hash_table_remove_all (priv->available_spell_checkers);
+
+	g_list_foreach (
+		priv->active_spell_checkers,
+		(GFunc) g_object_unref, NULL);
+	g_list_free (priv->active_spell_checkers);
+	priv->active_spell_checkers = NULL;
+
+	DISPOSE (priv->main_menu);
+	DISPOSE (priv->main_toolbar);
+	DISPOSE (priv->edit_toolbar);
+	DISPOSE (priv->edit_area);
+
+	DISPOSE (priv->color_combo_box);
+	DISPOSE (priv->size_combo_box);
+	DISPOSE (priv->style_combo_box);
+	DISPOSE (priv->scrolled_window);
+
+	DISPOSE (priv->palette);
+	DISPOSE (priv->text_color);
+}
+
+void
+gtkhtml_editor_private_finalize (GtkhtmlEditor *editor)
+{
+	GtkhtmlEditorPrivate *priv = editor->priv;
+
+	g_hash_table_destroy (priv->available_spell_checkers);
+	g_hash_table_destroy (priv->spell_suggestion_menus);
+
+	g_free (priv->filename);
+	g_free (priv->current_folder);
+}
+
+gchar *
+gtkhtml_editor_find_data_file (const gchar *basename)
+{
+	const gchar * const *datadirs;
+	gchar *filename;
+
+	g_return_val_if_fail (basename != NULL, NULL);
+
+	/* Support running directly from the source tree. */
+	filename = g_build_filename (".", basename, NULL);
+	if (g_file_test (filename, G_FILE_TEST_EXISTS))
+		return filename;
+	g_free (filename);
+
+	datadirs = g_get_system_data_dirs ();
+	while (*datadirs != NULL) {
+		filename = g_build_filename (
+			*datadirs++, GTKHTML_RELEASE_STRING, basename, NULL);
+		if (g_file_test (filename, G_FILE_TEST_EXISTS))
+			return filename;
+		g_free (filename);
+	}
+
+	g_critical ("Could not locate '%s'", basename);
+
+	return NULL;
+}
+
+gchar *
+gtkhtml_editor_get_file_charset (const gchar *filename)
+{
+	GRegex *regex;
+	GMatchInfo *match_info;
+	gchar *charset = NULL;
+	gchar *contents;
+	GError *error = NULL;
+
+	g_return_val_if_fail (filename != NULL, NULL);
+
+	if (!g_file_get_contents (filename, &contents, NULL, &error))
+		goto exit;
+
+	/* Search for "charset = token" as defined in RFC 2616. */
+	regex = g_regex_new (
+		"charset[ \t]*=[ \t]*(" TOKEN ")",
+		G_REGEX_CASELESS, 0, &error);
+	if (regex == NULL)
+		goto exit;
+
+	/* Extract "token", which should be the charset name. */
+	g_regex_match (regex, contents, 0, &match_info);
+	if (g_match_info_matches (match_info))
+		charset = g_match_info_fetch (match_info, 1);
+
+	g_match_info_free (match_info);
+	g_regex_unref (regex);
+
+exit:
+	if (error != NULL) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+
+	g_free (contents);
+
+	return charset;
+}
+
+gboolean
+gtkhtml_editor_get_file_contents (const gchar *filename,
+                                  const gchar *encoding,
+                                  gchar **contents,
+                                  gsize *length,
+                                  GError **error)
+{
+	GIOChannel *channel;
+	GIOStatus status;
+
+	g_return_val_if_fail (filename != NULL, FALSE);
+	g_return_val_if_fail (contents != NULL, FALSE);
+
+	channel = g_io_channel_new_file (filename, "r", error);
+	if (channel == NULL)
+		return FALSE;
+
+	status = g_io_channel_set_encoding (channel, encoding, error);
+	if (status == G_IO_STATUS_ERROR) {
+		g_io_channel_unref (channel);
+		return FALSE;
+	}
+
+	status = g_io_channel_read_to_end (channel, contents, length, error);
+	if (status == G_IO_STATUS_ERROR) {
+		g_io_channel_unref (channel);
+		return FALSE;
+	}
+
+	g_io_channel_unref (channel);
+
+	return TRUE;
+}
+
+gint
+gtkhtml_editor_insert_file (GtkhtmlEditor *editor,
+                            const gchar *title,
+                            GCallback response_cb)
+{
+	GtkWidget *dialog;
+	gint response;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), GTK_RESPONSE_CANCEL);
+	g_return_val_if_fail (response_cb != NULL, GTK_RESPONSE_CANCEL);
+
+	dialog = gtk_file_chooser_dialog_new (
+		title, GTK_WINDOW (editor),
+		GTK_FILE_CHOOSER_ACTION_OPEN,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+		NULL);
+
+	gtk_dialog_set_default_response (
+		GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+
+	g_signal_connect (dialog, "response", response_cb, editor);
+
+	response = gtkhtml_editor_file_chooser_dialog_run (editor, dialog);
+
+	gtk_widget_destroy (dialog);
+
+	return response;
+}
+
+void
+gtkhtml_editor_spell_check (GtkhtmlEditor *editor,
+                            gboolean whole_document)
+{
+	GtkHTML *html;
+	guint position;
+	gboolean inline_spelling;
+	gboolean spelling_errors;
+
+	g_return_if_fail (GTKHTML_IS_EDITOR (editor));
+
+	html = gtkhtml_editor_get_html (editor);
+	position = html->engine->cursor->position;
+	inline_spelling = gtk_html_get_inline_spelling (html);
+
+	if (whole_document) {
+		html_engine_disable_selection (html->engine);
+		html_engine_beginning_of_document (html->engine);
+		gtk_html_set_inline_spelling (html, TRUE);
+	}
+
+	spelling_errors =
+		!html_engine_spell_word_is_valid (html->engine) ||
+		gtkhtml_editor_next_spell_error (editor);
+
+	if (spelling_errors) {
+		GtkWidget *dialog;
+
+		dialog = gtkhtml_spell_dialog_new (GTK_WINDOW (editor));
+
+		gtkhtml_spell_dialog_set_spell_checkers (
+			GTKHTML_SPELL_DIALOG (dialog),
+			editor->priv->active_spell_checkers);
+
+		editor_set_word (editor, GTKHTML_SPELL_DIALOG (dialog));
+
+		g_signal_connect_swapped (
+			dialog, "added",
+			G_CALLBACK (editor_recheck_cb), editor);
+
+		g_signal_connect_swapped (
+			dialog, "ignored",
+			G_CALLBACK (editor_recheck_cb), editor);
+
+		g_signal_connect_swapped (
+			dialog, "next-word",
+			G_CALLBACK (editor_next_word_cb), editor);
+
+		g_signal_connect_swapped (
+			dialog, "prev-word",
+			G_CALLBACK (editor_prev_word_cb), editor);
+
+		g_signal_connect_swapped (
+			dialog, "replace",
+			G_CALLBACK (editor_replace_cb), editor);
+
+		g_signal_connect_swapped (
+			dialog, "replace-all",
+			G_CALLBACK (editor_replace_all_cb), editor);
+
+		gtk_dialog_run (GTK_DIALOG (dialog));
+
+		gtk_widget_destroy (dialog);
+	}
+
+	/* XXX Restore original inline spelling value. */
+}
+
+gboolean
+gtkhtml_editor_next_spell_error (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	gboolean found = FALSE;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_disable_selection (html->engine);
+
+	while (!found && html_engine_forward_word (html->engine))
+		found = !html_engine_spell_word_is_valid (html->engine);
+
+	return found;
+}
+
+gboolean
+gtkhtml_editor_prev_spell_error (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	gboolean found = FALSE;
+
+	g_return_val_if_fail (GTKHTML_IS_EDITOR (editor), FALSE);
+
+	html = gtkhtml_editor_get_html (editor);
+
+	html_engine_disable_selection (html->engine);
+	html_engine_backward_word (html->engine);
+
+	while (!found && html_engine_backward_word (html->engine))
+		found = !html_engine_spell_word_is_valid (html->engine);
+
+	return found;
+}
+
+/* Action callback for context menu spelling suggestions.
+ * XXX This should really be in gtkhtml-editor-actions.c */
+static void
+action_context_spell_suggest_cb (GtkAction *action,
+                                 GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	gchar *label;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	/* The action's label is the replacement word. */
+	g_object_get (action, "label", &label, NULL);
+	g_return_if_fail (label != NULL);
+
+	html_engine_replace_spell_word_with (html->engine, label);
+
+	g_free (label);
+}
+
+/* Helper for gtkhtml_editor_update_context() */
+static void
+editor_spell_checkers_foreach (GtkhtmlSpellChecker *checker,
+                               GtkhtmlEditor *editor)
+{
+	const GtkhtmlSpellLanguage *language;
+	const gchar *language_code;
+	GtkActionGroup *action_group;
+	GtkUIManager *manager;
+	GtkHTML *html;
+	GList *list;
+	gchar *path;
+	gchar *word;
+	gint count = 0;
+	guint merge_id;
+
+	language = gtkhtml_spell_checker_get_language (checker);
+	language_code = gtkhtml_spell_language_get_code (language);
+
+	html = gtkhtml_editor_get_html (editor);
+	word = html_engine_get_spell_word (html->engine);
+	list = gtkhtml_spell_checker_get_suggestions (checker, word, -1);
+
+	manager = gtkhtml_editor_get_ui_manager (editor);
+	action_group = editor->priv->suggestion_actions;
+	merge_id = editor->priv->spell_suggestions_merge_id;
+
+	path = g_strdup_printf (
+		"/context-menu/context-spell-suggest/"
+		"context-spell-suggest-%s-menu", language_code);
+
+	while (list != NULL) {
+		gchar *action_label = list->data;
+		gchar *action_name;
+		GtkAction *action;
+
+		/* Action name just needs to be unique. */
+		action_name = g_strdup_printf (
+			"suggest-%s-%d", language_code, count++);
+
+		action = gtk_action_new (
+			action_name, action_label, NULL, NULL);
+
+		g_signal_connect (
+			action, "activate", G_CALLBACK (
+			action_context_spell_suggest_cb), editor);
+
+		gtk_action_group_add_action (action_group, action);
+
+		gtk_ui_manager_add_ui (
+			manager, merge_id, path,
+			action_name, action_name,
+			GTK_UI_MANAGER_AUTO, FALSE);
+
+		g_free (action_label);
+		g_free (action_name);
+
+		list = g_list_delete_link (list, list);
+	}
+
+	g_free (path);
+	g_free (word);
+}
+
+void
+gtkhtml_editor_update_context (GtkhtmlEditor *editor)
+{
+	GtkHTML *html;
+	HTMLType type;
+	HTMLObject *object;
+	GtkUIManager *manager;
+	GtkActionGroup *action_group;
+	GList *list;
+	gboolean visible;
+	guint merge_id;
+
+	html = gtkhtml_editor_get_html (editor);
+	manager = gtkhtml_editor_get_ui_manager (editor);
+	gtk_html_update_styles (html);
+
+	/* Update context menu item visibility. */
+
+	object = html->engine->cursor->object;
+
+	if (object != NULL)
+		type = HTML_OBJECT_TYPE (object);
+	else
+		type = HTML_TYPE_NONE;
+
+	visible = (type == HTML_TYPE_IMAGE);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_IMAGE), visible);
+
+	visible = (type == HTML_TYPE_LINKTEXT);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_LINK), visible);
+
+	visible = (type == HTML_TYPE_RULE);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_RULE), visible);
+
+	visible = (type == HTML_TYPE_TEXT);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_TEXT), visible);
+
+	visible =
+		gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_IMAGE)) ||
+		gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_LINK)) ||
+		gtk_action_get_visible (ACTION (CONTEXT_PROPERTIES_TEXT));
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_PARAGRAPH), visible);
+
+	/* Set to visible if any of these are true:
+	 *   - Selection is active and contains a link.
+	 *   - Cursor is on a link.
+	 *   - Cursor is on an image that has a URL or target.
+	 */
+	visible =
+		(html_engine_is_selection_active (html->engine) &&
+		 html_engine_selection_contains_link (html->engine)) ||
+		(type == HTML_TYPE_LINKTEXT) ||
+		(type == HTML_TYPE_IMAGE &&
+			(HTML_IMAGE (object)->url != NULL ||
+			 HTML_IMAGE (object)->target != NULL));
+	gtk_action_set_visible (ACTION (CONTEXT_REMOVE_LINK), visible);
+
+	/* Get the parent object. */
+	object = (object != NULL) ? object->parent : NULL;
+
+	/* Get the grandparent object. */
+	object = (object != NULL) ? object->parent : NULL;
+
+	if (object != NULL)
+		type = HTML_OBJECT_TYPE (object);
+	else
+		type = HTML_TYPE_NONE;
+
+	visible = (type == HTML_TYPE_TABLECELL);
+	gtk_action_set_visible (ACTION (CONTEXT_DELETE_CELL), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_DELETE_COLUMN), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_DELETE_ROW), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_DELETE_TABLE), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_AFTER), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_INSERT_COLUMN_BEFORE), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_ABOVE), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_INSERT_ROW_BELOW), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_INSERT_TABLE), visible);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_CELL), visible);
+
+	/* Get the great grandparent object. */
+	object = (object != NULL) ? object->parent : NULL;
+
+	if (object != NULL)
+		type = HTML_OBJECT_TYPE (object);
+	else
+		type = HTML_TYPE_NONE;
+
+	/* Note the |= (cursor must be in a table cell). */
+	visible |= (type == HTML_TYPE_TABLE);
+	gtk_action_set_visible (ACTION (CONTEXT_PROPERTIES_TABLE), visible);
+
+	/********************** Spell Check Suggestions **********************/
+
+	object = html->engine->cursor->object;
+	action_group = editor->priv->suggestion_actions;
+
+	/* Remove the old content from the context menu. */
+	merge_id = editor->priv->spell_suggestions_merge_id;
+	if (merge_id > 0) {
+		gtk_ui_manager_remove_ui (manager, merge_id);
+		editor->priv->spell_suggestions_merge_id = 0;
+	}
+
+	/* Clear the action group for spelling suggestions. */
+	list = gtk_action_group_list_actions (action_group);
+	while (list != NULL) {
+		GtkAction *action = list->data;
+
+		gtk_action_group_remove_action (action_group, action);
+		list = g_list_delete_link (list, list);
+	}
+
+	/* Decide if we should show spell checking items. */
+	visible =
+		!html_engine_is_selection_active (html->engine) &&
+		object != NULL && html_object_is_text (object) &&
+		!html_engine_spell_word_is_valid (html->engine);
+	action_group = editor->priv->spell_check_actions;
+	gtk_action_group_set_visible (action_group, visible);
+
+	/* Exit early if spell checking items are invisible. */
+	if (!visible)
+		return;
+
+	list = editor->priv->active_spell_checkers;
+	merge_id = gtk_ui_manager_new_merge_id (manager);
+	editor->priv->spell_suggestions_merge_id = merge_id;
+
+	/* Add actions and context menu content for active languages. */
+	g_list_foreach (list, (GFunc) editor_spell_checkers_foreach, editor);
+}
Index: components/editor/gtkhtml-editor-widgets.h
===================================================================
--- components/editor/gtkhtml-editor-widgets.h	(revision 0)
+++ components/editor/gtkhtml-editor-widgets.h	(revision 0)
@@ -0,0 +1,225 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-widgets.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_EDITOR_WIDGETS_H
+#define GTKHTML_EDITOR_WIDGETS_H
+
+#define GTKHTML_EDITOR_WIDGET(editor, name) \
+	(gtkhtml_editor_get_widget ((editor), (name)))
+
+/* Cell Properties Window */
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_CELL_RADIO_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-cell-radio-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-color-combo")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_COLUMN_RADIO_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-column-radio-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_COLUMN_SPAN_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-column-span-spin-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_HEADER_STYLE_CHECK_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-header-style-check-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_HORIZONTAL_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-horizontal-combo-box")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_IMAGE_FILE_CHOOSER(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-image-file-chooser")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_ROW_RADIO_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-row-radio-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_ROW_SPAN_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-row-span-spin-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_TABLE_RADIO_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-table-radio-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_VERTICAL_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-vertical-combo-box")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_WIDTH_CHECK_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-width-check-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_WIDTH_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-width-combo-box")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_WIDTH_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-width-spin-button")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-window")
+#define GTKHTML_EDITOR_WIDGET_CELL_PROPERTIES_WRAP_TEXT_CHECK_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "cell-properties-wrap-text-check-button")
+
+/* Find Window */
+#define GTKHTML_EDITOR_WIDGET_FIND_BACKWARDS(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-backwards")
+#define GTKHTML_EDITOR_WIDGET_FIND_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-button")
+#define GTKHTML_EDITOR_WIDGET_FIND_CASE_SENSITIVE(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-case-sensitive")
+#define GTKHTML_EDITOR_WIDGET_FIND_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-window")
+#define GTKHTML_EDITOR_WIDGET_FIND_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-entry")
+#define GTKHTML_EDITOR_WIDGET_FIND_REGULAR_EXPRESSION(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "find-regular-expression")
+
+/* Image Properties Window */
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_ALIGNMENT_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-alignment-combo-box")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_BORDER_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-border-spin-button")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_DESCRIPTION_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-description-entry")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_HEIGHT_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-height-combo-box")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_HEIGHT_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-height-spin-button")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_SOURCE_FILE_CHOOSER(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-source-file-chooser")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_URL_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-url-button")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_URL_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-url-entry")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_WIDTH_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-width-combo-box")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_WIDTH_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-width-spin-button")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-window")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_X_PADDING_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-x-padding-spin-button")
+#define GTKHTML_EDITOR_WIDGET_IMAGE_PROPERTIES_Y_PADDING_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "image-properties-y-padding-spin-button")
+
+/* Link Properties Window */
+#define GTKHTML_EDITOR_WIDGET_LINK_PROPERTIES_DESCRIPTION_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "link-properties-description-entry")
+#define GTKHTML_EDITOR_WIDGET_LINK_PROPERTIES_TEST_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "link-properties-test-button")
+#define GTKHTML_EDITOR_WIDGET_LINK_PROPERTIES_URL_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "link-properties-url-entry")
+#define GTKHTML_EDITOR_WIDGET_LINK_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "link-properties-window")
+
+/* Page Properties Window */
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_BACKGROUND_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-background-color-combo")
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_CUSTOM_FILE_CHOOSER(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-custom-file-chooser")
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_LINK_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-link-color-combo")
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_TEMPLATE_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-template-combo-box")
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_TEXT_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-text-color-combo")
+#define GTKHTML_EDITOR_WIDGET_PAGE_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "page-properties-window")
+
+/* Paragraph Properties Window */
+#define GTKHTML_EDITOR_WIDGET_PARAGRAPH_PROPERTIES_CENTER_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "paragraph-properties-center-button")
+#define GTKHTML_EDITOR_WIDGET_PARAGRAPH_PROPERTIES_LEFT_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "paragraph-properties-left-button")
+#define GTKHTML_EDITOR_WIDGET_PARAGRAPH_PROPERTIES_RIGHT_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "paragraph-properties-right-button")
+#define GTKHTML_EDITOR_WIDGET_PARAGRAPH_PROPERTIES_STYLE_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "paragraph-properties-style-combo-box")
+#define GTKHTML_EDITOR_WIDGET_PARAGRAPH_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "paragraph-properties-window")
+
+/* Replace Confirmation Window */
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CONFIRMATION_CLOSE_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-confirmation-close-button")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CONFIRMATION_NEXT_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-confirmation-next-button")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CONFIRMATION_REPLACE_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-confirmation-replace-button")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CONFIRMATION_REPLACE_ALL_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-confirmation-replace-all-button")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CONFIRMATION_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-confirmation-window")
+
+/* Replace Window */
+#define GTKHTML_EDITOR_WIDGET_REPLACE_BACKWARDS(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-backwards")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-button")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_CASE_SENSITIVE(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-case-sensitive")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-entry")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_WITH_ENTRY(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-with-entry")
+#define GTKHTML_EDITOR_WIDGET_REPLACE_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "replace-window")
+
+/* Rule Properties Window */
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_ALIGNMENT_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-alignment-combo-box")
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_SHADED_CHECK_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-shaded-check-button")
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_SIZE_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-size-spin-button")
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_WIDTH_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-width-combo-box")
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_WIDTH_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-width-spin-button")
+#define GTKHTML_EDITOR_WIDGET_RULE_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "rule-properties-window")
+
+/* Spell Check Window */
+#define GTKHTML_EDITOR_WIDGET_SPELL_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "spell-window")
+
+/* Table Properties Window */
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_ALIGNMENT_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-alignment-combo-box")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_BORDER_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-border-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-color-combo")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_COLS_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-cols-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_IMAGE_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-image-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_PADDING_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-padding-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_ROWS_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-rows-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_SPACING_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-spacing-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_WIDTH_CHECK_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-width-check-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_WIDTH_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-width-combo-box")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_WIDTH_SPIN_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-width-spin-button")
+#define GTKHTML_EDITOR_WIDGET_TABLE_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "table-properties-window")
+
+/* Text Properties Window */
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_BOLD_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-bold-button")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_COLOR_COMBO(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-color-combo")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_ITALIC_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-italic-button")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_SIZE_COMBO_BOX(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-size-combo-box")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_STRIKETHROUGH_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-strikethrough-button")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_UNDERLINE_BUTTON(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-underline-button")
+#define GTKHTML_EDITOR_WIDGET_TEXT_PROPERTIES_WINDOW(editor) \
+	GTKHTML_EDITOR_WIDGET ((editor), "text-properties-window")
+
+#endif /* GTKHTML_EDITOR_WIDGETS_H */
Index: components/editor/gtkhtml-editor-private.h
===================================================================
--- components/editor/gtkhtml-editor-private.h	(revision 0)
+++ components/editor/gtkhtml-editor-private.h	(revision 0)
@@ -0,0 +1,193 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-private.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_EDITOR_PRIVATE_H
+#define GTKHTML_EDITOR_PRIVATE_H
+
+#include <gtkhtml-editor.h>
+
+#include <glade/glade.h>
+#include <glib/gi18n-lib.h>
+
+/* Custom Widgets */
+#include "gtkhtml-color-combo.h"
+#include "gtkhtml-color-palette.h"
+#include "gtkhtml-color-swatch.h"
+#include "gtkhtml-combo-box.h"
+#include "gtkhtml-spell-dialog.h"
+
+/* GtkHTML internals */
+#include "gtkhtml-private.h"
+#include "gtkhtmlfontstyle.h"
+#include "htmlclue.h"
+#include "htmlclueflow.h"
+#include "htmlcolor.h"
+#include "htmlcolorset.h"
+#include "htmlcursor.h"
+#include "htmlengine.h"
+#include "htmlengine-edit.h"
+#include "htmlengine-edit-cut-and-paste.h"
+#include "htmlengine-edit-movement.h"
+#include "htmlengine-edit-rule.h"
+#include "htmlengine-edit-table.h"
+#include "htmlengine-edit-tablecell.h"
+#include "htmlengine-edit-text.h"
+#include "htmlengine-search.h"
+#include "htmlimage.h"
+#include "htmlobject.h"
+#include "htmlpainter.h"
+#include "htmlgdkpainter.h"
+#include "htmlplainpainter.h"
+#include "htmlrule.h"
+#include "htmlselection.h"
+#include "htmlsettings.h"
+#include "htmltable.h"
+#include "htmltablecell.h"
+#include "htmltext.h"
+#include "htmltype.h"
+#include "htmlundo.h"
+
+/* Marshalling */
+#include "gtkhtml-editor-marshal.h"
+
+#define GTKHTML_EDITOR_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_EDITOR, GtkhtmlEditorPrivate))
+
+/* Shorthand, requires a variable named "editor". */
+#define ACTION(name)	(GTKHTML_EDITOR_ACTION_##name (editor))
+#define WIDGET(name)	(GTKHTML_EDITOR_WIDGET_##name (editor))
+
+/* For use in dispose() methods. */
+#define DISPOSE(obj) \
+	G_STMT_START { \
+	if ((obj) != NULL) { g_object_unref (obj); (obj) = NULL; } \
+	} G_STMT_END
+
+G_BEGIN_DECLS
+
+typedef enum {
+	TABLE_CELL_SCOPE_CELL,
+	TABLE_CELL_SCOPE_ROW,
+	TABLE_CELL_SCOPE_COLUMN,
+	TABLE_CELL_SCOPE_TABLE
+} TableCellScope;
+
+struct _GtkhtmlEditorPrivate {
+
+	/*** UI Management ***/
+
+	GtkUIManager *manager;
+	GtkActionGroup *core_actions;
+	GtkActionGroup *html_actions;
+	GtkActionGroup *context_actions;
+	GtkActionGroup *html_context_actions;
+	GtkActionGroup *language_actions;
+	GtkActionGroup *spell_check_actions;
+	GtkActionGroup *suggestion_actions;
+	GladeXML *glade_xml;
+
+	/*** Rendering ***/
+
+	HTMLPainter *html_painter;
+	HTMLPainter *plain_painter;
+
+	/*** Spell Checking ***/
+
+	GHashTable *available_spell_checkers;
+	GHashTable *spell_suggestion_menus;
+	GList *active_spell_checkers;
+	guint spell_suggestions_merge_id;
+
+	/*** Main Window Widgets ***/
+
+	GtkWidget *main_menu;
+	GtkWidget *main_toolbar;
+	GtkWidget *edit_toolbar;
+	GtkWidget *edit_area;
+
+	GtkWidget *color_combo_box;
+	GtkWidget *size_combo_box;
+	GtkWidget *style_combo_box;
+	GtkWidget *scrolled_window;
+
+	/*** Cell Properties State ***/
+
+	HTMLObject *cell_object;
+	HTMLObject *cell_parent;
+	TableCellScope cell_scope;
+
+	/*** Image Properties State ***/
+
+	HTMLObject *image_object;
+
+	/*** Link Properties State ***/
+
+	HTMLObject *link_object;
+	gint link_start_offset;
+	gint link_end_offset;
+	gboolean link_custom_description;
+
+	/*** Rule Properties State ***/
+
+	HTMLObject *rule_object;
+
+	/*** Table Properties State ***/
+
+	HTMLObject *table_object;
+
+	/*** Miscellaneous ***/
+
+	/* Note, 'filename' is not used by GtkhtmlEditor itself but is here
+	 * for the convenience of extending the editor to support saving to
+	 * a file. */
+
+	gchar *filename;
+	gchar *current_folder;
+	GtkhtmlColorPalette *palette;
+	GtkhtmlColorState *text_color;
+};
+
+void		gtkhtml_editor_private_init	 (GtkhtmlEditor *editor);
+void		gtkhtml_editor_private_dispose	 (GtkhtmlEditor *editor);
+void		gtkhtml_editor_private_finalize	 (GtkhtmlEditor *editor);
+
+/* Private Utilities */
+
+void		gtkhtml_editor_actions_init	 (GtkhtmlEditor *editor);
+gchar *		gtkhtml_editor_find_data_file	 (const gchar *basename);
+gchar *		gtkhtml_editor_get_file_charset	 (const gchar *filename);
+gboolean	gtkhtml_editor_get_file_contents (const gchar *filename,
+						  const gchar *encoding,
+						  gchar **contents,
+						  gsize *length,
+						  GError **error);
+gint		gtkhtml_editor_insert_file	 (GtkhtmlEditor *editor,
+						  const gchar *title,
+						  GCallback response_cb);
+void		gtkhtml_editor_spell_check	 (GtkhtmlEditor *editor,
+						  gboolean whole_document);
+gboolean	gtkhtml_editor_next_spell_error	 (GtkhtmlEditor *editor);
+gboolean	gtkhtml_editor_prev_spell_error	 (GtkhtmlEditor *editor);
+void		gtkhtml_editor_update_context	 (GtkhtmlEditor *editor);
+
+G_END_DECLS
+
+#endif /* GTKHTML_EDITOR_PRIVATE_H */
Index: components/editor/gtkhtml-editor.xml
===================================================================
--- components/editor/gtkhtml-editor.xml	(revision 0)
+++ components/editor/gtkhtml-editor.xml	(revision 0)
@@ -0,0 +1,28 @@
+<glade-catalog name="gtkhtml-editor" library="glade-gtkhtml-editor" depends="gtk+">
+
+  <glade-widget-classes>
+    <glade-widget-class name="GtkhtmlColorCombo" generic-name="color-combo" title="Color Combo Box">
+      <properties>
+        <property id="color"/>
+        <property id="popup-shown"/>
+      </properties>
+    </glade-widget-class>
+    <glade-widget-class name="GtkhtmlColorSwatch" generic-name="color-swatch" title="Color Swatch">
+      <properties>
+        <property id="color"/>
+      </properties>
+    </glade-widget-class>
+    <glade-widget-class name="GtkhtmlComboBox" generic-name="combo-box" title="Radio Action Combo Box">
+      <properties>
+        <property id="action"/>
+      </properties>
+    </glade-widget-class>
+  </glade-widget-classes>
+
+  <glade-widget-group name="widgets" title="GtkHTML Editor">
+    <glade-widget-class-ref name="GtkhtmlColorCombo"/>
+    <glade-widget-class-ref name="GtkhtmlColorSwatch"/>
+    <glade-widget-class-ref name="GtkhtmlComboBox"/>
+  </glade-widget-group>
+
+</glade-catalog>
Index: components/editor/gtkhtml-editor-marshal.list
===================================================================
--- components/editor/gtkhtml-editor-marshal.list	(revision 0)
+++ components/editor/gtkhtml-editor-marshal.list	(revision 0)
@@ -0,0 +1 @@
+VOID:STRING,POINTER
Index: components/editor/gtkhtml-spell-dialog.c
===================================================================
--- components/editor/gtkhtml-spell-dialog.c	(revision 0)
+++ components/editor/gtkhtml-spell-dialog.c	(revision 0)
@@ -0,0 +1,807 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-dialog.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-spell-dialog.h"
+
+#include <glib/gi18n-lib.h>
+#include "gtkhtml-spell-checker.h"
+
+#define GTKHTML_SPELL_DIALOG_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_SPELL_DIALOG, GtkhtmlSpellDialogPrivate))
+
+enum {
+	COMBO_COLUMN_CHECKER,		/* GTKHTML_TYPE_SPELL_CHECKER */
+	COMBO_COLUMN_TEXT		/* G_TYPE_STRING */
+};
+
+enum {
+	PROP_0,
+	PROP_WORD
+};
+
+enum {
+	ADDED,
+	IGNORED,
+	NEXT_WORD,
+	PREV_WORD,
+	REPLACE,
+	REPLACE_ALL,
+	LAST_SIGNAL
+};
+
+struct _GtkhtmlSpellDialogPrivate {
+
+	/* widgets */
+	GtkWidget *add_word_button;
+	GtkWidget *back_button;
+	GtkWidget *dictionary_combo;
+	GtkWidget *ignore_button;
+	GtkWidget *replace_button;
+	GtkWidget *replace_all_button;
+	GtkWidget *skip_button;
+	GtkWidget *suggestion_label;
+	GtkWidget *tree_view;
+
+	GList *spell_checkers;
+	gchar *word;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+spell_dialog_render_checker (GtkComboBox *combo_box,
+                             GtkCellRenderer *renderer,
+                             GtkTreeModel *model,
+                             GtkTreeIter *iter)
+{
+	const GtkhtmlSpellLanguage *language;
+	GtkhtmlSpellChecker *checker;
+	const gchar *name;
+
+	gtk_tree_model_get (model, iter, 0, &checker, -1);
+	language = gtkhtml_spell_checker_get_language (checker);
+	name = gtkhtml_spell_language_get_name (language);
+
+	g_object_set (renderer, "text", name, NULL);
+
+	g_object_unref (checker);
+}
+
+static void
+spell_dialog_update_buttons (GtkhtmlSpellDialog *dialog)
+{
+	gboolean sensitive;
+
+	/* Update "Add Word" and "Ignore" button sensitivity. */
+	sensitive = (gtkhtml_spell_dialog_get_word (dialog) != NULL);
+	gtk_widget_set_sensitive (dialog->priv->add_word_button, sensitive);
+	gtk_widget_set_sensitive (dialog->priv->ignore_button, sensitive);
+}
+
+static void
+spell_dialog_update_suggestion_label (GtkhtmlSpellDialog *dialog)
+{
+	GtkLabel *label;
+	const gchar *word;
+	gchar *markup;
+	gchar *text;
+
+	label = GTK_LABEL (dialog->priv->suggestion_label);
+	word = gtkhtml_spell_dialog_get_word (dialog);
+
+	/* Handle the simple case and get out. */
+	if (word == NULL) {
+		gtk_label_set_markup (label, NULL);
+		return;
+	}
+
+	text = g_strdup_printf (_("Suggestions for \"%s\""), word);
+	markup = g_strdup_printf ("<b>%s</b>", text);
+
+	gtk_label_set_markup (label, markup);
+
+	g_free (markup);
+	g_free (text);
+}
+
+static void
+spell_dialog_update_tree_view (GtkhtmlSpellDialog *dialog)
+{
+	GtkhtmlSpellChecker *checker;
+	GtkTreeSelection *selection;
+	GtkTreeView *tree_view;
+	GtkListStore *store;
+	GtkTreePath *path;
+	const gchar *word;
+	GList *list = NULL;
+
+	tree_view = GTK_TREE_VIEW (dialog->priv->tree_view);
+	selection = gtk_tree_view_get_selection (tree_view);
+	checker = gtkhtml_spell_dialog_get_active_checker (dialog);
+	word = gtkhtml_spell_dialog_get_word (dialog);
+
+	store = gtk_list_store_new (1, G_TYPE_STRING);
+
+	if (checker != NULL && word != NULL)
+		list = gtkhtml_spell_checker_get_suggestions (
+			checker, word, -1);
+
+	while (list != NULL) {
+		const gchar *suggestion = list->data;
+		GtkTreeIter iter;
+
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter, 0, suggestion, -1);
+
+		g_free (list->data);
+		list = g_list_delete_link (list, list);
+	}
+
+	gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (store));
+
+	/* Select the first item. */
+	path = gtk_tree_path_new_first ();
+	gtk_tree_selection_select_path (selection, path);
+	gtk_tree_path_free (path);
+
+	g_object_unref (checker);
+}
+
+static void
+spell_dialog_add_word_cb (GtkhtmlSpellDialog *dialog)
+{
+	GtkhtmlSpellChecker *checker;
+	const gchar *word;
+
+	checker = gtkhtml_spell_dialog_get_active_checker (dialog);
+	word = gtkhtml_spell_dialog_get_word (dialog);
+
+	gtkhtml_spell_checker_add_word (checker, word, -1);
+	g_signal_emit (dialog, signals[ADDED], 0);
+
+	gtkhtml_spell_dialog_next_word (dialog);
+}
+
+static void
+spell_dialog_ignore_cb (GtkhtmlSpellDialog *dialog)
+{
+	GtkhtmlSpellChecker *checker;
+	const gchar *word;
+
+	checker = gtkhtml_spell_dialog_get_active_checker (dialog);
+	word = gtkhtml_spell_dialog_get_word (dialog);
+
+	gtkhtml_spell_checker_add_word_to_session (checker, word, -1);
+	g_signal_emit (dialog, signals[IGNORED], 0);
+
+	gtkhtml_spell_dialog_next_word (dialog);
+}
+
+static void
+spell_dialog_selection_changed_cb (GtkhtmlSpellDialog *dialog)
+{
+	GtkTreeSelection *selection;
+	GtkTreeView *tree_view;
+	gboolean selected;
+
+	tree_view = GTK_TREE_VIEW (dialog->priv->tree_view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	/* Update "Replace" and "Replace All" button sensitivity. */
+	selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
+	gtk_widget_set_sensitive (dialog->priv->replace_button, selected);
+	gtk_widget_set_sensitive (dialog->priv->replace_all_button, selected);
+}
+
+static void
+spell_dialog_replace_cb (GtkhtmlSpellDialog *dialog)
+{
+	gchar *word;
+
+	word = gtkhtml_spell_dialog_get_active_suggestion (dialog);
+	g_return_if_fail (word != NULL);
+
+	g_signal_emit (dialog, signals[REPLACE], 0, word);
+
+	g_free (word);
+}
+
+static void
+spell_dialog_replace_all_cb (GtkhtmlSpellDialog *dialog)
+{
+	gchar *word;
+
+	word = gtkhtml_spell_dialog_get_active_suggestion (dialog);
+	g_return_if_fail (word != NULL);
+
+	g_signal_emit (dialog, signals[REPLACE_ALL], 0, word);
+
+	g_free (word);
+}
+
+static void
+spell_dialog_set_property (GObject *object,
+                           guint property_id,
+                           const GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_WORD:
+			gtkhtml_spell_dialog_set_word (
+				GTKHTML_SPELL_DIALOG (object),
+				g_value_get_string (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_dialog_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_WORD:
+			g_value_set_string (
+				value, gtkhtml_spell_dialog_get_word (
+				GTKHTML_SPELL_DIALOG (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_dialog_dispose (GObject *object)
+{
+	GtkhtmlSpellDialogPrivate *priv;
+
+	priv = GTKHTML_SPELL_DIALOG_GET_PRIVATE (object);
+
+	if (priv->add_word_button != NULL) {
+		g_object_unref (priv->add_word_button);
+		priv->add_word_button = NULL;
+	}
+
+	if (priv->back_button != NULL) {
+		g_object_unref (priv->back_button);
+		priv->back_button = NULL;
+	}
+
+	if (priv->dictionary_combo != NULL) {
+		g_object_unref (priv->dictionary_combo);
+		priv->dictionary_combo = NULL;
+	}
+
+	if (priv->ignore_button != NULL) {
+		g_object_unref (priv->ignore_button);
+		priv->ignore_button = NULL;
+	}
+
+	if (priv->replace_button != NULL) {
+		g_object_unref (priv->replace_button);
+		priv->replace_button = NULL;
+	}
+
+	if (priv->replace_all_button != NULL) {
+		g_object_unref (priv->replace_all_button);
+		priv->replace_all_button = NULL;
+	}
+
+	if (priv->skip_button != NULL) {
+		g_object_unref (priv->skip_button);
+		priv->skip_button = NULL;
+	}
+
+	if (priv->tree_view != NULL) {
+		g_object_unref (priv->tree_view);
+		priv->tree_view = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+spell_dialog_finalize (GObject *object)
+{
+	GtkhtmlSpellDialogPrivate *priv;
+
+	priv = GTKHTML_SPELL_DIALOG_GET_PRIVATE (object);
+
+	g_free (priv->word);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+spell_dialog_class_init (GtkhtmlSpellDialogClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlSpellDialogPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = spell_dialog_set_property;
+	object_class->get_property = spell_dialog_get_property;
+	object_class->dispose = spell_dialog_dispose;
+	object_class->finalize = spell_dialog_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_WORD,
+		g_param_spec_string (
+			"word",
+			_("Misspelled Word"),
+			_("The current misspelled word"),
+			NULL,
+			G_PARAM_READWRITE));
+
+	signals[ADDED] = g_signal_new (
+		"added",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[IGNORED] = g_signal_new (
+		"ignored",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[NEXT_WORD] = g_signal_new (
+		"next-word",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[PREV_WORD] = g_signal_new (
+		"prev-word",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	signals[REPLACE] = g_signal_new (
+		"replace",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1,
+		G_TYPE_STRING);
+
+	signals[REPLACE_ALL] = g_signal_new (
+		"replace-all",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		0, NULL, NULL,
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1,
+		G_TYPE_STRING);
+}
+
+static void
+spell_dialog_init (GtkhtmlSpellDialog *dialog)
+{
+	GtkTreeSelection *selection;
+	GtkTreeViewColumn *column;
+	GtkCellRenderer *renderer;
+	GtkWidget *action_area;
+	GtkWidget *container;
+	GtkWidget *table;
+	GtkWidget *vbox;
+	GtkWidget *widget;
+	gchar *markup;
+
+	dialog->priv = GTKHTML_SPELL_DIALOG_GET_PRIVATE (dialog);
+
+	g_signal_connect (
+		dialog, "notify::word", G_CALLBACK (
+		spell_dialog_update_buttons), NULL);
+
+	g_signal_connect (
+		dialog, "notify::word", G_CALLBACK (
+		spell_dialog_update_suggestion_label), NULL);
+
+	g_signal_connect (
+		dialog, "notify::word", G_CALLBACK (
+		spell_dialog_update_tree_view), NULL);
+
+	/* Build the widgets. */
+
+	vbox = GTK_DIALOG (dialog)->vbox;
+	action_area = GTK_DIALOG (dialog)->action_area;
+
+	gtk_dialog_add_button (
+		GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+	gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+	gtk_window_set_title (GTK_WINDOW (dialog), _("Spell Checker"));
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+	gtk_box_set_spacing (GTK_BOX (vbox), 2);
+
+	/* Table */
+	widget = gtk_table_new (4, 2, FALSE);
+	gtk_container_set_border_width (GTK_CONTAINER (widget), 5);
+	gtk_table_set_row_spacings (GTK_TABLE (widget), 6);
+	gtk_table_set_col_spacings (GTK_TABLE (widget), 6);
+	gtk_table_set_row_spacing (GTK_TABLE (widget), 1, 12);
+	gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
+	gtk_widget_show (widget);
+	table = widget;
+
+	/* Suggestion Label */
+	widget = gtk_label_new (NULL);
+	gtk_label_set_ellipsize (GTK_LABEL (widget), PANGO_ELLIPSIZE_END);
+	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 0, 2, 0, 1,
+		GTK_EXPAND | GTK_FILL, 0, 0, 0);
+	dialog->priv->suggestion_label = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Scrolled Window */
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_SHADOW_ETCHED_IN);
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 0, 1, 1, 2,
+		GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
+	gtk_widget_show (widget);
+	container = widget;
+
+	/* Tree View */
+	widget = gtk_tree_view_new ();
+	column = gtk_tree_view_column_new ();
+	renderer = gtk_cell_renderer_text_new ();
+	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
+	g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+	gtk_tree_view_column_pack_start (column, renderer, TRUE);
+	gtk_tree_view_column_add_attribute (column, renderer, "text", 0);
+	gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column);
+	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE);
+	gtk_label_set_mnemonic_widget (
+		GTK_LABEL (dialog->priv->suggestion_label), widget);
+	g_signal_connect_swapped (
+		selection, "changed",
+		G_CALLBACK (spell_dialog_selection_changed_cb), dialog);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	dialog->priv->tree_view = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Vertical Button Box */
+	widget = gtk_vbutton_box_new ();
+	gtk_button_box_set_layout (
+		GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START);
+	gtk_box_set_spacing (GTK_BOX (widget), 6);
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 1, 2, 1, 2,
+		0, GTK_EXPAND | GTK_FILL, 0, 0);
+	gtk_widget_show (widget);
+	container = widget;
+
+	/* Replace Button */
+	widget = gtk_button_new_with_mnemonic (_("_Replace"));
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_CONVERT, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (spell_dialog_replace_cb), dialog);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	dialog->priv->replace_button = g_object_ref (widget);
+	gtk_widget_set_sensitive (widget, FALSE);
+	gtk_widget_show (widget);
+
+	/* Replace All Button */
+	widget = gtk_button_new_with_mnemonic (_("R_eplace All"));
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_APPLY, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (spell_dialog_replace_all_cb), dialog);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	dialog->priv->replace_all_button = g_object_ref (widget);
+	gtk_widget_set_sensitive (widget, FALSE);
+	gtk_widget_show (widget);
+
+	/* Ignore Button */
+	widget = gtk_button_new_with_mnemonic (_("_Ignore"));
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_CLEAR, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (spell_dialog_ignore_cb), dialog);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	dialog->priv->ignore_button = g_object_ref (widget);
+	gtk_widget_set_sensitive (widget, FALSE);
+	gtk_widget_show (widget);
+
+	/* Skip Button */
+	widget = gtk_button_new_with_mnemonic (_("_Skip"));
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (gtkhtml_spell_dialog_next_word), dialog);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	dialog->priv->skip_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Back Button */
+	widget = gtk_button_new_with_mnemonic (_("_Back"));
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (gtkhtml_spell_dialog_prev_word), dialog);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	dialog->priv->back_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Dictionary Label */
+	markup = g_markup_printf_escaped ("<b>%s</b>", _("Dictionary"));
+	widget = gtk_label_new (markup);
+	gtk_label_set_use_markup (GTK_LABEL (widget), TRUE);
+	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 0, 2, 2, 3,
+		GTK_EXPAND | GTK_FILL, 0, 0, 0);
+	gtk_widget_show (widget);
+	g_free (markup);
+
+	/* Dictionary Combo Box */
+	widget = gtk_combo_box_new ();
+	renderer = gtk_cell_renderer_text_new ();
+	gtk_cell_layout_pack_start (
+		GTK_CELL_LAYOUT (widget), renderer, TRUE);
+	gtk_cell_layout_set_cell_data_func (
+		GTK_CELL_LAYOUT (widget), renderer,
+		(GtkCellLayoutDataFunc) spell_dialog_render_checker,
+		NULL, NULL);
+	g_signal_connect_swapped (
+		widget, "changed",
+		G_CALLBACK (spell_dialog_update_tree_view), dialog);
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 0, 1, 3, 4,
+		GTK_EXPAND | GTK_FILL, 0, 0, 0);
+	dialog->priv->dictionary_combo = g_object_ref (widget);
+	gtk_widget_show (widget);
+
+	/* Add Word Button */
+	widget = gtk_button_new_with_mnemonic (_("_Add Word"));
+	g_signal_connect_swapped (
+		widget, "clicked",
+		G_CALLBACK (spell_dialog_add_word_cb), dialog);
+	gtk_button_set_image (
+		GTK_BUTTON (widget),
+		gtk_image_new_from_stock (
+		GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON));
+	gtk_table_attach (
+		GTK_TABLE (table), widget, 1, 2, 3, 4,
+		GTK_EXPAND | GTK_FILL, 0, 0, 0);
+	dialog->priv->add_word_button = g_object_ref (widget);
+	gtk_widget_show (widget);
+}
+
+GType
+gtkhtml_spell_dialog_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlSpellDialogClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) spell_dialog_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlSpellDialog),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) spell_dialog_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_DIALOG, "GtkhtmlSpellDialog", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+gtkhtml_spell_dialog_new (GtkWindow *parent)
+{
+	return g_object_new (
+		GTKHTML_TYPE_SPELL_DIALOG, "transient-for", parent, NULL);
+}
+
+void
+gtkhtml_spell_dialog_close (GtkhtmlSpellDialog *dialog)
+{
+	g_return_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog));
+
+	gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+}
+
+const gchar *
+gtkhtml_spell_dialog_get_word (GtkhtmlSpellDialog *dialog)
+{
+	g_return_val_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog), NULL);
+
+	return dialog->priv->word;
+}
+
+void
+gtkhtml_spell_dialog_set_word (GtkhtmlSpellDialog *dialog,
+                               const gchar *word)
+{
+	g_return_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog));
+
+	/* Do not emit signals if the word is unchanged. */
+	if (word != NULL && dialog->priv->word != NULL)
+		if (g_str_equal (word, dialog->priv->word))
+			return;
+
+	g_free (dialog->priv->word);
+	dialog->priv->word = g_strdup (word);
+
+	g_object_notify (G_OBJECT (dialog), "word");
+}
+
+void
+gtkhtml_spell_dialog_next_word (GtkhtmlSpellDialog *dialog)
+{
+	g_signal_emit (dialog, signals[NEXT_WORD], 0);
+}
+
+void
+gtkhtml_spell_dialog_prev_word (GtkhtmlSpellDialog *dialog)
+{
+	g_signal_emit (dialog, signals[PREV_WORD], 0);
+}
+
+GList *
+gtkhtml_spell_dialog_get_spell_checkers (GtkhtmlSpellDialog *dialog)
+{
+	g_return_val_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog), NULL);
+
+	return g_list_copy (dialog->priv->spell_checkers);
+}
+
+void
+gtkhtml_spell_dialog_set_spell_checkers (GtkhtmlSpellDialog *dialog,
+                                         GList *spell_checkers)
+{
+	GtkComboBox *combo_box;
+	GtkListStore *store;
+	GList *list;
+
+	g_return_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog));
+
+	combo_box = GTK_COMBO_BOX (dialog->priv->dictionary_combo);
+
+	/* Free the old list of spell checkers. */
+	list = dialog->priv->spell_checkers;
+	g_list_foreach (list, (GFunc) g_object_unref, NULL);
+	g_list_free (list);
+
+	/* Copy and sort the new list of spell checkers. */
+	list = g_list_sort (
+		g_list_copy (spell_checkers),
+		(GCompareFunc) gtkhtml_spell_checker_compare);
+	g_list_foreach (list, (GFunc) g_object_ref, NULL);
+	dialog->priv->spell_checkers = list;
+
+	/* Populate a list store for the combo box. */
+
+	store = gtk_list_store_new (1, GTKHTML_TYPE_SPELL_CHECKER);
+
+	while (list != NULL) {
+		GtkhtmlSpellChecker *checker = list->data;
+		GtkTreeIter iter;
+
+		gtk_list_store_append (store, &iter);
+		gtk_list_store_set (store, &iter, 0, checker, -1);
+
+		list = g_list_next (list);
+	}
+
+	/* FIXME Try to preserve the previously selected language. */
+	gtk_combo_box_set_model (combo_box, GTK_TREE_MODEL (store));
+	gtk_combo_box_set_active (combo_box, 0);
+
+	g_object_unref (store);
+
+	/* XXX notify property? */
+}
+
+GtkhtmlSpellChecker *
+gtkhtml_spell_dialog_get_active_checker (GtkhtmlSpellDialog *dialog)
+{
+	GtkhtmlSpellChecker *checker;
+	GtkComboBox *combo_box;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+
+	g_return_val_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog), NULL);
+
+	combo_box = GTK_COMBO_BOX (dialog->priv->dictionary_combo);
+	model = gtk_combo_box_get_model (combo_box);
+
+	if (!gtk_combo_box_get_active_iter (combo_box, &iter))
+		return NULL;
+
+	gtk_tree_model_get (model, &iter, COMBO_COLUMN_CHECKER, &checker, -1);
+
+	return checker;
+}
+
+gchar *
+gtkhtml_spell_dialog_get_active_suggestion (GtkhtmlSpellDialog *dialog)
+{
+	GtkTreeSelection *selection;
+	GtkTreeView *tree_view;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *word;
+
+	g_return_val_if_fail (GTKHTML_IS_SPELL_DIALOG (dialog), NULL);
+
+	tree_view = GTK_TREE_VIEW (dialog->priv->tree_view);
+	selection = gtk_tree_view_get_selection (tree_view);
+
+	/* If nothing is selected, return NULL. */
+	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+		return NULL;
+
+	gtk_tree_model_get (model, &iter, 0, &word, -1);
+	g_return_val_if_fail (word != NULL, NULL);
+
+	return word;
+}
Index: components/editor/main.c
===================================================================
--- components/editor/main.c	(revision 0)
+++ components/editor/main.c	(revision 0)
@@ -0,0 +1,413 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* GtkhtmlEditor test program
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <libintl.h>
+#include <locale.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gtkhtml-editor.h"
+#include <gtkhtml/gtkhtml-stream.h>
+
+static const gchar *file_ui =
+"<ui>\n"
+"  <menubar name='main-menu'>\n"
+"    <menu action='file-menu'>\n"
+"     <menuitem action='save'/>\n"
+"     <menuitem action='save-as'/>\n"
+"     <separator/>\n"
+"     <menuitem action='print-preview'/>\n"
+"     <menuitem action='print'/>\n"
+"     <separator/>\n"
+"     <menuitem action='quit'/>\n"
+"    </menu>\n"
+"  </menubar>\n"
+"</ui>";
+
+static const gchar *view_ui =
+"<ui>\n"
+"  <menubar name='main-menu'>\n"
+"    <menu action='view-menu'>\n"
+"     <menuitem action='view-html-output'/>\n"
+"     <menuitem action='view-html-source'/>\n"
+"     <menuitem action='view-plain-source'/>\n"
+"    </menu>\n"
+"  </menubar>\n"
+"</ui>";
+
+static void
+handle_error (GError **error)
+{
+	if (*error != NULL) {
+		g_warning ("%s", (*error)->message);
+		g_clear_error (error);
+	}
+}
+
+static GtkPrintOperationResult
+print (GtkhtmlEditor *editor,
+       GtkPrintOperationAction action)
+{
+	GtkPrintOperation *operation;
+	GtkPrintOperationResult result;
+	GError *error = NULL;
+
+	operation = gtk_print_operation_new ();
+
+	result = gtk_html_print_operation_run (
+		gtkhtml_editor_get_html (editor), operation, action,
+		GTK_WINDOW (editor), NULL, NULL, NULL, NULL, NULL, &error);
+
+	g_object_unref (operation);
+	handle_error (&error);
+
+	return result;
+}
+
+static gint
+save_dialog (GtkhtmlEditor *editor)
+{
+	GtkWidget *dialog;
+	const gchar *filename;
+	gint response;
+
+	dialog = gtk_file_chooser_dialog_new (
+		_("Save As"), GTK_WINDOW (editor),
+		GTK_FILE_CHOOSER_ACTION_SAVE,
+		GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+		GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+		NULL);
+
+	gtk_file_chooser_set_do_overwrite_confirmation (
+		GTK_FILE_CHOOSER (dialog), TRUE);
+
+	filename = gtkhtml_editor_get_filename (editor);
+
+	if (filename != NULL)
+		gtk_file_chooser_set_filename (
+			GTK_FILE_CHOOSER (dialog), filename);
+	else {
+		gtk_file_chooser_set_current_folder (
+			GTK_FILE_CHOOSER (dialog), g_get_home_dir ());
+		gtk_file_chooser_set_current_name (
+			GTK_FILE_CHOOSER (dialog), _("Untitled document"));
+	}
+
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	if (response == GTK_RESPONSE_ACCEPT) {
+		gchar *new_filename;
+
+		new_filename = gtk_file_chooser_get_filename (
+			GTK_FILE_CHOOSER (dialog));
+		gtkhtml_editor_set_filename (editor, new_filename);
+		g_free (new_filename);
+	}
+
+	gtk_widget_destroy (dialog);
+
+	return response;
+}
+
+/* Helper for view_source_dialog() */
+static gboolean
+view_source_dialog_receiver (HTMLEngine *engine,
+                             const gchar *data,
+                             guint length,
+                             GString *string)
+{
+	g_string_append_len (string, data, length);
+
+	return TRUE;
+}
+
+static void
+view_source_dialog (GtkhtmlEditor *editor,
+                    const gchar *title,
+                    const gchar *content_type,
+                    gboolean show_output)
+{
+	GtkWidget *dialog;
+	GtkWidget *content;
+	GtkWidget *scrolled_window;
+	GString *string;
+
+	dialog = gtk_dialog_new_with_buttons (
+		title, GTK_WINDOW (editor),
+		GTK_DIALOG_DESTROY_WITH_PARENT |
+		GTK_DIALOG_NO_SEPARATOR,
+		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+		NULL);
+
+	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (scrolled_window),
+		GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (scrolled_window), GTK_SHADOW_IN);
+	gtk_box_pack_start (
+		GTK_BOX (GTK_DIALOG (dialog)->vbox),
+		scrolled_window, TRUE, TRUE, 0);
+
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 6);
+	gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 6);
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 300);
+
+	string = g_string_sized_new (4096);
+
+	gtk_html_export (
+		gtkhtml_editor_get_html (editor),
+		content_type, (GtkHTMLSaveReceiverFn)
+		view_source_dialog_receiver, string);
+
+	if (show_output) {
+		GtkHTMLStream *stream;
+
+		content = gtk_html_new ();
+		stream = gtk_html_begin (GTK_HTML (content));
+		gtk_html_stream_write (stream, string->str, string->len);
+		gtk_html_stream_close (stream, GTK_HTML_STREAM_OK);
+	} else {
+		GtkTextBuffer *buffer;
+
+		content = gtk_text_view_new ();
+		buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (content));
+		gtk_text_buffer_set_text (buffer, string->str, string->len);
+		gtk_text_view_set_editable (GTK_TEXT_VIEW (content), FALSE);
+	}
+
+	g_string_free (string, TRUE);
+
+	gtk_container_add (GTK_CONTAINER (scrolled_window), content);
+	gtk_widget_show_all (scrolled_window);
+
+	gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+}
+
+static void
+action_print_cb (GtkAction *action,
+                 GtkhtmlEditor *editor)
+{
+	print (editor, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
+}
+
+static void
+action_print_preview_cb (GtkAction *action,
+                         GtkhtmlEditor *editor)
+{
+	print (editor, GTK_PRINT_OPERATION_ACTION_PREVIEW);
+}
+
+static void
+action_quit_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	gtk_main_quit ();
+}
+
+static void
+action_save_cb (GtkAction *action,
+                GtkhtmlEditor *editor)
+{
+	const gchar *filename;
+	gboolean as_html;
+	GError *error = NULL;
+
+	if (gtkhtml_editor_get_filename (editor) == NULL)
+		if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
+			return;
+
+	filename = gtkhtml_editor_get_filename (editor);
+	as_html = gtkhtml_editor_get_html_mode (editor);
+
+	gtkhtml_editor_save (editor, filename, as_html, &error);
+	handle_error (&error);
+}
+
+static void
+action_save_as_cb (GtkAction *action,
+                   GtkhtmlEditor *editor)
+{
+	const gchar *filename;
+	gboolean as_html;
+	GError *error = NULL;
+
+	if (save_dialog (editor) == GTK_RESPONSE_CANCEL)
+		return;
+
+	filename = gtkhtml_editor_get_filename (editor);
+	as_html = gtkhtml_editor_get_html_mode (editor);
+
+	gtkhtml_editor_save (editor, filename, as_html, &error);
+	handle_error (&error);
+}
+
+static void
+action_view_html_output (GtkAction *action,
+                         GtkhtmlEditor *editor)
+{
+	view_source_dialog (editor, _("HTML Output"), "text/html", TRUE);
+}
+
+static void
+action_view_html_source (GtkAction *action,
+                         GtkhtmlEditor *editor)
+{
+	view_source_dialog (editor, _("HTML Source"), "text/html", FALSE);
+}
+
+static void
+action_view_plain_source (GtkAction *action,
+                          GtkhtmlEditor *editor)
+{
+	view_source_dialog (editor, _("Plain Source"), "text/plain", FALSE);
+}
+
+static GtkActionEntry file_entries[] = {
+
+	{ "print",
+	  GTK_STOCK_PRINT,
+	  N_("_Print..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_print_cb) },
+
+	{ "print-preview",
+	  GTK_STOCK_PRINT_PREVIEW,
+	  N_("Print Pre_view"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_print_preview_cb) },
+
+	{ "quit",
+	  GTK_STOCK_QUIT,
+	  N_("_Quit"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_quit_cb) },
+
+	{ "save",
+	  GTK_STOCK_SAVE,
+	  N_("_Save"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_save_cb) },
+
+	{ "save-as",
+	  GTK_STOCK_SAVE_AS,
+	  N_("Save _As..."),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_save_as_cb) },
+
+	{ "file-menu",
+	  NULL,
+	  N_("_File"),
+	  NULL,
+	  NULL,
+	  NULL }
+};
+
+static GtkActionEntry view_entries[] = {
+
+	{ "view-html-output",
+	  NULL,
+	  N_("HTML _Output"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_view_html_output) },
+
+	{ "view-html-source",
+	  NULL,
+	  N_("_HTML Source"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_view_html_source) },
+
+	{ "view-plain-source",
+	  NULL,
+	  N_("_Plain Source"),
+	  NULL,
+	  NULL,
+	  G_CALLBACK (action_view_plain_source) },
+
+	{ "view-menu",
+	  NULL,
+	  N_("_View"),
+	  NULL,
+	  NULL,
+	  NULL }
+};
+
+gint
+main (gint argc, gchar **argv)
+{
+	GtkActionGroup *action_group;
+	GtkUIManager *manager;
+	GtkWidget *editor;
+	GError *error = NULL;
+
+	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+
+	g_thread_init (NULL);
+
+	gtk_init (&argc, &argv);
+
+	editor = gtkhtml_editor_new ();
+
+	manager = gtkhtml_editor_get_ui_manager (GTKHTML_EDITOR (editor));
+
+	gtk_ui_manager_add_ui_from_string (manager, file_ui, -1, &error);
+	handle_error (&error);
+
+	gtk_ui_manager_add_ui_from_string (manager, view_ui, -1, &error);
+	handle_error (&error);
+
+	action_group = gtk_action_group_new ("file");
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, file_entries,
+		G_N_ELEMENTS (file_entries), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	action_group = gtk_action_group_new ("view");
+	gtk_action_group_set_translation_domain (
+		action_group, GETTEXT_PACKAGE);
+	gtk_action_group_add_actions (
+		action_group, view_entries,
+		G_N_ELEMENTS (view_entries), editor);
+	gtk_ui_manager_insert_action_group (manager, action_group, 0);
+
+	gtk_ui_manager_ensure_update (manager);
+	gtk_widget_show (editor);
+
+	g_signal_connect (
+		editor, "destroy",
+		G_CALLBACK (gtk_main_quit), NULL);
+
+	gtk_main ();
+
+	return EXIT_SUCCESS;
+}
Index: components/editor/Makefile.am
===================================================================
--- components/editor/Makefile.am	(revision 0)
+++ components/editor/Makefile.am	(revision 0)
@@ -0,0 +1,125 @@
+### Process this file with automake to produce Makefile.in
+
+gtkhtml_data = $(datadir)/gtkhtml-@GTKHTML_API_VERSION@
+
+bin_PROGRAMS = gtkhtml-editor-test
+lib_LTLIBRARIES = libgtkhtml-editor.la
+
+AM_CFLAGS = \
+	@GTKHTML_CFLAGS@			\
+	-I$(top_srcdir)				\
+	-I$(top_srcdir)/gtkhtml			\
+	-I$(top_srcdir)/components/editor	\
+	-DG_LOG_DOMAIN=\"gtkhtml-editor\"	\
+	-DLOCALEDIR=\""$(datadir)/locale/"\"	\
+	-DICONDIR=\""$(gtkhtml_data)/icons"\"	\
+	-DHAVE_CONFIG_H
+
+BUILT_SOURCES = \
+	gtkhtml-editor-marshal.c		\
+	gtkhtml-editor-marshal.h		\
+	gtkhtml-spell-marshal.c			\
+	gtkhtml-spell-marshal.h
+
+libgtkhtml_editordir = $(includedir)/libgtkhtml-@GTKHTML_API_VERSION@/editor
+
+libgtkhtml_editor_la_SOURCES = \
+	$(BUILT_SOURCES)			\
+	gtkhtml-color-combo.c			\
+	gtkhtml-color-combo.h			\
+	gtkhtml-color-palette.c			\
+	gtkhtml-color-palette.h			\
+	gtkhtml-color-state.c			\
+	gtkhtml-color-state.h			\
+	gtkhtml-color-swatch.c			\
+	gtkhtml-color-swatch.h			\
+	gtkhtml-combo-box.c			\
+	gtkhtml-combo-box.h			\
+	gtkhtml-editor.c			\
+	gtkhtml-editor-actions.c		\
+	gtkhtml-editor-private.c		\
+	gtkhtml-editor-private.h		\
+	gtkhtml-editor-signals.c		\
+	gtkhtml-editor-signals.h		\
+	gtkhtml-spell-dialog.c			\
+	gtkhtml-spell-dialog.h			\
+	gtkhtml-spell-checker.c			\
+	gtkhtml-spell-language.c
+
+libgtkhtml_editor_HEADERS = \
+	gtkhtml-editor.h			\
+	gtkhtml-editor-actions.h		\
+	gtkhtml-editor-common.h			\
+	gtkhtml-editor-widgets.h		\
+	gtkhtml-spell-checker.h			\
+	gtkhtml-spell-language.h
+
+libgtkhtml_editor_la_LIBADD = \
+	@GTKHTML_LIBS@				\
+	$(top_builddir)/gtkhtml/libgtkhtml-@GTKHTML_API_VERSION@.la
+
+gtkhtml_editor_test_SOURCES = main.c
+
+gtkhtml_editor_test_LDADD = \
+	libgtkhtml-editor.la			\
+	$(top_builddir)/gtkhtml/libgtkhtml-@GTKHTML_API_VERSION@.la
+
+gtkhtml-editor-marshal.h: gtkhtml-editor-marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --header --prefix=gtkhtml_editor_marshal > $@
+
+gtkhtml-editor-marshal.c: gtkhtml-editor-marshal.list $(GLIB_GENMARSHAL)
+	echo "#include \"gtkhtml-editor-marshal.h\"" > $@ && \
+	$(GLIB_GENMARSHAL) $< --body --prefix=gtkhtml_editor_marshal >> $@
+
+gtkhtml-spell-marshal.h: gtkhtml-spell-marshal.list $(GLIB_GENMARSHAL)
+	$(GLIB_GENMARSHAL) $< --header --prefix=gtkhtml_spell_marshal > $@
+
+gtkhtml-spell-marshal.c: gtkhtml-spell-marshal.list $(GLIB_GENMARSHAL)
+	echo "#include \"gtkhtml-spell-marshal.h\"" > $@ && \
+	$(GLIB_GENMARSHAL) $< --body --prefix=gtkhtml_spell_marshal >> $@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gtkhtml-editor.pc
+
+uidir = $(gtkhtml_data)
+ui_DATA = \
+	gtkhtml-editor.glade			\
+	gtkhtml-editor.ui
+
+EXTRA_DIST = \
+	$(pkgconfig_DATA)			\
+	$(ui_DATA)				\
+	gtkhtml_editor_marshal.list		\
+	gtkhtml_spell_marshal.list
+
+CLEANFILES = \
+	$(BUILT_SOURCES)
+
+MAINTAINERCLEANFILES = \
+	gtkhtml-editor.glade.bak		\
+	gtkhtml-editor.gladep.bak
+
+if MAINTAINER_MODE
+
+gladecatalog_DATA = gtkhtml-editor.xml
+gladecatalogdir = `$(PKG_CONFIG) --variable=catalogdir gladeui-1.0`
+
+libglade_gtkhtml_editor_LTLIBRARIES = libglade-gtkhtml-editor.la
+libglade_gtkhtml_editordir = `$(PKG_CONFIG) --variable=moduledir gladeui-1.0`
+
+libglade_gtkhtml_editor_la_CFLAGS = @GTKHTML_CFLAGS@
+
+libglade_gtkhtml_editor_la_SOURCES = \
+	gtkhtml-color-combo.c			\
+	gtkhtml-color-palette.c			\
+	gtkhtml-color-state.c			\
+	gtkhtml-color-swatch.c			\
+	gtkhtml-combo-box.c
+
+libglade_gtkhtml_editor_la_LDFLAGS = -module -avoid-version
+
+libglade_gtkhtml_editor_la_LIBADD = @GTKHTML_CFLAGS@
+
+EXTRA_DIST += $(gladecatalog_DATA)
+
+endif
Index: components/editor/gtkhtml-editor.glade
===================================================================
--- components/editor/gtkhtml-editor.glade	(revision 0)
+++ components/editor/gtkhtml-editor.glade	(revision 0)
@@ -0,0 +1,3254 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.1 on Wed Mar 12 16:34:34 2008 -->
+<glade-interface>
+  <requires lib="gtkhtml-editor"/>
+  <widget class="GtkWindow" id="text-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Text Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="text-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkHBox" id="text-properties-inner-hbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="border_width">6</property>
+            <property name="spacing">12</property>
+            <child>
+              <widget class="GtkTable" id="text-properties-table-left">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="n_rows">4</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">6</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <widget class="GtkImage" id="text-properties-bold-image">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="stock">gtk-bold</property>
+                  </widget>
+                  <packing>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkImage" id="text-properties-italic-image">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="stock">gtk-italic</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkImage" id="text-properties-underline-image">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="stock">gtk-underline</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkImage" id="text-properties-strikethrough-image">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="stock">gtk-strikethrough</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options"></property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="text-properties-bold-button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Bold</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="text-properties-italic-button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Italic</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="text-properties-underline-button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Underline</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="text-properties-strikethrough-button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Strikethrough</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkTable" id="text-properties-table-right">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="n_rows">3</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">6</property>
+                <property name="row_spacing">6</property>
+                <child>
+                  <widget class="GtkhtmlComboBox" id="text-properties-size-combo-box">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkAlignment" id="text-properties-alignment">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="text-properties-color-label">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Color:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="text-properties-size-label">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Si_ze:</property>
+                    <property name="use_underline">True</property>
+                  </widget>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_FILL</property>
+                    <property name="y_options"></property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkhtmlColorCombo" id="text-properties-color-combo">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="default_label">Automatic</property>
+                  </widget>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="y_options">GTK_FILL</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="text-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="text-properties-ok-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="text-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="paragraph-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Paragraph Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="paragraph-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="paragraph-properties-general-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="paragraph-properties-general-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="paragraph-properties-general-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkHBox" id="paragraph-properties-general-hbox">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="paragraph-properties-general-style-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">_Style:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkhtmlComboBox" id="paragraph-properties-style-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                      </widget>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="paragraph-properties-alignment-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="paragraph-properties-alignment-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Alignment&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="paragraph-properties-alignment-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkHButtonBox" id="paragraph-properties-alignment-button-box">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">6</property>
+                    <property name="homogeneous">True</property>
+                    <child>
+                      <widget class="GtkToggleButton" id="paragraph-properties-left-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">gtk-justify-left</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkToggleButton" id="paragraph-properties-center-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">gtk-justify-center</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkToggleButton" id="paragraph-properties-right-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">gtk-justify-right</property>
+                        <property name="use_stock">True</property>
+                        <property name="response_id">0</property>
+                      </widget>
+                      <packing>
+                        <property name="position">2</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="paragraph-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="paragraph-properties-ok-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-ok</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="paragraph-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="find-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Find</property>
+    <property name="resizable">False</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">gtk-find</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="find-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="find-inner-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkEntry" id="find-entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="activates_default">True</property>
+                <signal name="changed" handler="gtkhtml_editor_find_entry_changed_cb" object="find-window"/>
+                <signal name="activate" handler="gtkhtml_editor_find_entry_activate_cb" object="find-window"/>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkHBox" id="find-hbox">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="spacing">6</property>
+                <child>
+                  <widget class="GtkCheckButton" id="find-backwards">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Search _backwards</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="gtkhtml_editor_find_backwards_toggled_cb" object="find-window"/>
+                  </widget>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="find-case-sensitive">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">Case _sensitive</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="gtkhtml_editor_find_case_sensitive_toggled_cb" object="find-window"/>
+                  </widget>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkCheckButton" id="find-regular-expression">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="label" translatable="yes">_Regular expression</property>
+                    <property name="use_underline">True</property>
+                    <property name="response_id">0</property>
+                    <property name="draw_indicator">True</property>
+                    <signal name="toggled" handler="gtkhtml_editor_find_regular_expression_toggled_cb" object="find-window"/>
+                  </widget>
+                  <packing>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="find-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="find-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="find-window"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="find-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-find</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="replace-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Replace</property>
+    <property name="resizable">False</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="replace-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="extension_events">GDK_EXTENSION_EVENTS_ALL</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkTable" id="replace-table">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="n_rows">3</property>
+            <property name="n_columns">3</property>
+            <property name="column_spacing">6</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <widget class="GtkAlignment" id="replace-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="replace-case-sensitive">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">Case _sensitive</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkCheckButton" id="replace-backwards">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">Search _backwards</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+                <property name="draw_indicator">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="replace-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">R_eplace:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">replace-entry</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="replace-with-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_With:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">replace-with-entry</property>
+              </widget>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="replace-entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="replace-with-entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="replace-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="replace-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">-6</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="replace-window"/>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkButton" id="replace-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-find-and-replace</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="replace-confirmation-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Replace Confirmation</property>
+    <property name="resizable">False</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="icon_name">gtk-find-and-replace</property>
+    <signal name="delete_event" handler="gtkhtml_editor_replace_confirmation_delete_event_cb"/>
+    <child>
+      <widget class="GtkHButtonBox" id="replace-confirmation-button-box">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <property name="homogeneous">True</property>
+        <child>
+          <widget class="GtkButton" id="replace-confirmation-replace-all-button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="response_id">0</property>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkButton" id="replace-confirmation-next-button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="response_id">0</property>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkButton" id="replace-confirmation-close-button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="use_stock">True</property>
+            <property name="response_id">0</property>
+          </widget>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkButton" id="replace-confirmation-replace-button">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="response_id">0</property>
+          </widget>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="link-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="title" translatable="yes">Link Properties</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="show" handler="gtkhtml_editor_link_properties_show_window_cb"/>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="link-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkTable" id="link-properties-table">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="n_rows">2</property>
+            <property name="n_columns">3</property>
+            <property name="column_spacing">6</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <widget class="GtkButton" id="link-properties-test-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="use_underline">True</property>
+                <property name="response_id">0</property>
+              </widget>
+              <packing>
+                <property name="left_attach">2</property>
+                <property name="right_attach">3</property>
+                <property name="x_options"></property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="link-properties-description-entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <signal name="changed" handler="gtkhtml_editor_link_properties_description_changed_cb" object="link-properties-window"/>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">3</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkEntry" id="link-properties-url-entry">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <signal name="changed" handler="gtkhtml_editor_link_properties_url_changed_cb" object="link-properties-window"/>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="link-properties-description-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">_Description:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">link-properties-description-entry</property>
+              </widget>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="link-properties-url-label">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">1</property>
+                <property name="label" translatable="yes">_URL:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">link-properties-url-entry</property>
+              </widget>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="link-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="link-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="link-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="rule-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Rule Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="show" handler="gtkhtml_editor_rule_properties_show_window_cb"/>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="rule-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="rule-properties-size-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="rule-properties-size-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Size&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="rule-properties-size-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="rule-properties-size-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">3</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="rule-properties-width-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">px
+%</property>
+                        <signal name="changed" handler="gtkhtml_editor_rule_properties_width_changed_cb" object="rule-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="rule-properties-size-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_rule_properties_size_changed_cb" object="rule-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="rule-properties-size-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Size:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="rule-properties-width-spin-button">
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_rule_properties_width_changed_cb" object="rule-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="rule-properties-width-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Width:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="rule-properties-style-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="rule-properties-style-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Style&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="rule-properties-style-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="rule-properties-style-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkCheckButton" id="rule-properties-shaded-check-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">S_haded</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="gtkhtml_editor_rule_properties_shaded_toggled_cb" object="rule-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="rule-properties-alignment-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">Left
+Center
+Right</property>
+                        <signal name="changed" handler="gtkhtml_editor_rule_properties_alignment_changed_cb" object="rule-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="rule-properties-alignment-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Alignment:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="rule-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="rule-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="rule-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="table-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Table Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <signal name="show" handler="gtkhtml_editor_table_properties_show_window_cb"/>
+    <child>
+      <widget class="GtkVBox" id="table-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="table-properties-general-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="table-properties-general-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="table-properties-general-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkHBox" id="table-properties-general-hbox">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <widget class="GtkHBox" id="table-properties-rows-hbox">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <widget class="GtkImage" id="table-properties-rows-image">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="icon_name">stock_select-row</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkLabel" id="table-properties-rows-label">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">_Rows:</property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">table-properties-rows-spin-button</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkSpinButton" id="table-properties-rows-spin-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="adjustment">1 1 32767 1 10 10</property>
+                            <signal name="value_changed" handler="gtkhtml_editor_table_properties_rows_changed_cb" object="table-properties-window"/>
+                          </widget>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkHBox" id="table-properties-cols-hbox">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="spacing">6</property>
+                        <child>
+                          <widget class="GtkImage" id="table-properties-cols-image">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="icon_name">stock_select-column</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkLabel" id="table-properties-cols-label">
+                            <property name="visible">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">C_olumns:</property>
+                            <property name="use_underline">True</property>
+                            <property name="mnemonic_widget">table-properties-cols-spin-button</property>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkSpinButton" id="table-properties-cols-spin-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="adjustment">1 1 32767 1 10 10</property>
+                            <signal name="value_changed" handler="gtkhtml_editor_table_properties_cols_changed_cb" object="table-properties-window"/>
+                          </widget>
+                          <packing>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="table-properties-layout-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="table-properties-layout-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Layout&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="table-properties-layout-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="table-properties-layout-left-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">3</property>
+                    <property name="n_columns">7</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="table-properties-border-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 32767 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_table_properties_border_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="table-properties-padding-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 32767 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_table_properties_padding_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="table-properties-spacing-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 32767 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_table_properties_spacing_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-border-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Border:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">table-properties-border-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-padding-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Padding:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">table-properties-padding-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-spacing-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Spacing:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">table-properties-spacing-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-alignment-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Alignment:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">table-properties-alignment-combo-box</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="table-properties-alignment-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">Left
+Center
+Right</property>
+                        <signal name="changed" handler="gtkhtml_editor_table_properties_alignment_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">3</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="table-properties-width-check-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Width:</property>
+                        <property name="use_underline">True</property>
+                        <property name="xalign">1</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="gtkhtml_editor_table_properties_width_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="table-properties-width-spin-button">
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">1 1 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_table_properties_width_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="table-properties-width-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">px
+%</property>
+                        <signal name="changed" handler="gtkhtml_editor_table_properties_width_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-spacing-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-padding-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-border-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="table-properties-background-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="table-properties-background-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Background&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="table-properties-background-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="table-properties-background-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkhtmlColorCombo" id="table-properties-color-combo">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="default_color">#000000000000</property>
+                        <property name="default_label">Transparent</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkFileChooserButton" id="table-properties-image-button">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="selection_changed" handler="gtkhtml_editor_table_properties_image_changed_cb" object="table-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-image-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Image:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">table-properties-image-button</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="table-properties-color-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Co_lor:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="table-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="table-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="table-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="page-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Page Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="realize" handler="gtkhtml_editor_page_properties_window_realized_cb"/>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <child>
+      <widget class="GtkVBox" id="page-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="page-properties-colors-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="page-properties-colors-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Colors&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="page-properties-colors-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="page-properties-colors-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">3</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkhtmlColorCombo" id="page-properties-background-color-combo">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="default_color">#000000000000</property>
+                        <property name="default_label">Automatic</property>
+                        <signal name="changed" handler="gtkhtml_editor_page_properties_background_color_changed_cb" object="page-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkhtmlColorCombo" id="page-properties-link-color-combo">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="default_color">#000000000000</property>
+                        <property name="default_label">_Automatic</property>
+                        <signal name="changed" handler="gtkhtml_editor_page_properties_link_color_changed_cb" object="page-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkhtmlColorCombo" id="page-properties-text-color-combo">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="default_color">#000000000000</property>
+                        <property name="default_label">_Automatic</property>
+                        <signal name="changed" handler="gtkhtml_editor_page_properties_text_color_changed_cb" object="page-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="page-properties-background-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Background:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="page-properties-link-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Link:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="page-properties-text-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Text:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="page-properties-background-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="page-properties-background-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Background Image&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="page-properties-background-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="page-properties-backgrond-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkComboBox" id="page-properties-template-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">None
+Perforated Paper
+Blue Ink
+Paper
+Ribbon
+Midnight
+Confidential
+Draft
+Graph Paper</property>
+                        <signal name="changed" handler="gtkhtml_editor_page_properties_template_changed_cb" object="page-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkFileChooserButton" id="page-properties-custom-file-chooser">
+                        <property name="width_request">200</property>
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="selection_changed" handler="gtkhtml_editor_page_properties_custom_file_changed_cb" object="page-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="page-properties-custom-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">C_ustom:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="page-properties-template-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">T_emplate:</property>
+                        <property name="use_underline">True</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="page-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="page-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="page-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="cell-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">1</property>
+    <property name="title" translatable="yes">Cell Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <signal name="show" handler="gtkhtml_editor_cell_properties_show_window_cb"/>
+    <child>
+      <widget class="GtkVBox" id="cell-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="border_width">12</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="cell-properties-scope-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="cell-properties-scope-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Scope&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="cell-properties-scope-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="cell-properties-scope-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">5</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkImage" id="cell-properties-cell-image">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="icon_name">stock_select-cell</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkImage" id="cell-properties-table-image">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="icon_name">stock_select-table</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkImage" id="cell-properties-row-image">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="icon_name">stock_select-row</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="right_attach">4</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkImage" id="cell-properties-column-image">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="icon_name">stock_select-column</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="right_attach">4</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="cell-properties-cell-radio-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">C_ell</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="gtkhtml_editor_cell_properties_scope_toggled_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="cell-properties-table-radio-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Table</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">cell-properties-cell-radio-button</property>
+                        <signal name="toggled" handler="gtkhtml_editor_cell_properties_scope_toggled_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="cell-properties-row-radio-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Row</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">cell-properties-cell-radio-button</property>
+                        <signal name="toggled" handler="gtkhtml_editor_cell_properties_scope_toggled_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkRadioButton" id="cell-properties-column-radio-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Col_umn</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="active">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">cell-properties-cell-radio-button</property>
+                        <signal name="toggled" handler="gtkhtml_editor_cell_properties_scope_toggled_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="cell-properties-alignment-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="cell-properties-alignment-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Alignment &amp;amp; Behavior&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="cell-properties-alignment-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="cell-properties-alignment-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">5</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-horizontal-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Horizontal:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-horizontal-combo-box</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-vertical-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Vertical:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-vertical-combo-box</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">3</property>
+                        <property name="right_attach">4</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="cell-properties-horizontal-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">Left
+Center
+Right</property>
+                        <signal name="changed" handler="gtkhtml_editor_cell_properties_horizontal_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="cell-properties-vertical-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">Top
+Middle
+Bottom</property>
+                        <signal name="changed" handler="gtkhtml_editor_cell_properties_vertical_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkHBox" id="cell-properties-alignment-hbox">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="spacing">12</property>
+                        <child>
+                          <widget class="GtkCheckButton" id="cell-properties-wrap-text-check-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">_Wrap Text</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="gtkhtml_editor_cell_properties_wrap_text_toggled_cb" object="cell-properties-window"/>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkCheckButton" id="cell-properties-header-style-check-button">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                            <property name="label" translatable="yes">Hea_der Style</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                            <signal name="toggled" handler="gtkhtml_editor_cell_properties_header_style_toggled_cb" object="cell-properties-window"/>
+                          </widget>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                      </widget>
+                      <packing>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="cell-properties-layout-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="cell-properties-layout-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Layout&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="cell-properties-layout-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="cell-properties-layout-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">6</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkCheckButton" id="cell-properties-width-check-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">Width:</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <property name="draw_indicator">True</property>
+                        <signal name="toggled" handler="gtkhtml_editor_cell_properties_width_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="cell-properties-width-spin-button">
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_cell_properties_width_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="cell-properties-width-combo-box">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">px
+%</property>
+                        <signal name="changed" handler="gtkhtml_editor_cell_properties_width_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-row-span-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Row Span:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-row-span-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-column-span-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">Column Span:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-column-span-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="cell-properties-row-span-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="change_value" handler="gtkhtml_editor_cell_properties_row_span_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="cell-properties-column-span-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="change_value" handler="gtkhtml_editor_cell_properties_column_span_changed_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="cell-properties-background-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="cell-properties-background-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Background&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="cell-properties-background-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="cell-properties-background-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-color-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">C_olor:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-color-combo</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="cell-properties-image-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">I_mage:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">cell-properties-image-file-chooser</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkhtmlColorCombo" id="cell-properties-color-combo">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="default_color">#000000000000</property>
+                        <property name="default_label">Transparent</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkFileChooserButton" id="cell-properties-image-file-chooser">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="title" translatable="yes">Select An Image</property>
+                        <signal name="file_set" handler="gtkhtml_editor_cell_properties_image_file_set_cb" object="cell-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="cell-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="cell-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="cell-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+  <widget class="GtkWindow" id="image-properties-window">
+    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+    <property name="border_width">12</property>
+    <property name="title" translatable="yes">Image Properties</property>
+    <property name="resizable">False</property>
+    <property name="modal">True</property>
+    <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property>
+    <property name="destroy_with_parent">True</property>
+    <signal name="delete_event" handler="gtk_widget_hide_on_delete"/>
+    <signal name="show" handler="gtkhtml_editor_image_properties_show_window_cb"/>
+    <child>
+      <widget class="GtkVBox" id="image-properties-vbox">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <widget class="GtkVBox" id="image-properties-general-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="image-properties-general-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;General&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="image-properties-general-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="image-properties-general-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">2</property>
+                    <property name="n_columns">2</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-source-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Source:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-source-file-chooser</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-description-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Description:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-description-entry</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkFileChooserButton" id="image-properties-source-file-chooser">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="file_set" handler="gtkhtml_editor_image_properties_source_file_set_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="image-properties-description-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="changed" handler="gtkhtml_editor_image_properties_description_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="image-properties-layout-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="image-properties-layout-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Layout&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="image-properties-layout-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="image-properties-layout-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">3</property>
+                    <property name="n_columns">7</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="image-properties-border-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_image_properties_border_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-border-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="image-properties-y-padding-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_image_properties_padding_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-y-padding-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-x-padding-units-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">0</property>
+                        <property name="label" translatable="yes">px</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">6</property>
+                        <property name="right_attach">7</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="image-properties-x-padding-spin-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_image_properties_padding_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">5</property>
+                        <property name="right_attach">6</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-border-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Border:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-border-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-y-padding-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Y-Padding:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-y-padding-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-x-padding-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_X-Padding:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-x-padding-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">4</property>
+                        <property name="right_attach">5</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="image-properties-alignment-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">Top
+Middle
+Bottom</property>
+                        <signal name="changed" handler="gtkhtml_editor_image_properties_alignment_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="image-properties-height-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">px
+%
+follow</property>
+                        <signal name="changed" handler="gtkhtml_editor_image_properties_size_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkComboBox" id="image-properties-width-combo-box">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="items" translatable="yes">px
+%
+follow</property>
+                        <signal name="changed" handler="gtkhtml_editor_image_properties_size_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="x_options"></property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="image-properties-height-spin-button">
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_image_properties_size_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkSpinButton" id="image-properties-width-spin-button">
+                        <property name="width_request">100</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="adjustment">0 0 100 1 10 10</property>
+                        <signal name="value_changed" handler="gtkhtml_editor_image_properties_size_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-alignment-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Alignment:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-alignment-combo-box</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-height-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Height:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-height-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-width-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_Width:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-width-spin-button</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkVBox" id="image-properties-link-vbox">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="image-properties-link-header">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Link&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="image-properties-link-alignment">
+                <property name="visible">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkTable" id="image-properties-link-table">
+                    <property name="visible">True</property>
+                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                    <property name="n_rows">1</property>
+                    <property name="n_columns">3</property>
+                    <property name="column_spacing">6</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <widget class="GtkLabel" id="image-properties-url-label">
+                        <property name="visible">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="xalign">1</property>
+                        <property name="label" translatable="yes">_URL:</property>
+                        <property name="use_underline">True</property>
+                        <property name="mnemonic_widget">image-properties-url-entry</property>
+                      </widget>
+                      <packing>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkEntry" id="image-properties-url-entry">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <signal name="changed" handler="gtkhtml_editor_image_properties_url_entry_changed_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <widget class="GtkButton" id="image-properties-url-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                        <property name="label" translatable="yes">_Test URL...</property>
+                        <property name="use_underline">True</property>
+                        <property name="response_id">0</property>
+                        <signal name="clicked" handler="gtkhtml_editor_image_properties_url_button_clicked_cb" object="image-properties-window"/>
+                      </widget>
+                      <packing>
+                        <property name="left_attach">2</property>
+                        <property name="right_attach">3</property>
+                        <property name="x_options">GTK_FILL</property>
+                        <property name="y_options"></property>
+                      </packing>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHButtonBox" id="image-properties-button-box">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="spacing">12</property>
+            <property name="layout_style">GTK_BUTTONBOX_END</property>
+            <child>
+              <widget class="GtkButton" id="image-properties-close-button">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+                <property name="label" translatable="yes">gtk-close</property>
+                <property name="use_stock">True</property>
+                <property name="response_id">0</property>
+                <signal name="clicked" handler="gtk_widget_hide" object="image-properties-window"/>
+              </widget>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">GTK_PACK_END</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
Index: components/editor/gtkhtml-spell-dialog.h
===================================================================
--- components/editor/gtkhtml-spell-dialog.h	(revision 0)
+++ components/editor/gtkhtml-spell-dialog.h	(revision 0)
@@ -0,0 +1,82 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-dialog.h
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GTKHTML_SPELL_DIALOG_H
+#define GTKHTML_SPELL_DIALOG_H
+
+#include <gtkhtml-editor-common.h>
+#include <gtkhtml-spell-checker.h>
+
+/* Standard GObject macros */
+#define GTKHTML_TYPE_SPELL_DIALOG \
+	(gtkhtml_spell_dialog_get_type ())
+#define GTKHTML_SPELL_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), GTKHTML_TYPE_SPELL_DIALOG, GtkhtmlSpellDialog))
+#define GTKHTML_SPELL_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), GTKHTML_TYPE_SPELL_DIALOG, GtkhtmlSpellDialogClass))
+#define GTKHTML_IS_SPELL_DIALOG(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), GTKHTML_TYPE_SPELL_DIALOG))
+#define GTKHTML_IS_SPELL_DIALOG_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), GTKHTML_TYPE_SPELL_DIALOG))
+#define GTKHTML_SPELL_DIALOG_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), GTKHTML_TYPE_SPELL_DIALOG, GtkhtmlSpellDialogClass))
+
+G_BEGIN_DECLS
+
+typedef struct _GtkhtmlSpellDialog GtkhtmlSpellDialog;
+typedef struct _GtkhtmlSpellDialogClass GtkhtmlSpellDialogClass;
+typedef struct _GtkhtmlSpellDialogPrivate GtkhtmlSpellDialogPrivate;
+
+struct _GtkhtmlSpellDialog {
+	GtkDialog parent;
+	GtkhtmlSpellDialogPrivate *priv;
+};
+
+struct _GtkhtmlSpellDialogClass {
+	GtkDialogClass parent_class;
+};
+
+GType		gtkhtml_spell_dialog_get_type	(void);
+GtkWidget *	gtkhtml_spell_dialog_new	(GtkWindow *parent);
+void		gtkhtml_spell_dialog_close	(GtkhtmlSpellDialog *dialog);
+const gchar *	gtkhtml_spell_dialog_get_word	(GtkhtmlSpellDialog *dialog);
+void		gtkhtml_spell_dialog_set_word	(GtkhtmlSpellDialog *dialog,
+						 const gchar *word);
+void		gtkhtml_spell_dialog_next_word	(GtkhtmlSpellDialog *dialog);
+void		gtkhtml_spell_dialog_prev_word	(GtkhtmlSpellDialog *dialog);
+GList *		gtkhtml_spell_dialog_get_spell_checkers
+						(GtkhtmlSpellDialog *dialog);
+void		gtkhtml_spell_dialog_set_spell_checkers
+						(GtkhtmlSpellDialog *dialog,
+						 GList *spell_checkers);
+GtkhtmlSpellChecker *
+		gtkhtml_spell_dialog_get_active_checker
+						(GtkhtmlSpellDialog *dialog);
+gchar *		gtkhtml_spell_dialog_get_active_suggestion
+						(GtkhtmlSpellDialog *dialog);
+
+G_END_DECLS
+
+#endif /* GTKHTML_SPELL_DIALOG_H */
Index: components/editor/gtkhtml-spell-checker.c
===================================================================
--- components/editor/gtkhtml-spell-checker.c	(revision 0)
+++ components/editor/gtkhtml-spell-checker.c	(revision 0)
@@ -0,0 +1,407 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-spell-checker.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gtkhtml-spell-checker.h"
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <enchant/enchant.h>
+
+#include "gtkhtml-spell-marshal.h"
+
+#define GTKHTML_SPELL_CHECKER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), GTKHTML_TYPE_SPELL_CHECKER, GtkhtmlSpellCheckerPrivate))
+
+enum {
+	PROP_0,
+	PROP_LANGUAGE
+};
+
+enum {
+	ADDED,
+	ADDED_TO_SESSION,
+	SESSION_CLEARED,
+	LAST_SIGNAL
+};
+
+struct _GtkhtmlSpellCheckerPrivate {
+	EnchantDict *dict;
+	EnchantBroker *broker;
+	const GtkhtmlSpellLanguage *language;
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static gboolean
+spell_checker_is_digit (const gchar *text,
+                        gssize length)
+{
+	const gchar *cp;
+	const gchar *end;
+
+	g_return_val_if_fail (text != NULL, FALSE);
+
+	if (length < 0)
+		length = strlen (text);
+
+	cp = text;
+	end = text + length;
+
+	while (cp != end) {
+		gunichar c;
+
+		c = g_utf8_get_char (cp);
+
+		if (!g_unichar_isdigit (c) && c != '.' && c != ',')
+			return FALSE;
+
+		cp = g_utf8_next_char (cp);
+	}
+
+	return TRUE;
+}
+
+static GObject *
+spell_checker_constructor (GType type,
+                           guint n_construct_properties,
+                           GObjectConstructParam *construct_properties)
+{
+	GObject *object;
+
+	/* Chain up to parent's constructor() method. */
+	object = G_OBJECT_CLASS (parent_class)->constructor (
+		type, n_construct_properties, construct_properties);
+
+	gtkhtml_spell_checker_clear_session (GTKHTML_SPELL_CHECKER (object));
+
+	return object;
+}
+
+static void
+spell_checker_set_property (GObject *object,
+                            guint property_id,
+                            const GValue *value,
+                            GParamSpec *pspec)
+{
+	GtkhtmlSpellCheckerPrivate *priv;
+
+	priv = GTKHTML_SPELL_CHECKER_GET_PRIVATE (object);
+
+	switch (property_id) {
+		case PROP_LANGUAGE:
+			priv->language = g_value_get_boxed (value);
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_checker_get_property (GObject *object,
+                            guint property_id,
+                            GValue *value,
+                            GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_LANGUAGE:
+			g_value_set_boxed (
+				value, gtkhtml_spell_checker_get_language (
+				GTKHTML_SPELL_CHECKER (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+spell_checker_finalize (GObject *object)
+{
+	GtkhtmlSpellCheckerPrivate *priv;
+
+	priv = GTKHTML_SPELL_CHECKER_GET_PRIVATE (object);
+
+	if (priv->dict != NULL)
+		enchant_broker_free_dict (priv->broker, priv->dict);
+	enchant_broker_free (priv->broker);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+spell_checker_class_init (GtkhtmlSpellCheckerClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (GtkhtmlSpellCheckerPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->constructor = spell_checker_constructor;
+	object_class->set_property = spell_checker_set_property;
+	object_class->get_property = spell_checker_get_property;
+	object_class->finalize = spell_checker_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_LANGUAGE,
+		g_param_spec_boxed (
+			"language",
+			_("Language"),
+			_("The language used by the spell checker"),
+			GTKHTML_TYPE_SPELL_LANGUAGE,
+			G_PARAM_CONSTRUCT_ONLY |
+			G_PARAM_READWRITE));
+
+	signals[ADDED] = g_signal_new (
+		"added",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (
+		GtkhtmlSpellCheckerClass, added),
+		NULL, NULL,
+		gtkhtml_spell_marshal_VOID__STRING_INT,
+		G_TYPE_NONE, 2,
+		G_TYPE_STRING,
+		G_TYPE_INT);
+
+	signals[ADDED_TO_SESSION] = g_signal_new (
+		"added-to-session",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (
+		GtkhtmlSpellCheckerClass, added_to_session),
+		NULL, NULL,
+		gtkhtml_spell_marshal_VOID__STRING_INT,
+		G_TYPE_NONE, 2,
+		G_TYPE_STRING,
+		G_TYPE_INT);
+
+	signals[SESSION_CLEARED] = g_signal_new (
+		"session-cleared",
+		G_OBJECT_CLASS_TYPE (object_class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (
+		GtkhtmlSpellCheckerClass, session_cleared),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+spell_checker_init (GtkhtmlSpellChecker *checker)
+{
+	checker->priv = GTKHTML_SPELL_CHECKER_GET_PRIVATE (checker);
+	checker->priv->broker = enchant_broker_init ();
+}
+
+GType
+gtkhtml_spell_checker_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (GtkhtmlSpellCheckerClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) spell_checker_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (GtkhtmlSpellChecker),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) spell_checker_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			G_TYPE_OBJECT, "GtkhtmlSpellChecker", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkhtmlSpellChecker *
+gtkhtml_spell_checker_new (const GtkhtmlSpellLanguage *language)
+{
+	return g_object_new (
+		GTKHTML_TYPE_SPELL_CHECKER, "language", language, NULL);
+}
+
+const GtkhtmlSpellLanguage *
+gtkhtml_spell_checker_get_language (GtkhtmlSpellChecker *checker)
+{
+	g_return_val_if_fail (GTKHTML_IS_SPELL_CHECKER (checker), NULL);
+
+	return checker->priv->language;
+}
+
+gboolean
+gtkhtml_spell_checker_check_word (GtkhtmlSpellChecker *checker,
+                                  const gchar *word,
+                                  gssize length)
+{
+	EnchantDict *dict;
+	gint result;
+
+	g_return_val_if_fail (GTKHTML_IS_SPELL_CHECKER (checker), FALSE);
+	g_return_val_if_fail (word != NULL, FALSE);
+
+	if ((dict = checker->priv->dict) == NULL)
+		return FALSE;
+
+	if (length < 0)
+		length = strlen (word);
+
+	if (spell_checker_is_digit (word, length))
+		return TRUE;
+
+	result = enchant_dict_check (dict, word, length);
+
+	if (result < 0)
+		g_warning (
+			"Error checking word '%s' (%s)",
+			word, enchant_dict_get_error (dict));
+
+	return (result == 0);
+}
+
+GList *
+gtkhtml_spell_checker_get_suggestions (GtkhtmlSpellChecker *checker,
+                                       const gchar *word,
+                                       gssize length)
+{
+	EnchantDict *dict;
+	gchar **suggestions;
+	gsize n_suggestions;
+	GList *list = NULL;
+
+	g_return_val_if_fail (GTKHTML_IS_SPELL_CHECKER (checker), NULL);
+
+	if ((dict = checker->priv->dict) == NULL)
+		return NULL;
+
+	suggestions = enchant_dict_suggest (
+		dict, word, length, &n_suggestions);
+
+	while (n_suggestions > 0)
+		list = g_list_prepend (list, suggestions[--n_suggestions]);
+
+	g_free (suggestions);
+
+	return g_list_sort (list, (GCompareFunc) g_utf8_collate);
+}
+
+void
+gtkhtml_spell_checker_store_replacement (GtkhtmlSpellChecker *checker,
+                                         const gchar *word,
+                                         gssize word_length,
+                                         const gchar *replacement,
+                                         gssize replacement_length)
+{
+	EnchantDict *dict;
+
+	g_return_if_fail (GTKHTML_IS_SPELL_CHECKER (checker));
+
+	if ((dict = checker->priv->dict) != NULL)
+		return;
+
+	enchant_dict_store_replacement (
+		dict, word, word_length, replacement, replacement_length);
+}
+
+void
+gtkhtml_spell_checker_add_word (GtkhtmlSpellChecker *checker,
+                                const gchar *word,
+                                gssize length)
+{
+	EnchantDict *dict;
+
+	g_return_if_fail (GTKHTML_IS_SPELL_CHECKER (checker));
+
+	if ((dict = checker->priv->dict) == NULL)
+		return;
+
+	enchant_dict_add_to_pwl (dict, word, length);
+	g_signal_emit (G_OBJECT (checker), signals[ADDED], 0, word, length);
+}
+
+void
+gtkhtml_spell_checker_add_word_to_session (GtkhtmlSpellChecker *checker,
+                                           const gchar *word,
+                                           gssize length)
+{
+	EnchantDict *dict;
+
+	g_return_if_fail (GTKHTML_IS_SPELL_CHECKER (checker));
+
+	if ((dict = checker->priv->dict) == NULL)
+		return;
+
+	enchant_dict_add_to_session (dict, word, length);
+	g_signal_emit (G_OBJECT (checker), signals[ADDED_TO_SESSION], 0, word, length);
+}
+
+void
+gtkhtml_spell_checker_clear_session (GtkhtmlSpellChecker *checker)
+{
+	GtkhtmlSpellCheckerPrivate *priv;
+
+	g_return_if_fail (GTKHTML_IS_SPELL_CHECKER (checker));
+
+	priv = checker->priv;
+
+	if (priv->dict != NULL) {
+		enchant_broker_free_dict (priv->broker, priv->dict);
+		priv->dict = NULL;
+	}
+
+	if (priv->language == NULL)
+		priv->language = gtkhtml_spell_language_lookup (NULL);
+
+	if (priv->language != NULL) {
+		const gchar *code;
+
+		code = gtkhtml_spell_language_get_code (priv->language);
+		priv->dict = enchant_broker_request_dict (priv->broker, code);
+	}
+
+	if (priv->dict == NULL) {
+		priv->language = NULL;
+		g_warning ("Cannot load the dictionary");
+	}
+
+	g_signal_emit (G_OBJECT (checker), signals[SESSION_CLEARED], 0);
+}
+
+gint
+gtkhtml_spell_checker_compare (GtkhtmlSpellChecker *checker_a,
+                               GtkhtmlSpellChecker *checker_b)
+{
+	const GtkhtmlSpellLanguage *language_a;
+	const GtkhtmlSpellLanguage *language_b;
+
+	language_a = gtkhtml_spell_checker_get_language (checker_a);
+	language_b = gtkhtml_spell_checker_get_language (checker_b);
+
+	return gtkhtml_spell_language_compare (language_a, language_b);
+}
Index: components/editor/gtkhtml-editor-signals.c
===================================================================
--- components/editor/gtkhtml-editor-signals.c	(revision 0)
+++ components/editor/gtkhtml-editor-signals.c	(revision 0)
@@ -0,0 +1,1930 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gtkhtml-editor-signals.c
+ *
+ * Copyright (C) 2008 Novell, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* This file is for widget signal handlers, primarily for property dialogs.
+ * Most of these handlers will be auto-connected by libglade.  GtkAction
+ * callbacks belong in gtkhtml-editor-actions.c. */
+
+#include "gtkhtml-editor-signals.h"
+
+#include <libgnome/gnome-url.h>
+
+#include "gtkhtml-editor-private.h"
+
+/* Think of this as a Python decorator.  It silences compiler
+ * warnings about "no previous prototype for 'function_name'". */
+#define AUTOCONNECTED_SIGNAL_HANDLER(x) x; x
+
+enum {
+	SIZE_UNIT_PX,
+	SIZE_UNIT_PERCENT,
+	SIZE_UNIT_FOLLOW
+};
+
+/* Dialogs are transient windows for the main editor window.  So
+ * given a dialog window we can extract the main editor window. */
+static GtkhtmlEditor *
+extract_gtkhtml_editor (GtkWidget *window)
+{
+	GtkhtmlEditor *editor;
+
+	g_object_get (window, "transient-for", &editor, NULL);
+	g_assert (GTKHTML_IS_EDITOR (editor));
+
+	return editor;
+}
+
+/*****************************************************************************
+ * Cell Properties Window
+ *****************************************************************************/
+
+typedef void (*CellCallback) (GtkhtmlEditor *editor,
+                              HTMLTableCell *cell,
+                              GtkWidget *widget);
+
+static void
+cell_properties_set_column (GtkhtmlEditor *editor,
+                            CellCallback callback,
+                            GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLObject *parent;
+	HTMLTableCell *cell;
+	HTMLTableCell *iter;
+
+	html = gtkhtml_editor_get_html (editor);
+	cell = HTML_TABLE_CELL (editor->priv->cell_object);
+	parent = editor->priv->cell_parent;
+
+	iter = html_engine_get_table_cell (html->engine);
+
+	while (iter != NULL) {
+		if (iter->col == cell->col &&
+			HTML_OBJECT (iter)->parent == parent)
+			callback (editor, iter, widget);
+		html_engine_next_cell (html->engine, FALSE);
+		iter = html_engine_get_table_cell (html->engine);
+	}
+}
+
+static void
+cell_properties_set_row (GtkhtmlEditor *editor,
+                         CellCallback callback,
+                         GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLObject *parent;
+	HTMLTableCell *cell;
+	HTMLTableCell *iter;
+
+	html = gtkhtml_editor_get_html (editor);
+	cell = HTML_TABLE_CELL (editor->priv->cell_object);
+	parent = editor->priv->cell_parent;
+
+	iter = html_engine_get_table_cell (html->engine);
+
+	while (iter != NULL && iter->row == cell->row) {
+		if (HTML_OBJECT (iter)->parent == parent)
+			callback (editor, iter, widget);
+		html_engine_next_cell (html->engine, FALSE);
+		iter = html_engine_get_table_cell (html->engine);
+	}
+}
+
+static void
+cell_properties_set_table (GtkhtmlEditor *editor,
+                           CellCallback callback,
+                           GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLObject *parent;
+	HTMLTableCell *cell;
+	HTMLTableCell *iter;
+
+	html = gtkhtml_editor_get_html (editor);
+	cell = HTML_TABLE_CELL (editor->priv->cell_object);
+	parent = editor->priv->cell_parent;
+
+	iter = html_engine_get_table_cell (html->engine);
+
+	while (iter != NULL) {
+		if (HTML_OBJECT (iter)->parent == parent)
+			callback (editor, iter, widget);
+		html_engine_next_cell (html->engine, FALSE);
+		iter = html_engine_get_table_cell (html->engine);
+	}
+}
+
+static void
+cell_properties_set (GtkhtmlEditor *editor,
+                     CellCallback callback,
+                     GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLTable *table;
+	HTMLTableCell *cell;
+	guint position;
+
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->cell_parent);
+	cell = HTML_TABLE_CELL (editor->priv->cell_object);
+
+	position = html->engine->cursor->position;
+
+	switch (editor->priv->cell_scope) {
+		case TABLE_CELL_SCOPE_CELL:
+			callback (editor, cell, widget);
+			break;
+
+		case TABLE_CELL_SCOPE_ROW:
+			if (html_engine_table_goto_row (
+				html->engine, table, cell->row))
+				cell_properties_set_row (
+					editor, callback, widget);
+			break;
+
+		case TABLE_CELL_SCOPE_COLUMN:
+			if (html_engine_table_goto_col (
+				html->engine, table, cell->col))
+				cell_properties_set_column (
+					editor, callback, widget);
+			break;
+
+		case TABLE_CELL_SCOPE_TABLE:
+			if (html_engine_goto_table_0 (html->engine, table))
+				cell_properties_set_table (
+					editor, callback, widget);
+			break;
+	}
+
+	html_cursor_jump_to_position (
+		html->engine->cursor, html->engine, position);
+}
+
+static void
+cell_properties_set_background_color_cb (GtkhtmlEditor *editor,
+                                         HTMLTableCell *cell,
+                                         GtkWidget *widget)
+{
+	GtkHTML *html;
+	GdkColor color;
+
+	html = gtkhtml_editor_get_html (editor);
+	gtkhtml_color_combo_get_current_color (
+		GTKHTML_COLOR_COMBO (widget), &color);
+
+	html_engine_table_cell_set_bg_color (html->engine, cell, &color);
+}
+
+static void
+cell_properties_set_background_image_cb (GtkhtmlEditor *editor,
+                                         HTMLTableCell *cell,
+                                         GtkWidget *widget)
+{
+	GtkHTML *html;
+	const gchar *filename;
+	gchar *uri;
+
+	html = gtkhtml_editor_get_html (editor);
+	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+
+	uri = gtk_html_filename_to_uri (filename);
+	html_engine_table_cell_set_bg_pixmap (html->engine, cell, uri);
+	g_free (uri);
+}
+
+static void
+cell_properties_set_column_span_cb (GtkhtmlEditor *editor,
+                                    HTMLTableCell *cell,
+                                    GtkWidget *widget)
+{
+	GtkHTML *html;
+	gint value;
+
+	html = gtkhtml_editor_get_html (editor);
+	widget = WIDGET (CELL_PROPERTIES_COLUMN_SPAN_SPIN_BUTTON);
+	value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	html_engine_set_cspan (html->engine, value);
+}
+
+static void
+cell_properties_set_header_style_cb (GtkhtmlEditor *editor,
+                                     HTMLTableCell *cell,
+                                     GtkWidget *widget)
+{
+	GtkHTML *html;
+	gboolean active;
+
+	html = gtkhtml_editor_get_html (editor);
+	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+	html_engine_table_cell_set_heading (html->engine, cell, active);
+}
+
+static void
+cell_properties_set_horizontal_alignment_cb (GtkhtmlEditor *editor,
+                                             HTMLTableCell *cell,
+                                             GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLHAlignType align;
+	gint active;
+
+	html = gtkhtml_editor_get_html (editor);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+	align = HTML_HALIGN_LEFT + (HTMLHAlignType) active;
+
+	html_engine_table_cell_set_halign (html->engine, cell, active);
+}
+
+static void
+cell_properties_set_row_span_cb (GtkhtmlEditor *editor,
+                                 HTMLTableCell *cell,
+                                 GtkWidget *widget)
+{
+	GtkHTML *html;
+	gint value;
+
+	html = gtkhtml_editor_get_html (editor);
+	widget = WIDGET (CELL_PROPERTIES_ROW_SPAN_SPIN_BUTTON);
+	value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	html_engine_set_rspan (html->engine, value);
+}
+
+static void
+cell_properties_set_vertical_alignment_cb (GtkhtmlEditor *editor,
+                                           HTMLTableCell *cell,
+                                           GtkWidget *widget)
+{
+	GtkHTML *html;
+	HTMLVAlignType align;
+	gint active;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	widget = WIDGET (CELL_PROPERTIES_VERTICAL_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+	align = HTML_VALIGN_TOP + (HTMLVAlignType) active;
+
+	html_engine_table_cell_set_valign (html->engine, cell, align);
+}
+
+static void
+cell_properties_set_width_cb (GtkhtmlEditor *editor,
+                              HTMLTableCell *cell,
+                              GtkWidget *widget)
+{
+	GtkHTML *html;
+	gboolean sensitive;;
+	gint active;
+	gint value;
+
+	html = gtkhtml_editor_get_html (editor);
+
+	sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+	widget = WIDGET (CELL_PROPERTIES_WIDTH_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+	widget = WIDGET (CELL_PROPERTIES_WIDTH_SPIN_BUTTON);
+	value = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	html_engine_table_cell_set_width (
+		html->engine, cell,
+		sensitive ? value : 0,
+		(active == SIZE_UNIT_PERCENT));
+}
+
+static void
+cell_properties_set_wrap_text_cb (GtkhtmlEditor *editor,
+                                  HTMLTableCell *cell,
+                                  GtkWidget *widget)
+{
+	GtkHTML *html;
+	gboolean active;
+
+	html = gtkhtml_editor_get_html (editor);
+	active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+	html_engine_table_cell_set_no_wrap (html->engine, cell, !active);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_color_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_background_color_cb,
+		WIDGET (CELL_PROPERTIES_COLOR_COMBO));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_column_span_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_column_span_cb,
+		WIDGET (CELL_PROPERTIES_COLUMN_SPAN_SPIN_BUTTON));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_image_file_set_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_background_image_cb,
+		WIDGET (CELL_PROPERTIES_IMAGE_FILE_CHOOSER));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_header_style_toggled_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_header_style_cb,
+		WIDGET (CELL_PROPERTIES_HEADER_STYLE_CHECK_BUTTON));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_horizontal_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_horizontal_alignment_cb,
+		WIDGET (CELL_PROPERTIES_HORIZONTAL_COMBO_BOX));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_row_span_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_row_span_cb,
+		WIDGET (CELL_PROPERTIES_ROW_SPAN_SPIN_BUTTON));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_scope_toggled_cb (GtkWidget *window,
+                                                 GtkWidget *button))
+{
+	GtkhtmlEditor *editor;
+
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
+		return;
+
+	editor = extract_gtkhtml_editor (window);
+
+	if (button == WIDGET (CELL_PROPERTIES_CELL_RADIO_BUTTON))
+		editor->priv->cell_scope = TABLE_CELL_SCOPE_CELL;
+
+	else if (button == WIDGET (CELL_PROPERTIES_ROW_RADIO_BUTTON))
+		editor->priv->cell_scope = TABLE_CELL_SCOPE_ROW;
+
+	else if (button == WIDGET (CELL_PROPERTIES_COLUMN_RADIO_BUTTON))
+		editor->priv->cell_scope = TABLE_CELL_SCOPE_COLUMN;
+
+	else if (button == WIDGET (CELL_PROPERTIES_TABLE_RADIO_BUTTON))
+		editor->priv->cell_scope = TABLE_CELL_SCOPE_TABLE;
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_show_window_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	HTMLTableCell *cell;
+	GtkWidget *widget;
+	GtkHTML *html;
+	gdouble value;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	cell = html_engine_get_table_cell (html->engine);
+	editor->priv->cell_object = HTML_OBJECT (cell);
+	g_assert (HTML_IS_TABLE_CELL (cell));
+
+	editor->priv->cell_parent = editor->priv->cell_object->parent;
+	g_assert (HTML_IS_TABLE (editor->priv->cell_parent));
+
+	/* Select 'cell' scope. */
+	widget = WIDGET (CELL_PROPERTIES_CELL_RADIO_BUTTON);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
+
+	widget = WIDGET (CELL_PROPERTIES_COLOR_COMBO);
+	if (cell->have_bg)
+		gtkhtml_color_combo_set_current_color (
+			GTKHTML_COLOR_COMBO (widget), &cell->bg);
+
+	widget = WIDGET (CELL_PROPERTIES_IMAGE_FILE_CHOOSER);
+	if (cell->have_bgPixmap) {
+		gchar *filename;
+
+		filename = gtk_html_filename_from_uri (cell->bgPixmap->url);
+		gtk_file_chooser_set_filename (
+			GTK_FILE_CHOOSER (widget), filename);
+		g_free (filename);
+	}
+
+	if (HTML_CLUE (cell)->halign == HTML_HALIGN_NONE)
+		active = HTML_HALIGN_LEFT;
+	else
+		active = HTML_CLUE (cell)->halign - HTML_HALIGN_LEFT;
+	widget = WIDGET (CELL_PROPERTIES_HORIZONTAL_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	active = HTML_CLUE (cell)->valign - HTML_VALIGN_TOP;
+	widget = WIDGET (CELL_PROPERTIES_VERTICAL_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	if (cell->percent_width) {
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_CHECK_BUTTON);
+		gtk_toggle_button_set_active (
+			GTK_TOGGLE_BUTTON (widget), TRUE);
+
+		value = (gdouble) cell->fixed_width;
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+		active = SIZE_UNIT_PERCENT;
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	} else if (cell->fixed_width) {
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_CHECK_BUTTON);
+		gtk_toggle_button_set_active (
+			GTK_TOGGLE_BUTTON (widget), TRUE);
+
+		value = (gdouble) cell->fixed_width;
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+		active = SIZE_UNIT_PX;
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	} else {
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_CHECK_BUTTON);
+		gtk_toggle_button_set_active (
+			GTK_TOGGLE_BUTTON (widget), FALSE);
+
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), 0.0);
+
+		widget = WIDGET (CELL_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), 0);
+	}
+
+	active = !cell->no_wrap;
+	widget = WIDGET (CELL_PROPERTIES_WRAP_TEXT_CHECK_BUTTON);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+
+	active = cell->heading;
+	widget = WIDGET (CELL_PROPERTIES_HEADER_STYLE_CHECK_BUTTON);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+
+	value = (gdouble) cell->cspan;
+	widget = WIDGET (CELL_PROPERTIES_COLUMN_SPAN_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) cell->rspan;
+	widget = WIDGET (CELL_PROPERTIES_ROW_SPAN_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_vertical_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_vertical_alignment_cb,
+		WIDGET (CELL_PROPERTIES_VERTICAL_COMBO_BOX));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_width_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkAdjustment *adjustment;
+	GtkWidget *widget;
+	gboolean sensitive;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+
+	widget = WIDGET (CELL_PROPERTIES_WIDTH_CHECK_BUTTON);
+	sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+	widget = WIDGET (CELL_PROPERTIES_WIDTH_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+	gtk_widget_set_sensitive (widget, sensitive);
+
+	widget = WIDGET (CELL_PROPERTIES_WIDTH_SPIN_BUTTON);
+	adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
+	gtk_widget_set_sensitive (widget, sensitive);
+
+	if (active == SIZE_UNIT_PERCENT) {
+		adjustment->upper = 100;
+		gtk_adjustment_changed (adjustment);
+	} else {
+		adjustment->upper = (gdouble) G_MAXINT;
+		gtk_adjustment_changed (adjustment);
+	}
+
+	/* Clamp the value between the new bounds. */
+	gtk_adjustment_set_value (adjustment, adjustment->value);
+
+	cell_properties_set (
+		editor, cell_properties_set_width_cb,
+		WIDGET (CELL_PROPERTIES_WIDTH_CHECK_BUTTON));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_cell_properties_wrap_text_toggled_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	cell_properties_set (
+		editor, cell_properties_set_wrap_text_cb,
+		WIDGET (CELL_PROPERTIES_WRAP_TEXT_CHECK_BUTTON));
+
+	g_object_unref (editor);
+}
+
+/*****************************************************************************
+ * Find Window
+ *****************************************************************************/
+
+static void
+sensitize_find_action (GtkWidget *window)
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+	gtk_action_set_sensitive (ACTION (FIND), TRUE);
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_find_backwards_toggled_cb (GtkWidget *window,
+                                          GtkToggleButton *button))
+{
+	sensitize_find_action (window);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_find_case_sensitive_toggled_cb (GtkWidget *window,
+                                               GtkToggleButton *button))
+{
+	if (!gtk_toggle_button_get_active (button))
+		sensitize_find_action (window);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_find_entry_activate_cb (GtkWidget *window,
+                                       GtkEntry *entry))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+	gtk_action_activate (ACTION (FIND));
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_find_entry_changed_cb (GtkWidget *window,
+                                      GtkEntry *entry))
+{
+	sensitize_find_action (window);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_find_regular_expression_toggled_cb (GtkWidget *window,
+                                                   GtkToggleButton *button))
+{
+	sensitize_find_action (window);
+}
+
+/*****************************************************************************
+ * Image Properties Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_alignment_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	HTMLVAlignType valign;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_ALIGNMENT_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+	valign = HTML_VALIGN_TOP + (HTMLVAlignType) active;
+
+	html_image_set_valign (image, valign);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_border_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	gint border;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_BORDER_SPIN_BUTTON);
+	border = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	html_image_set_border (image, border);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_description_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	const gchar *text;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_DESCRIPTION_ENTRY);
+	text = gtk_entry_get_text (GTK_ENTRY (widget));
+
+	/* Convert empty strings to NULL. */
+	if (text != NULL && *text == '\0')
+		text = NULL;
+
+	html_image_set_alt (image, text);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_padding_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	gint hspace;
+	gint vspace;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_X_PADDING_SPIN_BUTTON);
+	hspace = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	widget = WIDGET (IMAGE_PROPERTIES_Y_PADDING_SPIN_BUTTON);
+	vspace = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+
+	html_image_set_spacing (image, hspace, vspace);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_show_window_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLObject *parent;
+	HTMLImage *image;
+	GtkHTML *html;
+	gdouble value;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	editor->priv->image_object = html->engine->cursor->object;
+	image = HTML_IMAGE (editor->priv->image_object);
+	g_assert (HTML_IS_IMAGE (image));
+
+	widget = WIDGET (IMAGE_PROPERTIES_SOURCE_FILE_CHOOSER);
+	parent = editor->priv->image_object->parent;
+	if ((parent == NULL
+		|| html_object_get_data (parent, "template_image") == NULL)
+		&& image->image_ptr->url != NULL) {
+
+		gchar *filename;
+
+		filename = gtk_html_filename_from_uri (image->image_ptr->url);
+		gtk_file_chooser_set_filename (
+			GTK_FILE_CHOOSER (widget), filename);
+		g_free (filename);
+	} else
+		gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (widget));
+
+	widget = WIDGET (IMAGE_PROPERTIES_DESCRIPTION_ENTRY);
+	if (image->alt != NULL)
+		gtk_entry_set_text (GTK_ENTRY (widget), image->alt);
+	else
+		gtk_entry_set_text (GTK_ENTRY (widget), "");
+
+	if (image->percent_width) {
+		active = SIZE_UNIT_PERCENT;
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) image->specified_width;
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	} else if (image->specified_width > 0) {
+		active = SIZE_UNIT_PX;
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) image->specified_width;
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	} else {
+		active = SIZE_UNIT_FOLLOW;
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) html_image_get_actual_width (image, NULL);
+		widget = WIDGET (IMAGE_PROPERTIES_WIDTH_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+	}
+
+	if (image->percent_height) {
+		active = SIZE_UNIT_PERCENT;
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) image->specified_height;
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	} else if (image->specified_height > 0) {
+		active = SIZE_UNIT_PX;
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) image->specified_height;
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	} else {
+		active = SIZE_UNIT_FOLLOW;
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_COMBO_BOX);
+		gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+		value = (gdouble) html_image_get_actual_height (image, NULL);
+		widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_SPIN_BUTTON);
+		gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+	}
+
+	active = image->valign - HTML_VALIGN_TOP;
+	widget = WIDGET (IMAGE_PROPERTIES_ALIGNMENT_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	value = (gdouble) image->hspace;
+	widget = WIDGET (IMAGE_PROPERTIES_X_PADDING_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) image->vspace;
+	widget = WIDGET (IMAGE_PROPERTIES_Y_PADDING_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) image->border;
+	widget = WIDGET (IMAGE_PROPERTIES_BORDER_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	widget = WIDGET (IMAGE_PROPERTIES_URL_ENTRY);
+	if (image->url != NULL) {
+		gchar *text;
+
+		if (image->target != NULL)
+			text = g_strdup_printf (
+				"%s#%s", image->url, image->target);
+		else
+			text = g_strdup (image->url);
+		gtk_entry_set_text (GTK_ENTRY (widget), text);
+		g_free (text);
+	} else
+		gtk_entry_set_text (GTK_ENTRY (widget), "");
+
+	widget = WIDGET (IMAGE_PROPERTIES_URL_BUTTON);
+	gtk_widget_set_sensitive (widget, image->url != NULL);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_size_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	gint height_units;
+	gint width_units;
+	gint height;
+	gint width;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_WIDTH_COMBO_BOX);
+	width_units = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+	widget = WIDGET (IMAGE_PROPERTIES_WIDTH_SPIN_BUTTON);
+	width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+	gtk_widget_set_sensitive (widget, (width_units != SIZE_UNIT_FOLLOW));
+
+	widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_COMBO_BOX);
+	height_units = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+	widget = WIDGET (IMAGE_PROPERTIES_HEIGHT_SPIN_BUTTON);
+	height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (widget));
+	gtk_widget_set_sensitive (widget, (height_units != SIZE_UNIT_FOLLOW));
+
+	html_image_set_size (
+		image,
+		(width_units != SIZE_UNIT_FOLLOW) ? width : 0,
+		(height_units != SIZE_UNIT_FOLLOW) ? height : 0,
+		(width_units == SIZE_UNIT_PERCENT),
+		(height_units == SIZE_UNIT_PERCENT));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_source_file_set_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLImage *image;
+	gchar *filename;
+	gchar *url = NULL;
+
+	editor = extract_gtkhtml_editor (window);
+	image = HTML_IMAGE (editor->priv->image_object);
+
+	widget = WIDGET (IMAGE_PROPERTIES_SOURCE_FILE_CHOOSER);
+	filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+
+	if (filename != NULL)
+		url = gtk_html_filename_to_uri (filename);
+
+	html_image_edit_set_url (image, url);
+
+	g_free (filename);
+	g_free (url);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_url_button_clicked_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	const gchar *text;
+
+	editor = extract_gtkhtml_editor (window);
+
+	widget = WIDGET (IMAGE_PROPERTIES_URL_ENTRY);
+	text = gtk_entry_get_text (GTK_ENTRY (widget));
+
+	g_return_if_fail (text != NULL);
+	gnome_url_show (text, NULL);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_image_properties_url_entry_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	HTMLColorSet *color_set;
+	HTMLColor *color;
+	GtkWidget *widget;
+	GtkHTML *html;
+	gchar **parts;
+	guint length;
+	const gchar *text;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	color_set = html->engine->settings->color_set;
+
+	widget = WIDGET (IMAGE_PROPERTIES_URL_ENTRY);
+	text = gtk_entry_get_text (GTK_ENTRY (widget));
+
+	widget = WIDGET (IMAGE_PROPERTIES_URL_BUTTON);
+	if (text != NULL && *text != '\0') {
+		color = html_colorset_get_color (color_set, HTMLLinkColor);
+		gtk_widget_set_sensitive (widget, TRUE);
+	} else {
+		color = html_colorset_get_color (color_set, HTMLTextColor);
+		gtk_widget_set_sensitive (widget, FALSE);
+	}
+
+	parts = g_strsplit (text, "#", 2);
+	length = g_strv_length (parts);
+
+	html_object_set_link (
+		editor->priv->image_object, color,
+		(length > 0) ? parts[0] : NULL,
+		(length > 1) ? parts[1] : NULL);
+
+	g_strfreev (parts);
+
+	g_object_unref (editor);
+}
+
+/*****************************************************************************
+ * Link Properties Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_link_properties_description_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *dsc_entry;
+	GtkWidget *url_entry;
+	GtkHTML *html;
+	gchar *text;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	dsc_entry = WIDGET (LINK_PROPERTIES_DESCRIPTION_ENTRY);
+	url_entry = WIDGET (LINK_PROPERTIES_URL_ENTRY);
+
+	text = g_strstrip (g_strdup (
+		gtk_entry_get_text (GTK_ENTRY (dsc_entry))));
+
+	editor->priv->link_custom_description = (*text != '\0');
+
+	if (editor->priv->link_custom_description) {
+		gint start_offset;
+		gint end_offset;
+		glong length;
+
+		start_offset = editor->priv->link_start_offset;
+		end_offset = editor->priv->link_end_offset;
+		length = g_utf8_strlen (text, -1);
+
+		if (start_offset != end_offset) {
+			html_cursor_jump_to (
+				html->engine->cursor, html->engine,
+				editor->priv->link_object, start_offset);
+			html_engine_set_mark (html->engine);
+			html_cursor_jump_to (
+				html->engine->cursor, html->engine,
+				editor->priv->link_object, end_offset);
+			html_engine_delete (html->engine);
+		}
+
+		html_engine_paste_link (
+			html->engine, text, length,
+			gtk_entry_get_text (GTK_ENTRY (url_entry)));
+
+		editor->priv->link_object = html->engine->cursor->object;
+		editor->priv->link_end_offset = start_offset + length;
+	}
+
+	g_free (text);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_link_properties_url_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *dsc_entry;
+	GtkWidget *url_entry;
+	GtkHTML *html;
+	gchar *text;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	dsc_entry = WIDGET (LINK_PROPERTIES_DESCRIPTION_ENTRY);
+	url_entry = WIDGET (LINK_PROPERTIES_URL_ENTRY);
+
+	text = g_strstrip (g_strdup (
+		gtk_entry_get_text (GTK_ENTRY (url_entry))));
+
+	gtk_action_set_sensitive (ACTION (TEST_URL), *text != '\0');
+
+	if (html_engine_is_selection_active (html->engine))
+		html_engine_set_link (html->engine, text);
+	else if (!editor->priv->link_custom_description) {
+		gtk_entry_set_text (GTK_ENTRY (dsc_entry), text);
+		editor->priv->link_custom_description = FALSE;
+	}
+
+	g_free (text);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_link_properties_show_window_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *dsc_entry;
+	GtkWidget *url_entry;
+	GtkHTML *html;
+	gchar *url = NULL;
+	gboolean sensitive;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	dsc_entry = WIDGET (LINK_PROPERTIES_DESCRIPTION_ENTRY);
+	url_entry = WIDGET (LINK_PROPERTIES_URL_ENTRY);
+
+	if (html_engine_is_selection_active (html->engine)) {
+		sensitive = FALSE;
+		editor->priv->link_object = NULL;
+	} else {
+		HTMLCursor *cursor;
+		gint start_offset = 0;
+		gint end_offset = 0;
+
+		cursor = html->engine->cursor;
+		editor->priv->link_object = cursor->object;
+
+		if (HTML_IS_TEXT (cursor->object))
+			url = html_object_get_complete_url (
+				cursor->object, cursor->offset);
+
+		if (url != NULL) {
+			if (HTML_IS_IMAGE (cursor->object)) {
+				start_offset = 0;
+				end_offset = 1;
+			} else {
+				Link *link;
+
+				link = html_text_get_link_at_offset (
+					HTML_TEXT (cursor->object),
+					cursor->offset);
+				if (link != NULL) {
+					start_offset = link->start_offset;
+					end_offset = link->end_offset;
+				}
+			}
+		} else if (HTML_IS_TEXT (cursor->object)) {
+			start_offset = cursor->offset;
+			end_offset = start_offset;
+		}
+
+		sensitive = (url == NULL);
+
+		gtk_entry_set_text (
+			GTK_ENTRY (url_entry),
+			(url != NULL) ? url : "http://");
+
+		editor->priv->link_object = cursor->object;
+		editor->priv->link_start_offset = start_offset;
+		editor->priv->link_end_offset = end_offset;
+	}
+
+	gtk_entry_set_text (GTK_ENTRY (dsc_entry), "");
+	gtk_widget_set_sensitive (dsc_entry, sensitive);
+	gtk_widget_grab_focus (url_entry);
+
+	g_free (url);
+
+	g_object_unref (editor);
+}
+
+/*****************************************************************************
+ * Page Properties Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_background_color_changed_cb (GtkWidget *window,
+                                                            GtkhtmlColorCombo *combo))
+{
+	const HTMLColorId color_id = HTMLBgColor;
+	GtkhtmlEditor *editor;
+	GdkColor color;
+	GtkHTML *html;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	if (!gtkhtml_color_combo_get_current_color (combo, &color))
+		color = html_colorset_get_color (
+			html->engine->defaultSettings->color_set,
+			color_id)->color;
+
+	html_colorset_set_color (
+		html->engine->settings->color_set, &color, color_id);
+	html_object_change_set_down (
+		html->engine->clue, HTML_CHANGE_RECALC_PI);
+
+	gtk_widget_queue_draw (GTK_WIDGET (html));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_custom_file_changed_cb (GtkWidget *window,
+                                                       GtkFileChooser *file_chooser))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	gchar *filename;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	if (html->engine->bgPixmapPtr != NULL) {
+		html_image_factory_unregister (
+			html->engine->image_factory,
+			html->engine->bgPixmapPtr, NULL);
+		html->engine->bgPixmapPtr = NULL;
+	}
+
+	filename = gtk_file_chooser_get_filename (file_chooser);
+	if (filename != NULL && *filename != '\0') {
+		gchar *uri;
+
+		uri = gtk_html_filename_to_uri (filename);
+		html->engine->bgPixmapPtr = html_image_factory_register (
+			html->engine->image_factory, NULL, uri, TRUE);
+		g_free (uri);
+	}
+	g_free (filename);
+
+	gtk_widget_queue_draw (GTK_WIDGET (html));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_link_color_changed_cb (GtkWidget *window,
+                                                      GtkhtmlColorCombo *combo))
+{
+	const HTMLColorId color_id = HTMLLinkColor;
+	GtkhtmlEditor *editor;
+	GdkColor color;
+	GtkHTML *html;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	if (!gtkhtml_color_combo_get_current_color (combo, &color))
+		color = html_colorset_get_color (
+			html->engine->defaultSettings->color_set,
+			color_id)->color;
+
+	html_colorset_set_color (
+		html->engine->settings->color_set, &color, color_id);
+	html_object_change_set_down (
+		html->engine->clue, HTML_CHANGE_RECALC_PI);
+
+	gtk_widget_queue_draw (GTK_WIDGET (html));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_template_changed_cb (GtkWidget *window,
+                                                    GtkComboBox *combo_box))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	GtkWidget *widget;
+	gchar *filename;
+
+	/* Template Parameters */
+	const gchar *basename;
+	GdkColor text_color;
+	GdkColor link_color;
+	GdkColor bgnd_color;
+	gint left_margin = 10;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	switch (gtk_combo_box_get_active (combo_box)) {
+		case 0:
+			basename = NULL;
+			text_color = html_colorset_get_color_allocated (
+				html->engine->settings->color_set,
+				html->engine->painter,
+				HTMLTextColor)->color;
+			link_color = html_colorset_get_color_allocated (
+				html->engine->settings->color_set,
+				html->engine->painter,
+				HTMLLinkColor)->color;
+			bgnd_color = html_colorset_get_color_allocated (
+				html->engine->settings->color_set,
+				html->engine->painter,
+				HTMLBgColor)->color;
+			break;
+
+		case 1:
+			basename = "paper.png";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x0;
+			link_color.red   = 0x0;
+			link_color.green = 0x3380;
+			link_color.blue  = 0x6680;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			left_margin = 30;
+			break;
+
+		case 2:
+			basename = "texture.png";
+			text_color.red   = 0x1FFF;
+			text_color.green = 0x1FFF;
+			text_color.blue  = 0x8FFF;
+			link_color.red   = 0x0;
+			link_color.green = 0x0;
+			link_color.blue  = 0xFFFF;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			break;
+
+		case 3:
+			basename = "rect.png";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x0;
+			link_color.red   = 0x0;
+			link_color.green = 0x0;
+			link_color.blue  = 0xFFFF;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			break;
+
+		case 4:
+			basename = "ribbon.jpg";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x0;
+			link_color.red   = 0x9900;
+			link_color.green = 0x3300;
+			link_color.blue  = 0x6600;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			left_margin = 70;
+			break;
+
+		case 5:
+			basename = "midnight-stars.jpg";
+			text_color.red   = 0xFFFF;
+			text_color.green = 0xFFFF;
+			text_color.blue  = 0xFFFF;
+			link_color.red   = 0xFFFF;
+			link_color.green = 0x9900;
+			link_color.blue  = 0x0;
+			bgnd_color.red   = 0x0;
+			bgnd_color.green = 0x0;
+			bgnd_color.blue  = 0x0;
+			break;
+
+		case 6:
+			basename = "confidential-stamp.jpg";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x0;
+			link_color.red   = 0x0;
+			link_color.green = 0x0;
+			link_color.blue  = 0xFFFF;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			break;
+
+		case 7:
+			basename = "draft-stamp.jpg";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x0;
+			link_color.red   = 0x0;
+			link_color.green = 0x0;
+			link_color.blue  = 0xFFFF;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			break;
+
+		case 8:
+			basename = "draft-paper.png";
+			text_color.red   = 0x0;
+			text_color.green = 0x0;
+			text_color.blue  = 0x8000;
+			link_color.red   = 0xE300;
+			link_color.green = 0x2100;
+			link_color.blue  = 0x2300;
+			bgnd_color.red   = 0xFFFF;
+			bgnd_color.green = 0xFFFF;
+			bgnd_color.blue  = 0xFFFF;
+			break;
+
+		default:
+			g_return_if_reached ();
+	}
+
+	widget = WIDGET (PAGE_PROPERTIES_CUSTOM_FILE_CHOOSER);
+	if (basename != NULL)
+		filename = g_build_filename (ICONDIR, basename, NULL);
+	else
+		filename = g_strdup ("");
+	gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
+	g_free (filename);
+
+	widget = WIDGET (PAGE_PROPERTIES_TEXT_COLOR_COMBO);
+	gtkhtml_color_combo_set_current_color (
+		GTKHTML_COLOR_COMBO (widget), &text_color);
+
+	widget = WIDGET (PAGE_PROPERTIES_LINK_COLOR_COMBO);
+	gtkhtml_color_combo_set_current_color (
+		GTKHTML_COLOR_COMBO (widget), &link_color);
+
+	widget = WIDGET (PAGE_PROPERTIES_BACKGROUND_COLOR_COMBO);
+	gtkhtml_color_combo_set_current_color (
+		GTKHTML_COLOR_COMBO (widget), &bgnd_color);
+
+	html->engine->leftBorder = left_margin;
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_text_color_changed_cb (GtkWidget *window,
+                                                      GtkhtmlColorCombo *combo))
+{
+	const HTMLColorId color_id = HTMLTextColor;
+	GtkhtmlEditor *editor;
+	GdkColor color;
+	GtkHTML *html;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	if (!gtkhtml_color_combo_get_current_color (combo, &color))
+		color = html_colorset_get_color (
+			html->engine->defaultSettings->color_set,
+			color_id)->color;
+
+	gtkhtml_color_state_set_default_color (
+		editor->priv->text_color, &color);
+
+	html_colorset_set_color (
+		html->engine->settings->color_set, &color, color_id);
+	html_object_change_set_down (
+		html->engine->clue, HTML_CHANGE_RECALC_PI);
+
+	gtk_widget_queue_draw (GTK_WIDGET (html));
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_page_properties_window_realized_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+
+	/* Active "None" Template */
+	gtk_combo_box_set_active (
+		GTK_COMBO_BOX (WIDGET (
+		PAGE_PROPERTIES_TEMPLATE_COMBO_BOX)), 0);
+
+	g_object_unref (editor);
+}
+
+/*****************************************************************************
+ * Rule Properties Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_rule_properties_alignment_changed_cb (GtkWidget *window,
+                                                     GtkComboBox *combo_box))
+{
+	GtkhtmlEditor *editor;
+	HTMLHAlignType align;
+	GtkHTML *html;
+	HTMLRule *rule;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	rule = HTML_RULE (editor->priv->rule_object);
+
+	align = HTML_HALIGN_LEFT + gtk_combo_box_get_active (combo_box);
+	html_rule_set_align (rule, html->engine, align);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_rule_properties_shaded_toggled_cb (GtkWidget *window,
+                                                  GtkToggleButton *button))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	HTMLRule *rule;
+	gboolean active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	rule = HTML_RULE (editor->priv->rule_object);
+
+	active = gtk_toggle_button_get_active (button);
+	html_rule_set_shade (rule, html->engine, active);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_rule_properties_size_changed_cb (GtkWidget *window,
+                                                GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	HTMLRule *rule;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	rule = HTML_RULE (editor->priv->rule_object);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_rule_set_size (rule, html->engine, value);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_rule_properties_show_window_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLRule *rule;
+	GtkHTML *html;
+	gdouble value;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	editor->priv->rule_object = html->engine->cursor->object;
+	rule = HTML_RULE (editor->priv->rule_object);
+	g_assert (HTML_IS_RULE (rule));
+
+	if (editor->priv->rule_object->percent > 0) {
+		value = (gdouble) editor->priv->rule_object->percent;
+		active = SIZE_UNIT_PERCENT;
+	} else {
+		value = (gdouble) rule->length;
+		active = SIZE_UNIT_PX;
+	}
+
+	widget = WIDGET (RULE_PROPERTIES_WIDTH_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	widget = WIDGET (RULE_PROPERTIES_WIDTH_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	value = (gdouble) rule->size;
+	widget = WIDGET (RULE_PROPERTIES_SIZE_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	active = rule->halign - HTML_HALIGN_LEFT;
+	widget = WIDGET (RULE_PROPERTIES_ALIGNMENT_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	active = rule->shade;
+	widget = WIDGET (RULE_PROPERTIES_SHADED_CHECK_BUTTON);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_rule_properties_width_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkAdjustment *adjustment;
+	GtkWidget *widget;
+	GtkHTML *html;
+	HTMLRule *rule;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	rule = HTML_RULE (editor->priv->rule_object);
+
+	widget = WIDGET (RULE_PROPERTIES_WIDTH_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+
+	widget = WIDGET (RULE_PROPERTIES_WIDTH_SPIN_BUTTON);
+	adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
+
+	if (active == SIZE_UNIT_PERCENT) {
+		adjustment->upper = 100;
+		gtk_adjustment_changed (adjustment);
+	} else {
+		adjustment->upper = (gdouble) G_MAXINT;
+		gtk_adjustment_changed (adjustment);
+	}
+
+	/* Clamp the value between the new bounds. */
+	gtk_adjustment_set_value (adjustment, adjustment->value);
+
+	html_rule_set_length (
+		rule, html->engine,
+		(active == SIZE_UNIT_PX) ? (gint) adjustment->value : 0,
+		(active == SIZE_UNIT_PX) ? 0 : (gint) adjustment->value);
+
+	g_object_unref (editor);
+}
+
+/*****************************************************************************
+ * Replace Confirmation Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (gboolean
+gtkhtml_editor_replace_confirmation_delete_event_cb (GtkWidget *window,
+                                                     GdkEvent *event))
+{
+	GtkhtmlEditor *editor;
+
+	editor = extract_gtkhtml_editor (window);
+	gtk_action_activate (ACTION (CONFIRM_REPLACE_CANCEL));
+	g_object_unref (editor);
+
+	return gtk_widget_hide_on_delete (window);
+}
+
+/*****************************************************************************
+ * Table Properties Window
+ *****************************************************************************/
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_alignment_changed_cb (GtkWidget *window,
+                                                      GtkComboBox *combo_box))
+{
+	GtkhtmlEditor *editor;
+	HTMLHAlignType align;
+	GtkHTML *html;
+	HTMLTable *table;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	html_cursor_forward (html->engine->cursor, html->engine);
+
+	align = HTML_HALIGN_LEFT + gtk_combo_box_get_active (combo_box);
+	html_engine_table_set_align (html->engine, table, align);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_border_changed_cb (GtkWidget *window,
+                                                   GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	HTMLTable *table;
+	GtkHTML *html;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	html_cursor_forward (html->engine->cursor, html->engine);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_engine_table_set_border_width (html->engine, table, value, FALSE);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_cols_changed_cb (GtkWidget *window,
+                                                 GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	html_cursor_jump_to (
+		html->engine->cursor, html->engine,
+		editor->priv->table_object, 1);
+	html_cursor_backward (html->engine->cursor, html->engine);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_engine_table_set_cols (html->engine, value);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_image_changed_cb (GtkWidget *window,
+                                                  GtkFileChooser *file_chooser))
+{
+	GtkhtmlEditor *editor;
+	HTMLTable *table;
+	GtkHTML *html;
+	gchar *uri;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	html_cursor_forward (html->engine->cursor, html->engine);
+
+	uri = gtk_file_chooser_get_uri (file_chooser);
+	html_engine_table_set_bg_pixmap (html->engine, table, uri);
+	g_free (uri);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_padding_changed_cb (GtkWidget *window,
+                                                    GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	HTMLTable *table;
+	GtkHTML *html;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	html_cursor_forward (html->engine->cursor, html->engine);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_engine_table_set_padding (html->engine, table, value, FALSE);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_spacing_changed_cb (GtkWidget *window,
+                                                    GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	HTMLTable *table;
+	GtkHTML *html;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	html_cursor_forward (html->engine->cursor, html->engine);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_engine_table_set_spacing (html->engine, table, value, FALSE);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_rows_changed_cb (GtkWidget *window,
+                                                 GtkSpinButton *button))
+{
+	GtkhtmlEditor *editor;
+	GtkHTML *html;
+	gint value;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	html_cursor_jump_to (
+		html->engine->cursor, html->engine,
+		editor->priv->table_object, 1);
+	html_cursor_backward (html->engine->cursor, html->engine);
+
+	value = gtk_spin_button_get_value_as_int (button);
+	html_engine_table_set_rows (html->engine, value);
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_show_window_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkWidget *widget;
+	HTMLTable *table;
+	HTMLClue *clue;
+	GtkHTML *html;
+	gdouble value;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+
+	table = html_engine_get_table (html->engine);
+	editor->priv->table_object = HTML_OBJECT (table);
+	g_assert (HTML_IS_TABLE (table));
+
+	value = (gdouble) table->totalRows;
+	widget = WIDGET (TABLE_PROPERTIES_ROWS_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) table->totalCols;
+	widget = WIDGET (TABLE_PROPERTIES_COLS_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	if (editor->priv->table_object->percent > 0) {
+		value = (gdouble) editor->priv->table_object->percent;
+		active = SIZE_UNIT_PERCENT;
+	} else if (table->specified_width > 0) {
+		value = (gdouble) table->specified_width;
+		active = SIZE_UNIT_PX;
+	} else {
+		value = 0.0;
+		active = SIZE_UNIT_PERCENT;
+	}
+
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	active = (value > 0.0);
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_CHECK_BUTTON);
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), active);
+
+	clue = HTML_CLUE (editor->priv->table_object->parent);
+	active = clue->halign - HTML_HALIGN_LEFT;
+	if (active == HTML_HALIGN_NONE)
+		active = HTML_HALIGN_LEFT;
+	widget = WIDGET (TABLE_PROPERTIES_ALIGNMENT_COMBO_BOX);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active);
+
+	value = (gdouble) table->spacing;
+	widget = WIDGET (TABLE_PROPERTIES_SPACING_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) table->padding;
+	widget = WIDGET (TABLE_PROPERTIES_PADDING_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	value = (gdouble) table->border;
+	widget = WIDGET (TABLE_PROPERTIES_BORDER_SPIN_BUTTON);
+	gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+
+	/* TODO - Initialize color combo */
+
+	if (table->bgPixmap != NULL) {
+		gchar *filename;
+		GError *error = NULL;
+
+		filename = g_filename_from_uri (
+			table->bgPixmap->url, NULL, &error);
+		if (filename != NULL) {
+			widget = WIDGET (TABLE_PROPERTIES_IMAGE_BUTTON);
+			gtk_file_chooser_set_filename (
+				GTK_FILE_CHOOSER (widget), filename);
+			g_free (filename);
+		} else {
+			g_assert (error != NULL);
+			g_warning ("%s", error->message);
+			g_error_free (error);
+		}
+	}
+
+	g_object_unref (editor);
+}
+
+AUTOCONNECTED_SIGNAL_HANDLER (void
+gtkhtml_editor_table_properties_width_changed_cb (GtkWidget *window))
+{
+	GtkhtmlEditor *editor;
+	GtkAdjustment *adjustment;
+	GtkWidget *widget;
+	GtkHTML *html;
+	HTMLTable *table;
+	gboolean sensitive;
+	gint active;
+
+	editor = extract_gtkhtml_editor (window);
+	html = gtkhtml_editor_get_html (editor);
+	table = HTML_TABLE (editor->priv->table_object);
+
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_CHECK_BUTTON);
+	sensitive = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_COMBO_BOX);
+	active = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+	gtk_widget_set_sensitive (widget, sensitive);
+
+	widget = WIDGET (TABLE_PROPERTIES_WIDTH_SPIN_BUTTON);
+	adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
+	gtk_widget_set_sensitive (widget, sensitive);
+
+	if (active == SIZE_UNIT_PERCENT) {
+		adjustment->upper = 100;
+		gtk_adjustment_changed (adjustment);
+	} else {
+		adjustment->upper = (gdouble) G_MAXINT;
+		gtk_adjustment_changed (adjustment);
+	}
+
+	/* Clamp the value between the new bounds. */
+	gtk_adjustment_set_value (adjustment, adjustment->value);
+
+	html_engine_table_set_width (
+		html->engine, table,
+		sensitive ? (gint) adjustment->value : 0,
+		(active == SIZE_UNIT_PERCENT));
+
+	g_object_unref (editor);
+}
Index: components/html-editor/Makefile.am
===================================================================
--- components/html-editor/Makefile.am	(revision 8785)
+++ components/html-editor/Makefile.am	(working copy)
@@ -13,7 +13,6 @@ endif
 
 INCLUDES = \
 	-I$(top_srcdir)/gtkhtml \
-	-I$(srcdir) \
 	-I$(includedir) \
 	$(GTKHTML_CFLAGS) \
 	$(EDITOR_I18N_CFLAGS) \
Index: components/Makefile.am
===================================================================
--- components/Makefile.am	(revision 8785)
+++ components/Makefile.am	(working copy)
@@ -1 +1,5 @@
-SUBDIRS = html-editor
+SUBDIRS = editor
+
+if BONOBO_EDITOR
+SUBDIRS += html-editor
+endif
Index: configure.in
===================================================================
--- configure.in	(revision 8785)
+++ configure.in	(working copy)
@@ -8,6 +8,7 @@ PACKAGE=gtkhtml
 # Required Package Versions
 m4_define([gtk_minimum_version], [2.12.0])
 m4_define([gail_minimum_version], [1.1.0])
+m4_define([gladeui_minimum_version], [3.0.0])
 m4_define([gnome_icon_theme_minimum_version], [1.2.0])
 m4_define([libbonobo_minimum_version], [2.20.3])
 m4_define([libbonoboui_minimum_version], [2.2.4])
@@ -52,6 +53,8 @@ AC_STDC_HEADERS
 AC_LIBTOOL_WIN32_DLL
 AM_PROG_LIBTOOL
 
+AC_PATH_PROG(GLIB_GENMARSHAL, glib-genmarshal)
+
 dnl Win32
 AC_MSG_CHECKING([for Win32])
 case "$host" in
@@ -82,22 +85,35 @@ AC_SUBST(GAIL_CFLAGS)
 AC_SUBST(GAIL_LIBS)
 AC_SUBST(GAIL_MODULES)
 
-GTKHTML_MODULES="gtk+-2.0 >= gtk_minimum_version libgnomeui-2.0 >= libgnomeui_minimum_version libglade-2.0 >= libglade_minimum_version"
+GTKHTML_MODULES="gtk+-2.0 >= gtk_minimum_version libgnomeui-2.0 >= libgnomeui_minimum_version libglade-2.0 >= libglade_minimum_version enchant iso-codes"
 PKG_CHECK_MODULES(GTKHTML, $GTKHTML_MODULES)
 AC_SUBST(GTKHTML_CFLAGS)
 AC_SUBST(GTKHTML_LIBS)
 AC_SUBST(GTKHTML_MODULES)
 
-EDITOR_MODULES="${GTKHTML_MODULES} libbonobo-2.0 >= libbonobo_minimum_version libbonoboui-2.0 >= libbonoboui_minimum_version"
-PKG_CHECK_MODULES(EDITOR, $EDITOR_MODULES)
-AC_SUBST(EDITOR_CFLAGS)
-AC_SUBST(EDITOR_LIBS)
+# Bonobo editor module
+AC_ARG_WITH(bonobo-editor,
+        AC_HELP_STRING([--with-bonobo-editor],
+                [build the older Bonobo-based editor [default=yes]]),
+        bonobo_editor="$withval", bonobo_editor="yes")
+if test "x$bonobo_editor" = "xyes"; then
+        EDITOR_MODULES="${GTKHTML_MODULES} libbonobo-2.0 >= libbonobo_minimum_version libbonoboui-2.0 >= libbonoboui_minimum_version"
+        PKG_CHECK_MODULES(EDITOR, $EDITOR_MODULES)
+        AC_SUBST(EDITOR_CFLAGS)
+        AC_SUBST(EDITOR_LIBS)
+
+        ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
+        AC_SUBST(ORBIT_IDL)
 
-ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`"
-AC_SUBST(ORBIT_IDL)
+        BONOBO_IDL_INCLUDES="-I`$PKG_CONFIG --variable=idldir libbonobo-2.0` -I`$PKG_CONFIG --variable=idldir bonobo-activation-2.0`"
+        AC_SUBST(BONOBO_IDL_INCLUDES)
+fi
+AM_CONDITIONAL(BONOBO_EDITOR, test x$bonobo_editor = xyes)
 
-BONOBO_IDL_INCLUDES="-I`$PKG_CONFIG --variable=idldir libbonobo-2.0` -I`$PKG_CONFIG --variable=idldir bonobo-activation-2.0`"
-AC_SUBST(BONOBO_IDL_INCLUDES)
+if test "$USE_MAINTAINER_MODE" = "yes"; then
+GLADEUI_MODULES="gladeui-1.0 >= 3.0.0"
+PKG_CHECK_MODULES(GLADEUI, $GLADEUI_MODULES)
+fi
 
 dnl **********************************
 dnl soup for testgtkhtml
@@ -114,6 +130,43 @@ dnl ************************************
 PKG_CHECK_MODULES(GIT, gnome-icon-theme >= gnome_icon_theme_minimum_version)
 
 dnl **************************************************
+dnl * iso-codes
+dnl **************************************************
+
+AC_MSG_CHECKING([for iso-codes package])
+have_iso_codes=no
+if $PKG_CONFIG --exists iso-codes; then
+	if $PKG_CONFIG iso-codes --atleast-version=0.49; then
+		have_iso_codes=yes
+		AC_MSG_RESULT([$have_iso_codes])
+	else
+		AC_MSG_WARN([iso-codes detected, but version 0.49 or later is required due to licensing])
+	fi
+else
+	AC_MSG_RESULT([$have_iso_codes])
+fi
+
+if test "x$have_iso_codes" = "xyes"; then
+	AC_MSG_CHECKING([whether iso-codes has iso-639 and iso-3166 domains])
+	if $PKG_CONFIG --variable=domains iso-codes | grep -q 639 && \
+		$PKG_CONFIG --variable=domains iso-codes | grep -q 3166 ; then
+			result=yes
+	else
+		result=no
+		have_iso_codes=no
+	fi
+	AC_MSG_RESULT([$result])
+fi
+
+if test "x$have_iso_codes" = "xyes"; then
+	AC_DEFINE_UNQUOTED([ISO_CODES_PREFIX],
+		["`$PKG_CONFIG --variable=prefix iso-codes`"],
+		[ISO codes prefix])
+	AC_DEFINE([HAVE_ISO_CODES], [1],
+		[Define if you have the iso-codes package])
+fi
+
+dnl **************************************************
 dnl * regex library
 dnl **************************************************
 AC_CHECK_FUNCS(regexec,,[AC_CHECK_LIB(regex,regexec,[REGEX_LIBS=-lregex],[AC_MSG_ERROR([No regex library found])])])
@@ -171,6 +224,8 @@ gtkhtml/libgtkhtml.pc
 a11y/Makefile
 components/Makefile
 components/html-editor/Makefile
+components/editor/Makefile
+components/editor/gtkhtml-editor.pc
 art/Makefile
 ])
 
Index: gtkhtml/htmlrule.h
===================================================================
--- gtkhtml/htmlrule.h	(revision 8785)
+++ gtkhtml/htmlrule.h	(working copy)
@@ -26,6 +26,7 @@
 
 #define HTML_RULE(x) ((HTMLRule *) (x))
 #define HTML_RULE_CLASS(x) ((HTMLRuleClass *) (x))
+#define HTML_IS_RULE(x) (HTML_CHECK_TYPE ((x), HTML_TYPE_RULE))
 
 struct _HTMLRule {
 	HTMLObject object;
Index: README.spell
===================================================================
--- README.spell	(revision 8785)
+++ README.spell	(working copy)
@@ -1,2 +0,0 @@
-To enable spell checking support you need to have gnome-spell component
-installed on your system.
