[evolution/express] Reorganize mailer widgets.



commit d229dd997dea4dd3d8d0fe1a4fa049f3793c90b2
Author: Matthew Barnes <mbarnes redhat com>
Date:   Fri Mar 12 21:54:28 2010 -0500

    Reorganize mailer widgets.
    
    This introduces some new mailer widgets:
    
    EMailFolderPane (inherits from GtkVBox)
    
        Packs a MessageList into a GtkScrolledWindow and defines properties
        for grouping messages by threads and hiding deleted messages.
    
        Use e_mail_folder_pane_set_folder() to load a CamelFolder.
    
    EMailMessagePane (inherits from EPreviewPane)
    
        Packs an EMailDisplay and ESearchBar.  The EMFormatHTMLDisplay
        (message formatter) can be extracted from the EMailDisplay widget.
    
        Use e_mail_message_pane_set_folder() followed by
        e_mail_message_pane_set_message() to load a CamelMimeMessage.
    
    EMailPaned (inherits from EPaned)
    
        Packs an EMailFolderPane in the upper pane and an EMailMessagePane
        in the lower pane and defines properties for automatically marking
        a displayed message as read.
    
        This now handles much of the folder/message display coordination
        that EMailReader was handling previously.
    
        Also, EMailBrowser -- the message browsing window -- is now built
        around an EMailPaned widget with the folder pane hidden.

 mail/Makefile.am                         |    6 +
 mail/e-mail-browser.c                    |  165 +++++---
 mail/e-mail-folder-pane.c                |  435 +++++++++++++++++++
 mail/e-mail-folder-pane.h                |   85 ++++
 mail/e-mail-message-pane.c               |  400 ++++++++++++++++++
 mail/e-mail-message-pane.h               |   76 ++++
 mail/e-mail-paned.c                      |  681 ++++++++++++++++++++++++++++++
 mail/e-mail-paned.h                      |   85 ++++
 mail/e-mail-reader.c                     |  383 -----------------
 mail/e-mail-reader.h                     |    1 -
 mail/message-list.c                      |    8 -
 modules/mail/e-mail-shell-content.c      |  124 +++---
 modules/mail/e-mail-shell-content.h      |    2 +-
 modules/mail/e-mail-shell-view-private.c |   14 +-
 widgets/misc/e-preview-pane.c            |    2 +-
 15 files changed, 1937 insertions(+), 530 deletions(-)
---
diff --git a/mail/Makefile.am b/mail/Makefile.am
index c802528..2d59187 100644
--- a/mail/Makefile.am
+++ b/mail/Makefile.am
@@ -39,13 +39,16 @@ mailinclude_HEADERS =					\
 	e-mail-backend.h				\
 	e-mail-browser.h				\
 	e-mail-display.h				\
+	e-mail-folder-pane.h				\
 	e-mail-label-action.h				\
 	e-mail-label-dialog.h				\
 	e-mail-label-list-store.h			\
 	e-mail-label-manager.h				\
 	e-mail-label-tree-view.h			\
 	e-mail-local.h					\
+	e-mail-message-pane.h				\
 	e-mail-migrate.h				\
+	e-mail-paned.h					\
 	e-mail-reader.h					\
 	e-mail-reader-utils.h				\
 	e-mail-sidebar.h				\
@@ -96,13 +99,16 @@ libevolution_mail_la_SOURCES =				\
 	e-mail-backend.c				\
 	e-mail-browser.c				\
 	e-mail-display.c				\
+	e-mail-folder-pane.c				\
 	e-mail-label-action.c				\
 	e-mail-label-dialog.c				\
 	e-mail-label-list-store.c			\
 	e-mail-label-manager.c				\
 	e-mail-label-tree-view.c			\
 	e-mail-local.c					\
+	e-mail-message-pane.c				\
 	e-mail-migrate.c				\
+	e-mail-paned.c					\
 	e-mail-reader.c					\
 	e-mail-reader-utils.c				\
 	e-mail-sidebar.c				\
diff --git a/mail/e-mail-browser.c b/mail/e-mail-browser.c
index 96f168f..425aeb8 100644
--- a/mail/e-mail-browser.c
+++ b/mail/e-mail-browser.c
@@ -26,6 +26,7 @@
 #include <camel/camel-folder.h>
 
 #include "e-util/e-util.h"
+#include "e-util/e-binding.h"
 #include "e-util/e-plugin-ui.h"
 #include "e-util/gconf-bridge.h"
 #include "shell/e-shell.h"
@@ -33,6 +34,7 @@
 #include "widgets/misc/e-popup-action.h"
 #include "widgets/misc/e-preview-pane.h"
 
+#include "mail/e-mail-paned.h"
 #include "mail/e-mail-reader.h"
 #include "mail/e-mail-reader-utils.h"
 #include "mail/em-folder-tree-model.h"
@@ -50,12 +52,10 @@ struct _EMailBrowserPrivate {
 	EFocusTracker *focus_tracker;
 	EShellBackend *shell_backend;
 	GtkActionGroup *action_group;
-	EMFormatHTMLDisplay *html_display;
 
 	GtkWidget *main_menu;
 	GtkWidget *main_toolbar;
-	GtkWidget *message_list;
-	GtkWidget *search_bar;
+	GtkWidget *paned;
 	GtkWidget *statusbar;
 
 	guint show_deleted : 1;
@@ -405,11 +405,6 @@ mail_browser_dispose (GObject *object)
 		priv->action_group = NULL;
 	}
 
-	if (priv->html_display != NULL) {
-		g_object_unref (priv->html_display);
-		priv->html_display = NULL;
-	}
-
 	if (priv->main_menu != NULL) {
 		g_object_unref (priv->main_menu);
 		priv->main_menu = NULL;
@@ -420,14 +415,9 @@ mail_browser_dispose (GObject *object)
 		priv->main_toolbar = NULL;
 	}
 
-	if (priv->message_list != NULL) {
-		g_object_unref (priv->message_list);
-		priv->message_list = NULL;
-	}
-
-	if (priv->search_bar != NULL) {
-		g_object_unref (priv->search_bar);
-		priv->search_bar = NULL;
+	if (priv->paned != NULL) {
+		g_object_unref (priv->paned);
+		priv->paned = NULL;
 	}
 
 	if (priv->statusbar != NULL) {
@@ -442,21 +432,23 @@ mail_browser_dispose (GObject *object)
 static void
 mail_browser_constructed (GObject *object)
 {
-	EMFormatHTMLDisplay *html_display;
 	EMailBrowserPrivate *priv;
 	EMailReader *reader;
 	EShellBackend *shell_backend;
 	EShell *shell;
+	EMailPaned *paned;
+	EMailDisplay *display;
+	EMailFolderPane *folder_pane;
+	EMailMessagePane *message_pane;
 	EFocusTracker *focus_tracker;
-	ESearchBar *search_bar;
 	GConfBridge *bridge;
 	GtkAccelGroup *accel_group;
 	GtkActionGroup *action_group;
 	GtkAction *action;
 	GtkUIManager *ui_manager;
+	GtkWidget *message_list;
 	GtkWidget *container;
 	GtkWidget *widget;
-	EWebView *web_view;
 	const gchar *domain;
 	const gchar *key;
 	const gchar *id;
@@ -468,33 +460,12 @@ mail_browser_constructed (GObject *object)
 	ui_manager = priv->ui_manager;
 	domain = GETTEXT_PACKAGE;
 
-	html_display = e_mail_reader_get_html_display (reader);
 	shell_backend = e_mail_reader_get_shell_backend (reader);
 
 	shell = e_shell_backend_get_shell (shell_backend);
 	e_shell_watch_window (shell, GTK_WINDOW (object));
 
-	web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html);
-
-	/* The message list is a widget, but it is not shown in the browser.
-	 * Unfortunately, the widget is inseparable from its model, and the
-	 * model is all we need. */
-	priv->message_list = message_list_new (shell_backend);
-	g_object_ref_sink (priv->message_list);
-
-	g_signal_connect_swapped (
-		priv->message_list, "message-selected",
-		G_CALLBACK (mail_browser_message_selected_cb), object);
-
-	g_signal_connect_swapped (
-		web_view, "popup-event",
-		G_CALLBACK (mail_browser_popup_event_cb), object);
-
-	g_signal_connect_swapped (
-		web_view, "status-message",
-		G_CALLBACK (mail_browser_status_message_cb), object);
-
-	e_mail_reader_init (reader);
+	e_shell_configure_ui_manager (shell, E_UI_MANAGER (ui_manager));
 
 	action_group = priv->action_group;
 	gtk_action_group_set_translation_domain (action_group, domain);
@@ -511,9 +482,6 @@ mail_browser_constructed (GObject *object)
 	e_ui_manager_add_ui_from_string (
 		E_UI_MANAGER (ui_manager), ui, NULL);
 
-	merge_id = gtk_ui_manager_new_merge_id (GTK_UI_MANAGER (ui_manager));
-	e_mail_reader_create_charset_menu (reader, ui_manager, merge_id);
-
 	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
 	gtk_window_add_accel_group (GTK_WINDOW (object), accel_group);
 
@@ -521,6 +489,15 @@ mail_browser_constructed (GObject *object)
 		ui_manager, "connect-proxy",
 		G_CALLBACK (mail_browser_connect_proxy_cb), object);
 
+	/* Initialize the EMailReader interface.  We have to create the
+	 * EMailPaned widget early because e_mail_reader_init() needs its
+	 * EMFormatHTMLDisplay. */
+
+	priv->paned = e_mail_paned_new (shell_backend);
+	g_object_ref_sink (priv->paned);
+
+	e_mail_reader_init (reader);
+
 	/* Configure an EFocusTracker to manage selection actions. */
 
 	focus_tracker = e_focus_tracker_new (GTK_WINDOW (object));
@@ -558,18 +535,45 @@ mail_browser_constructed (GObject *object)
 	priv->main_toolbar = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	gtk_widget_show (GTK_WIDGET (web_view));
-
-	widget = e_preview_pane_new (web_view);
+	widget = priv->paned;
 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
 	gtk_widget_show (widget);
 
-	search_bar = e_preview_pane_get_search_bar (E_PREVIEW_PANE (widget));
-	priv->search_bar = g_object_ref (search_bar);
+	/* Do this after the statusbar is created. */
+	merge_id = gtk_ui_manager_new_merge_id (GTK_UI_MANAGER (ui_manager));
+	e_mail_reader_create_charset_menu (reader, ui_manager, merge_id);
+
+	/* Configure internal widgets. */
+
+	paned = E_MAIL_PANED (priv->paned);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+	display = e_mail_message_pane_get_display (message_pane);
+
+	/* We only show the message pane. */
+	gtk_widget_hide (GTK_WIDGET (folder_pane));
 
 	g_signal_connect_swapped (
-		search_bar, "changed",
-		G_CALLBACK (em_format_redraw), priv->html_display);
+		priv->paned, "mark-as-read",
+		G_CALLBACK (e_mail_reader_mark_as_read), object);
+
+	g_signal_connect_swapped (
+		message_list, "message-selected",
+		G_CALLBACK (mail_browser_message_selected_cb), object);
+
+	g_signal_connect_swapped (
+		display, "popup-event",
+		G_CALLBACK (mail_browser_popup_event_cb), object);
+
+	g_signal_connect_swapped (
+		display, "status-message",
+		G_CALLBACK (mail_browser_status_message_cb), object);
+
+	e_mutual_binding_new_with_negation (
+		reader, "show-deleted",
+		folder_pane, "hide-deleted");
 
 	/* Bind GObject properties to GConf keys. */
 
@@ -622,20 +626,34 @@ static EMFormatHTMLDisplay *
 mail_browser_get_html_display (EMailReader *reader)
 {
 	EMailBrowserPrivate *priv;
+	EMailMessagePane *message_pane;
+	EMFormatHTML *formatter;
+	EMailDisplay *display;
+	EMailPaned *paned;
 
 	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 
-	return priv->html_display;
+	paned = E_MAIL_PANED (priv->paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+	display = e_mail_message_pane_get_display (message_pane);
+	formatter = e_mail_display_get_formatter (display);
+
+	return EM_FORMAT_HTML_DISPLAY (formatter);
 }
 
 static GtkWidget *
 mail_browser_get_message_list (EMailReader *reader)
 {
 	EMailBrowserPrivate *priv;
+	EMailFolderPane *folder_pane;
+	EMailPaned *paned;
 
 	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 
-	return priv->message_list;
+	paned = E_MAIL_PANED (priv->paned);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+
+	return e_mail_folder_pane_get_message_list (folder_pane);
 }
 
 static GtkMenu *
@@ -669,6 +687,28 @@ mail_browser_get_window (EMailReader *reader)
 }
 
 static void
+mail_browser_set_folder (EMailReader *reader,
+                         CamelFolder *folder,
+                         const gchar *folder_uri)
+{
+	EMailBrowserPrivate *priv;
+	EMailFolderPane *folder_pane;
+	EMailReaderIface *iface;
+	EMailPaned *paned;
+
+	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
+
+	/* Chain up to parent's set_folder() method. */
+	iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
+	iface->set_folder (reader, folder, folder_uri);
+
+	paned = E_MAIL_PANED (priv->paned);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+
+	e_mail_folder_pane_set_folder (folder_pane, folder, folder_uri);
+}
+
+static void
 mail_browser_set_message (EMailReader *reader,
                           const gchar *uid)
 {
@@ -700,10 +740,15 @@ static void
 mail_browser_show_search_bar (EMailReader *reader)
 {
 	EMailBrowserPrivate *priv;
+	EMailMessagePane *message_pane;
+	EMailPaned *paned;
 
 	priv = E_MAIL_BROWSER_GET_PRIVATE (reader);
 
-	gtk_widget_show (priv->search_bar);
+	paned = E_MAIL_PANED (priv->paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	e_preview_pane_show_search_bar (E_PREVIEW_PANE (message_pane));
 }
 
 static void
@@ -766,6 +811,7 @@ mail_browser_iface_init (EMailReaderIface *iface)
 	iface->get_popup_menu = mail_browser_get_popup_menu;
 	iface->get_shell_backend = mail_browser_get_shell_backend;
 	iface->get_window = mail_browser_get_window;
+	iface->set_folder = mail_browser_set_folder;
 	iface->set_message = mail_browser_set_message;
 	iface->show_search_bar = mail_browser_show_search_bar;
 }
@@ -773,9 +819,6 @@ mail_browser_iface_init (EMailReaderIface *iface)
 static void
 mail_browser_init (EMailBrowser *browser)
 {
-	EShell *shell;
-	EShellBackend *shell_backend;
-	GtkUIManager *ui_manager;
 	EMailReader *reader;
 	GConfBridge *bridge;
 	const gchar *prefix;
@@ -783,15 +826,9 @@ mail_browser_init (EMailBrowser *browser)
 	browser->priv = E_MAIL_BROWSER_GET_PRIVATE (browser);
 
 	reader = E_MAIL_READER (browser);
-	shell_backend = e_mail_reader_get_shell_backend (reader);
-	shell = e_shell_backend_get_shell (shell_backend);
-
-	ui_manager = e_ui_manager_new ();
-	e_shell_configure_ui_manager (shell, E_UI_MANAGER (ui_manager));
 
-	browser->priv->ui_manager = ui_manager;
+	browser->priv->ui_manager = e_ui_manager_new ();
 	browser->priv->action_group = gtk_action_group_new ("mail-browser");
-	browser->priv->html_display = em_format_html_display_new ();
 
 	bridge = gconf_bridge_get ();
 	prefix = "/apps/evolution/mail/mail_browser";
diff --git a/mail/e-mail-folder-pane.c b/mail/e-mail-folder-pane.c
new file mode 100644
index 0000000..a8bdf5e
--- /dev/null
+++ b/mail/e-mail-folder-pane.c
@@ -0,0 +1,435 @@
+/*
+ * e-mail-folder-pane.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-folder-pane.h"
+
+#include "e-util/e-util.h"
+
+#include "mail/em-utils.h"
+#include "mail/message-list.h"
+#include "mail/mail-ops.h"
+
+#define E_MAIL_FOLDER_PANE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_FOLDER_PANE, EMailFolderPanePrivate))
+
+struct _EMailFolderPanePrivate {
+	EShellBackend *shell_backend;
+
+	GtkWidget *message_list;  /* not referenced */
+
+	guint group_by_threads : 1;
+	guint hide_deleted     : 1;
+};
+
+enum {
+	PROP_0,
+	PROP_FOLDER,
+	PROP_FOLDER_URI,
+	PROP_GROUP_BY_THREADS,
+	PROP_HIDE_DELETED,
+	PROP_MESSAGE_LIST,
+	PROP_SHELL_BACKEND
+};
+
+static gpointer parent_class;
+
+static void
+mail_folder_pane_set_shell_backend (EMailFolderPane *folder_pane,
+                                    EShellBackend *shell_backend)
+{
+	g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
+	g_return_if_fail (folder_pane->priv->shell_backend == NULL);
+
+	folder_pane->priv->shell_backend = g_object_ref (shell_backend);
+}
+
+static void
+mail_folder_pane_set_property (GObject *object,
+                               guint property_id,
+                               const GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_GROUP_BY_THREADS:
+			e_mail_folder_pane_set_group_by_threads (
+				E_MAIL_FOLDER_PANE (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_HIDE_DELETED:
+			e_mail_folder_pane_set_hide_deleted (
+				E_MAIL_FOLDER_PANE (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SHELL_BACKEND:
+			mail_folder_pane_set_shell_backend (
+				E_MAIL_FOLDER_PANE (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_folder_pane_get_property (GObject *object,
+                               guint property_id,
+                               GValue *value,
+                               GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_FOLDER:
+			g_value_set_boxed (
+				value,
+				e_mail_folder_pane_get_folder (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+
+		case PROP_FOLDER_URI:
+			g_value_set_string (
+				value,
+				e_mail_folder_pane_get_folder_uri (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+
+		case PROP_GROUP_BY_THREADS:
+			g_value_set_boolean (
+				value,
+				e_mail_folder_pane_get_group_by_threads (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+
+		case PROP_HIDE_DELETED:
+			g_value_set_boolean (
+				value,
+				e_mail_folder_pane_get_hide_deleted (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+
+		case PROP_MESSAGE_LIST:
+			g_value_set_object (
+				value,
+				e_mail_folder_pane_get_message_list (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+
+		case PROP_SHELL_BACKEND:
+			g_value_set_object (
+				value,
+				e_mail_folder_pane_get_shell_backend (
+				E_MAIL_FOLDER_PANE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_folder_pane_dispose (GObject *object)
+{
+	EMailFolderPanePrivate *priv;
+
+	priv = E_MAIL_FOLDER_PANE_GET_PRIVATE (object);
+
+	if (priv->shell_backend != NULL) {
+		g_object_unref (priv->shell_backend);
+		priv->shell_backend = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_folder_pane_constructed (GObject *object)
+{
+	EMailFolderPanePrivate *priv;
+	GtkWidget *container;
+	GtkWidget *widget;
+
+	priv = E_MAIL_FOLDER_PANE_GET_PRIVATE (object);
+
+	container = GTK_WIDGET (object);
+
+	widget = gtk_scrolled_window_new (NULL, NULL);
+	gtk_scrolled_window_set_policy (
+		GTK_SCROLLED_WINDOW (widget),
+		GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
+	gtk_scrolled_window_set_shadow_type (
+		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
+	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
+	gtk_widget_show (widget);
+
+	container = widget;
+
+	widget = message_list_new (priv->shell_backend);
+	gtk_container_add (GTK_CONTAINER (container), widget);
+	priv->message_list = widget;
+	gtk_widget_show (widget);
+}
+
+static void
+mail_folder_pane_class_init (EMailFolderPaneClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMailFolderPanePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = mail_folder_pane_set_property;
+	object_class->get_property = mail_folder_pane_get_property;
+	object_class->dispose = mail_folder_pane_dispose;
+	object_class->constructed = mail_folder_pane_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FOLDER,
+		g_param_spec_boxed (
+			"folder",
+			NULL,
+			NULL,
+			E_TYPE_CAMEL_OBJECT,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FOLDER_URI,
+		g_param_spec_string (
+			"folder-uri",
+			NULL,
+			NULL,
+			NULL,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_GROUP_BY_THREADS,
+		g_param_spec_boolean (
+			"group-by-threads",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_HIDE_DELETED,
+		g_param_spec_boolean (
+			"hide-deleted",
+			NULL,
+			NULL,
+			TRUE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MESSAGE_LIST,
+		g_param_spec_object (
+			"message-list",
+			NULL,
+			NULL,
+			GTK_TYPE_WIDGET,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_BACKEND,
+		g_param_spec_object (
+			"shell-backend",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_BACKEND,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+mail_folder_pane_init (EMailFolderPane *folder_pane)
+{
+	folder_pane->priv = E_MAIL_FOLDER_PANE_GET_PRIVATE (folder_pane);
+}
+
+GType
+e_mail_folder_pane_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailFolderPaneClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) mail_folder_pane_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailFolderPane),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) mail_folder_pane_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			GTK_TYPE_VBOX, "EMailFolderPane", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_mail_folder_pane_new (EShellBackend *shell_backend)
+{
+	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
+
+	return g_object_new (
+		E_TYPE_MAIL_FOLDER_PANE,
+		"shell-backend", shell_backend, NULL);
+}
+
+CamelFolder *
+e_mail_folder_pane_get_folder (EMailFolderPane *folder_pane)
+{
+	GtkWidget *message_list;
+
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), NULL);
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+
+	return MESSAGE_LIST (message_list)->folder;
+}
+
+const gchar *
+e_mail_folder_pane_get_folder_uri (EMailFolderPane *folder_pane)
+{
+	GtkWidget *message_list;
+
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), NULL);
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+
+	return MESSAGE_LIST (message_list)->folder_uri;
+}
+
+void
+e_mail_folder_pane_set_folder (EMailFolderPane *folder_pane,
+                               CamelFolder *folder,
+                               const gchar *folder_uri)
+{
+	GtkWidget *message_list;
+	CamelFolder *previous_folder;
+	const gchar *previous_folder_uri;
+	gboolean outgoing;
+
+	g_return_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane));
+	g_return_if_fail (folder == NULL || CAMEL_IS_FOLDER (folder));
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+
+	previous_folder = e_mail_folder_pane_get_folder (folder_pane);
+	previous_folder_uri = e_mail_folder_pane_get_folder_uri (folder_pane);
+
+	if (previous_folder != NULL)
+		mail_sync_folder (previous_folder, NULL, NULL);
+
+	/* Skip the rest if we're already viewing the folder. */
+	if (g_strcmp0 (folder_uri, previous_folder_uri) == 0)
+		return;
+
+	outgoing = folder != NULL && folder_uri != NULL && (
+		em_utils_folder_is_drafts (folder, folder_uri) ||
+		em_utils_folder_is_outbox (folder, folder_uri) ||
+		em_utils_folder_is_sent (folder, folder_uri));
+
+	message_list_set_folder (
+		MESSAGE_LIST (message_list), folder, folder_uri, outgoing);
+
+	g_object_freeze_notify (G_OBJECT (folder_pane));
+	g_object_notify (G_OBJECT (folder_pane), "folder");
+	g_object_notify (G_OBJECT (folder_pane), "folder-uri");
+	g_object_thaw_notify (G_OBJECT (folder_pane));
+}
+
+gboolean
+e_mail_folder_pane_get_group_by_threads (EMailFolderPane *folder_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), FALSE);
+
+	return folder_pane->priv->group_by_threads;
+}
+
+void
+e_mail_folder_pane_set_group_by_threads (EMailFolderPane *folder_pane,
+                                         gboolean group_by_threads)
+{
+	GtkWidget *message_list;
+
+	g_return_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane));
+
+	folder_pane->priv->group_by_threads = group_by_threads;
+
+	/* XXX MessageList should define a property for this. */
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+	message_list_set_threaded (
+		MESSAGE_LIST (message_list), group_by_threads);
+
+	g_object_notify (G_OBJECT (folder_pane), "group-by-threads");
+}
+
+gboolean
+e_mail_folder_pane_get_hide_deleted (EMailFolderPane *folder_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), FALSE);
+
+	return folder_pane->priv->hide_deleted;
+}
+
+void
+e_mail_folder_pane_set_hide_deleted (EMailFolderPane *folder_pane,
+                                     gboolean hide_deleted)
+{
+	GtkWidget *message_list;
+
+	g_return_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane));
+
+	folder_pane->priv->hide_deleted = hide_deleted;
+
+	/* XXX MessageList should define a property for this. */
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+	message_list_set_hidedeleted (
+		MESSAGE_LIST (message_list), hide_deleted);
+
+	g_object_notify (G_OBJECT (folder_pane), "hide-deleted");
+}
+
+GtkWidget *
+e_mail_folder_pane_get_message_list (EMailFolderPane *folder_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), NULL);
+
+	return folder_pane->priv->message_list;
+}
+
+EShellBackend *
+e_mail_folder_pane_get_shell_backend (EMailFolderPane *folder_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_FOLDER_PANE (folder_pane), NULL);
+
+	return folder_pane->priv->shell_backend;
+}
diff --git a/mail/e-mail-folder-pane.h b/mail/e-mail-folder-pane.h
new file mode 100644
index 0000000..cd53207
--- /dev/null
+++ b/mail/e-mail-folder-pane.h
@@ -0,0 +1,85 @@
+/*
+ * e-mail-folder-pane.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_FOLDER_PANE_H
+#define E_MAIL_FOLDER_PANE_H
+
+#include <gtk/gtk.h>
+#include <camel/camel.h>
+#include <shell/e-shell-backend.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_FOLDER_PANE \
+	(e_mail_folder_pane_get_type ())
+#define E_MAIL_FOLDER_PANE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_FOLDER_PANE, EMailFolderPane))
+#define E_MAIL_FOLDER_PANE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_FOLDER_PANE, EMailFolderPaneClass))
+#define E_IS_MAIL_FOLDER_PANE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_FOLDER_PANE))
+#define E_IS_MAIL_FOLDER_PANE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_FOLDER_PANE))
+#define E_MAIL_FOLDER_PANE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_FOLDER_PANE, EMailFolderPaneClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailFolderPane EMailFolderPane;
+typedef struct _EMailFolderPaneClass EMailFolderPaneClass;
+typedef struct _EMailFolderPanePrivate EMailFolderPanePrivate;
+
+struct _EMailFolderPane {
+	GtkVBox parent;
+	EMailFolderPanePrivate *priv;
+};
+
+struct _EMailFolderPaneClass {
+	GtkVBoxClass parent_class;
+};
+
+GType		e_mail_folder_pane_get_type	(void);
+GtkWidget *	e_mail_folder_pane_new		(EShellBackend *shell_backend);
+CamelFolder *	e_mail_folder_pane_get_folder	(EMailFolderPane *folder_pane);
+const gchar *	e_mail_folder_pane_get_folder_uri
+						(EMailFolderPane *folder_pane);
+void		e_mail_folder_pane_set_folder	(EMailFolderPane *folder_pane,
+						 CamelFolder *folder,
+						 const gchar *folder_uri);
+gboolean	e_mail_folder_pane_get_group_by_threads
+						(EMailFolderPane *folder_pane);
+void		e_mail_folder_pane_set_group_by_threads
+						(EMailFolderPane *folder_pane,
+						 gboolean group_by_threads);
+gboolean	e_mail_folder_pane_get_hide_deleted
+						(EMailFolderPane *folder_pane);
+void		e_mail_folder_pane_set_hide_deleted
+						(EMailFolderPane *folder_pane,
+						 gboolean hide_deleted);
+GtkWidget *	e_mail_folder_pane_get_message_list
+						(EMailFolderPane *folder_pane);
+EShellBackend *	e_mail_folder_pane_get_shell_backend
+						(EMailFolderPane *folder_pane);
+
+G_END_DECLS
+
+#endif /* E_MAIL_FOLDER_PANE_H */
diff --git a/mail/e-mail-message-pane.c b/mail/e-mail-message-pane.c
new file mode 100644
index 0000000..e9aaa1a
--- /dev/null
+++ b/mail/e-mail-message-pane.c
@@ -0,0 +1,400 @@
+/*
+ * e-mail-message-pane.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-message-pane.h"
+
+#include <e-util/e-util.h>
+
+#include <mail/em-event.h>
+
+#define E_MAIL_MESSAGE_PANE_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_MESSAGE_PANE, EMailMessagePanePrivate))
+
+struct _EMailMessagePanePrivate {
+	CamelFolder *folder;
+	CamelMimeMessage *message;
+	gchar *message_uid;
+};
+
+enum {
+	PROP_0,
+	PROP_FOLDER,
+	PROP_MESSAGE,
+	PROP_MESSAGE_UID
+};
+
+static gpointer parent_class;
+
+static void
+mail_message_pane_format_message (EMailMessagePane *message_pane)
+{
+	EMailDisplay *display;
+	EMFormatHTML *formatter;
+	CamelFolder *folder;
+	CamelMimeMessage *message;
+	const gchar *message_uid;
+
+	folder = e_mail_message_pane_get_folder (message_pane);
+	message = e_mail_message_pane_get_message (message_pane);
+	message_uid = e_mail_message_pane_get_message_uid (message_pane);
+
+	display = e_mail_message_pane_get_display (message_pane);
+	formatter = e_mail_display_get_formatter (display);
+
+	if (folder != NULL && message != NULL && message_uid != NULL)
+		em_format_format (
+			EM_FORMAT (formatter), folder,
+			message_uid, message);
+	else
+		em_format_format (
+			EM_FORMAT (formatter), NULL, NULL, NULL);
+}
+
+static void
+mail_message_pane_reading_event (EMailMessagePane *message_pane)
+{
+	EMEvent *event;
+	EMEventTargetMessage *target;
+	CamelFolder *folder;
+	CamelMimeMessage *message;
+	const gchar *message_uid;
+
+	folder = e_mail_message_pane_get_folder (message_pane);
+	message = e_mail_message_pane_get_message (message_pane);
+	message_uid = e_mail_message_pane_get_message_uid (message_pane);
+
+	if (message == NULL)
+		return;
+
+	/* @Event: message.reading
+	 * @Title: Viewing a message
+	 * @Target: EMEventTargetMessage
+	 *
+	 * message.reading is emitted whenever a user views a message.
+	 */
+	event = em_event_peek ();
+	target = em_event_target_new_message (
+		event, folder, message, message_uid, 0, NULL);
+	e_event_emit (
+		(EEvent *) event, "message.reading",
+		(EEventTarget *) target);
+}
+
+static void
+mail_message_pane_set_property (GObject *object,
+                                guint property_id,
+                                const GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_FOLDER:
+			e_mail_message_pane_set_folder (
+				E_MAIL_MESSAGE_PANE (object),
+				g_value_get_boxed (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_message_pane_get_property (GObject *object,
+                                guint property_id,
+                                GValue *value,
+                                GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_FOLDER:
+			g_value_set_boxed (
+				value,
+				e_mail_message_pane_get_folder (
+				E_MAIL_MESSAGE_PANE (object)));
+			return;
+
+		case PROP_MESSAGE:
+			g_value_set_boxed (
+				value,
+				e_mail_message_pane_get_message (
+				E_MAIL_MESSAGE_PANE (object)));
+			return;
+
+		case PROP_MESSAGE_UID:
+			g_value_set_string (
+				value,
+				e_mail_message_pane_get_message_uid (
+				E_MAIL_MESSAGE_PANE (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_message_pane_dispose (GObject *object)
+{
+	EMailMessagePanePrivate *priv;
+
+	priv = E_MAIL_MESSAGE_PANE_GET_PRIVATE (object);
+
+	if (priv->folder != NULL) {
+		camel_object_unref (priv->folder);
+		priv->folder = NULL;
+	}
+
+	if (priv->message != NULL) {
+		camel_object_unref (priv->message);
+		priv->message = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_message_pane_finalize (GObject *object)
+{
+	EMailMessagePanePrivate *priv;
+
+	priv = E_MAIL_MESSAGE_PANE_GET_PRIVATE (object);
+
+	g_free (priv->message_uid);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_message_pane_constructed (GObject *object)
+{
+	EMailMessagePane *message_pane;
+	EPreviewPane *preview_pane;
+	EMFormatHTML *formatter;
+	ESearchBar *search_bar;
+	EMailDisplay *display;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (parent_class)->constructed (object);
+
+	preview_pane = E_PREVIEW_PANE (object);
+	search_bar = e_preview_pane_get_search_bar (preview_pane);
+
+	message_pane = E_MAIL_MESSAGE_PANE (object);
+	display = e_mail_message_pane_get_display (message_pane);
+	formatter = e_mail_display_get_formatter (display);
+
+	g_signal_connect_swapped (
+		search_bar, "changed",
+		G_CALLBACK (em_format_redraw), formatter);
+}
+
+static void
+mail_message_pane_class_init (EMailMessagePaneClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMailMessagePanePrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = mail_message_pane_set_property;
+	object_class->get_property = mail_message_pane_get_property;
+	object_class->dispose = mail_message_pane_dispose;
+	object_class->finalize = mail_message_pane_finalize;
+	object_class->constructed = mail_message_pane_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FOLDER,
+		g_param_spec_boxed (
+			"folder",
+			NULL,
+			NULL,
+			E_TYPE_CAMEL_OBJECT,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MESSAGE,
+		g_param_spec_boxed (
+			"message",
+			NULL,
+			NULL,
+			E_TYPE_CAMEL_OBJECT,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MESSAGE_UID,
+		g_param_spec_string (
+			"message-uid",
+			NULL,
+			NULL,
+			NULL,
+			G_PARAM_READABLE));
+}
+
+static void
+mail_message_pane_init (EMailMessagePane *message_pane)
+{
+	message_pane->priv = E_MAIL_MESSAGE_PANE_GET_PRIVATE (message_pane);
+
+	g_signal_connect (
+		message_pane, "notify::message",
+		G_CALLBACK (mail_message_pane_reading_event), NULL);
+
+	g_signal_connect (
+		message_pane, "notify::message",
+		G_CALLBACK (mail_message_pane_format_message), NULL);
+}
+
+GType
+e_mail_message_pane_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailMessagePaneClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) mail_message_pane_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailMessagePane),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) mail_message_pane_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_PREVIEW_PANE, "EMailMessagePane",
+			&type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_mail_message_pane_new (EMailDisplay *display)
+{
+	g_return_val_if_fail (E_IS_MAIL_DISPLAY (display), NULL);
+
+	return g_object_new (
+		E_TYPE_MAIL_MESSAGE_PANE, "web-view", display, NULL);
+}
+
+EMailDisplay *
+e_mail_message_pane_get_display (EMailMessagePane *message_pane)
+{
+	EPreviewPane *preview_pane;
+	EWebView *web_view;
+
+	/* This is purely a convenience function. */
+
+	g_return_val_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane), NULL);
+
+	preview_pane = E_PREVIEW_PANE (message_pane);
+	web_view = e_preview_pane_get_web_view (preview_pane);
+
+	return E_MAIL_DISPLAY (web_view);
+}
+
+CamelFolder *
+e_mail_message_pane_get_folder (EMailMessagePane *message_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane), NULL);
+
+	return message_pane->priv->folder;
+}
+
+void
+e_mail_message_pane_set_folder (EMailMessagePane *message_pane,
+                                CamelFolder *folder)
+{
+	g_return_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane));
+
+	if (folder != NULL) {
+		g_return_if_fail (CAMEL_IS_FOLDER (folder));
+		camel_object_ref (folder);
+	}
+
+	if (message_pane->priv->folder != NULL)
+		camel_object_unref (message_pane->priv->folder);
+
+	message_pane->priv->folder = folder;
+
+	/* Changing folders resets the message. */
+
+	if (message_pane->priv->message != NULL) {
+		camel_object_unref (message_pane->priv->message);
+		g_free (message_pane->priv->message_uid);
+	}
+
+	message_pane->priv->message = NULL;
+	message_pane->priv->message_uid = NULL;
+
+	g_object_freeze_notify (G_OBJECT (message_pane));
+	g_object_notify (G_OBJECT (message_pane), "folder");
+	g_object_notify (G_OBJECT (message_pane), "message");
+	g_object_notify (G_OBJECT (message_pane), "message-uid");
+	g_object_thaw_notify (G_OBJECT (message_pane));
+}
+
+CamelMimeMessage *
+e_mail_message_pane_get_message (EMailMessagePane *message_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane), NULL);
+
+	return message_pane->priv->message;
+}
+
+const gchar *
+e_mail_message_pane_get_message_uid (EMailMessagePane *message_pane)
+{
+	g_return_val_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane), NULL);
+
+	return message_pane->priv->message_uid;
+}
+
+void
+e_mail_message_pane_set_message (EMailMessagePane *message_pane,
+                                 CamelMimeMessage *message,
+                                 const gchar *message_uid)
+{
+	g_return_if_fail (E_IS_MAIL_MESSAGE_PANE (message_pane));
+
+	if (message != NULL) {
+		g_return_if_fail (CAMEL_IS_MIME_MESSAGE (message));
+		camel_object_ref (message);
+	} else
+		message_uid = NULL;
+
+	if (message_pane->priv->message != NULL) {
+		camel_object_unref (message_pane->priv->message);
+		g_free (message_pane->priv->message_uid);
+	}
+
+	message_pane->priv->message = message;
+	message_pane->priv->message_uid = g_strdup (message_uid);
+
+	g_object_freeze_notify (G_OBJECT (message_pane));
+	g_object_notify (G_OBJECT (message_pane), "message");
+	g_object_notify (G_OBJECT (message_pane), "message-uid");
+	g_object_thaw_notify (G_OBJECT (message_pane));
+}
diff --git a/mail/e-mail-message-pane.h b/mail/e-mail-message-pane.h
new file mode 100644
index 0000000..e7268e2
--- /dev/null
+++ b/mail/e-mail-message-pane.h
@@ -0,0 +1,76 @@
+/*
+ * e-mail-message-pane.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_MESSAGE_PANE_H
+#define E_MAIL_MESSAGE_PANE_H
+
+#include <camel/camel.h>
+#include <mail/e-mail-display.h>
+#include <misc/e-preview-pane.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_MESSAGE_PANE \
+	(e_mail_message_pane_get_type ())
+#define E_MAIL_MESSAGE_PANE(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_MESSAGE_PANE, EMailMessagePane))
+#define E_MAIL_MESSAGE_PANE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_MESSAGE_PANE, EMailMessagePaneClass))
+#define E_IS_MAIL_MESSAGE_PANE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_MESSAGE_PANE))
+#define E_IS_MAIL_MESSAGE_PANE_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_MESSAGE_PANE))
+#define E_MAIL_MESSAGE_PANE_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_MESSAGE_PANE, EMailMessagePaneClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailMessagePane EMailMessagePane;
+typedef struct _EMailMessagePaneClass EMailMessagePaneClass;
+typedef struct _EMailMessagePanePrivate EMailMessagePanePrivate;
+
+struct _EMailMessagePane {
+	EPreviewPane parent;
+	EMailMessagePanePrivate *priv;
+};
+
+struct _EMailMessagePaneClass {
+	EPreviewPaneClass parent_class;
+};
+
+GType		e_mail_message_pane_get_type	(void);
+GtkWidget *	e_mail_message_pane_new		(EMailDisplay *display);
+EMailDisplay *	e_mail_message_pane_get_display	(EMailMessagePane *message_pane);
+CamelFolder *	e_mail_message_pane_get_folder	(EMailMessagePane *message_pane);
+void		e_mail_message_pane_set_folder	(EMailMessagePane *message_pane,
+						 CamelFolder *folder);
+CamelMimeMessage *
+		e_mail_message_pane_get_message	(EMailMessagePane *message_pane);
+const gchar *	e_mail_message_pane_get_message_uid
+						(EMailMessagePane *message_pane);
+void		e_mail_message_pane_set_message	(EMailMessagePane *message_pane,
+						 CamelMimeMessage *message,
+						 const gchar *message_uid);
+
+G_END_DECLS
+
+#endif /* E_MAIL_MESSAGE_PANE_H */
diff --git a/mail/e-mail-paned.c b/mail/e-mail-paned.c
new file mode 100644
index 0000000..f0883e0
--- /dev/null
+++ b/mail/e-mail-paned.c
@@ -0,0 +1,681 @@
+/*
+ * e-mail-paned.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "e-mail-paned.h"
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+
+#include <e-util/e-binding.h>
+
+#include <mail/em-format-html-display.h>
+#include <mail/mail-mt.h>
+#include <mail/mail-ops.h>
+#include <mail/message-list.h>
+
+#define E_MAIL_PANED_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE \
+	((obj), E_TYPE_MAIL_PANED, EMailPanedPrivate))
+
+struct _EMailPanedPrivate {
+	EShellBackend *shell_backend;
+	EMFormatHTMLDisplay *formatter;
+
+	/* The user can elect to automatically mark a message as read
+	 * after a short delay when displaying the message's content. */
+	guint mark_as_read_delay;
+	gboolean mark_as_read_enabled;
+	gchar *mark_as_read_message_uid;
+
+	/* This timer runs when the user selects a single message. */
+	guint message_selected_timeout_id;
+
+	/* This is the ID of an asynchronous operation
+	 * to retrieve a message from a mail folder. */
+	gint retrieving_message_op_id;
+
+	/* These flags work together to prevent message selection
+	 * restoration after a folder switch from automatically
+	 * marking the message as read.  We only want that to
+	 * happen when the -user- selects a message. */
+	guint folder_was_just_selected    : 1;
+	guint restoring_message_selection : 1;
+};
+
+enum {
+	PROP_0,
+	PROP_FOLDER_PANE,
+	PROP_MARK_AS_READ_DELAY,
+	PROP_MARK_AS_READ_ENABLED,
+	PROP_MESSAGE_PANE,
+	PROP_SHELL_BACKEND
+};
+
+enum {
+	MARK_AS_READ,
+	LAST_SIGNAL
+};
+
+static gpointer parent_class;
+static guint signals[LAST_SIGNAL];
+
+static void
+mail_paned_load_string (EMailPaned *paned,
+                        const gchar *string)
+{
+	EMailMessagePane *message_pane;
+	EMailDisplay *display;
+	EMFormat *formatter;
+
+	formatter = EM_FORMAT (paned->priv->formatter);
+
+	if (em_format_busy (formatter))
+		return;
+
+	message_pane = e_mail_paned_get_message_pane (paned);
+	display = e_mail_message_pane_get_display (message_pane);
+
+	e_web_view_load_string (E_WEB_VIEW (display), string);
+}
+
+static void
+mail_paned_folder_changed_cb (EMailPaned *paned)
+{
+	EMailFolderPane *folder_pane;
+	CamelFolder *folder;
+
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+	folder = e_mail_folder_pane_get_folder (folder_pane);
+
+	paned->priv->folder_was_just_selected = (folder != NULL);
+}
+
+static gboolean
+mail_paned_message_read_cb (EMailPaned *paned)
+{
+	EMailFolderPane *folder_pane;
+	GtkWidget *message_list;
+	const gchar *cursor_uid;
+	const gchar *message_uid;
+
+	message_uid = paned->priv->mark_as_read_message_uid;
+	g_return_val_if_fail (message_uid != NULL, FALSE);
+
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
+
+	if (g_strcmp0 (cursor_uid, message_uid) == 0)
+		g_signal_emit (paned, signals[MARK_AS_READ], 0, message_uid);
+
+	return FALSE;
+}
+
+static void
+mail_paned_message_loaded_cb (CamelFolder *folder,
+                              const gchar *message_uid,
+                              CamelMimeMessage *message,
+                              gpointer user_data,
+                              CamelException *ex)
+{
+	EMailPaned *paned = user_data;
+	EMailFolderPane *folder_pane;
+	EMailMessagePane *message_pane;
+	GtkWidget *message_list;
+	EMFormat *formatter;
+	const gchar *cursor_uid;
+	gboolean schedule_timeout;
+	guint timeout_interval;
+
+	formatter = EM_FORMAT (paned->priv->formatter);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+
+	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
+
+	/* If the user picked a different message in the time it took
+	 * to fetch this message, then don't bother rendering it. */
+	if (g_strcmp0 (cursor_uid, message_uid) != 0)
+		goto exit;
+
+	e_mail_message_pane_set_message (message_pane, message, message_uid);
+
+	/* Determine whether to mark the message as read. */
+	schedule_timeout =
+		(message != NULL) &&
+		e_mail_paned_get_mark_as_read_enabled (paned) &&
+		!paned->priv->restoring_message_selection;
+	timeout_interval = e_mail_paned_get_mark_as_read_delay (paned);
+
+	g_free (paned->priv->mark_as_read_message_uid);
+	paned->priv->mark_as_read_message_uid = g_strdup (message_uid);
+
+	if (MESSAGE_LIST (message_list)->seen_id > 0) {
+		g_source_remove (MESSAGE_LIST (message_list)->seen_id);
+		MESSAGE_LIST (message_list)->seen_id = 0;
+	}
+
+	if (schedule_timeout)
+		MESSAGE_LIST (message_list)->seen_id = g_timeout_add (
+			timeout_interval, (GSourceFunc)
+			mail_paned_message_read_cb, paned);
+
+	else if (camel_exception_is_set (ex)) {
+		gchar *string;
+
+		if (ex->id != CAMEL_EXCEPTION_OPERATION_IN_PROGRESS)
+			string = g_strdup_printf (
+				"<h2>%s</h2><p>%s</p>",
+				_("Unable to retrieve message"),
+				ex->desc);
+		else
+			string = g_strdup_printf (
+				_("Retrieving message '%s'"), cursor_uid);
+
+		mail_paned_load_string (paned, string);
+		g_free (string);
+
+		camel_exception_clear (ex);
+	}
+
+	/* We referenced this in the call to mail_get_messagex(). */
+	g_object_unref (paned);
+
+exit:
+	paned->priv->restoring_message_selection = FALSE;
+}
+
+static gboolean
+mail_paned_message_selected_timeout_cb (EMailPaned *paned)
+{
+	EMailFolderPane *folder_pane;
+	EMailMessagePane *message_pane;
+	GtkWidget *message_list;
+	CamelFolder *folder;
+	EMFormat *formatter;
+	gboolean store_async;
+
+	formatter = EM_FORMAT (paned->priv->formatter);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	folder = e_mail_folder_pane_get_folder (folder_pane);
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+	store_async = folder->parent_store->flags & CAMEL_STORE_ASYNC;
+
+	if (MESSAGE_LIST (message_list)->last_sel_single) {
+		gboolean message_pane_visible;
+		gboolean selected_uid_changed;
+		const gchar *cursor_uid;
+		const gchar *format_uid;
+
+		/* Decide whether to download the full message now. */
+
+		cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
+		format_uid = formatter->uid;
+
+#if GTK_CHECK_VERSION(2,19,7)
+		message_pane_visible =
+			gtk_widget_get_visible (GTK_WIDGET (message_pane));
+#else
+		message_pane_visible = GTK_WIDGET_VISIBLE (message_pane);
+#endif
+		selected_uid_changed = g_strcmp0 (cursor_uid, format_uid);
+
+		if (message_pane_visible && selected_uid_changed) {
+			MailMsgDispatchFunc dispatch_func;
+			gchar *string;
+			gint op_id;
+
+			string = g_strdup_printf (
+				_("Retrieving message '%s'"), cursor_uid);
+			mail_paned_load_string (paned, string);
+			g_free (string);
+
+			if (store_async)
+				dispatch_func = mail_msg_unordered_push;
+			else
+				dispatch_func = mail_msg_fast_ordered_push;
+
+			op_id = mail_get_messagex (
+				folder, cursor_uid,
+				mail_paned_message_loaded_cb,
+				g_object_ref (paned),
+				dispatch_func);
+
+			if (!store_async)
+				paned->priv->retrieving_message_op_id = op_id;
+		}
+	} else {
+		e_mail_message_pane_set_message (message_pane, NULL, NULL);
+		paned->priv->restoring_message_selection = FALSE;
+	}
+
+	paned->priv->message_selected_timeout_id = 0;
+
+	return FALSE;
+}
+
+static void
+mail_paned_message_selected_cb (EMailPaned *paned,
+                                const gchar *uid,
+                                MessageList *message_list)
+{
+	EMailFolderPane *folder_pane;
+	CamelFolder *folder;
+	gboolean store_async;
+
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+
+	folder = e_mail_folder_pane_get_folder (folder_pane);
+	store_async = folder->parent_store->flags & CAMEL_STORE_ASYNC;
+
+	/* Cancel previous message retrieval if the store is not async. */
+	if (!store_async && paned->priv->retrieving_message_op_id > 0)
+		mail_msg_cancel (paned->priv->retrieving_message_op_id);
+
+	/* Cancel the seen timer. */
+	if (message_list->seen_id > 0) {
+		g_source_remove (message_list->seen_id);
+		message_list->seen_id = 0;
+	}
+
+	/* Cancel the message selected timer. */
+	if (paned->priv->message_selected_timeout_id > 0) {
+		g_source_remove (paned->priv->message_selected_timeout_id);
+		paned->priv->message_selected_timeout_id = 0;
+	}
+
+	/* If a folder was just selected then we are not automatically
+	 * restoring the previous message selection.  We behave slightly
+	 * differently than if the user had selected the message. */
+	paned->priv->restoring_message_selection =
+		paned->priv->folder_was_just_selected;
+	paned->priv->folder_was_just_selected = FALSE;
+
+	/* Skip the timeout if we're restoring the previous message
+	 * selection.  The timeout is there for when we're scrolling
+	 * rapidly through the message list. */
+	if (paned->priv->restoring_message_selection)
+		mail_paned_message_selected_timeout_cb (paned);
+	else
+		paned->priv->message_selected_timeout_id = g_timeout_add (
+			100, (GSourceFunc)
+			mail_paned_message_selected_timeout_cb, paned);
+}
+
+static void
+mail_paned_set_shell_backend (EMailPaned *paned,
+                              EShellBackend *shell_backend)
+{
+	g_return_if_fail (E_IS_SHELL_BACKEND (shell_backend));
+	g_return_if_fail (paned->priv->shell_backend == NULL);
+
+	paned->priv->shell_backend = g_object_ref (shell_backend);
+}
+
+static void
+mail_paned_set_property (GObject *object,
+                         guint property_id,
+                         const GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_MARK_AS_READ_DELAY:
+			e_mail_paned_set_mark_as_read_delay (
+				E_MAIL_PANED (object),
+				g_value_get_uint (value));
+			return;
+
+		case PROP_MARK_AS_READ_ENABLED:
+			e_mail_paned_set_mark_as_read_enabled (
+				E_MAIL_PANED (object),
+				g_value_get_boolean (value));
+			return;
+
+		case PROP_SHELL_BACKEND:
+			mail_paned_set_shell_backend (
+				E_MAIL_PANED (object),
+				g_value_get_object (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_paned_get_property (GObject *object,
+                         guint property_id,
+                         GValue *value,
+                         GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_FOLDER_PANE:
+			g_value_set_object (
+				value,
+				e_mail_paned_get_folder_pane (
+				E_MAIL_PANED (object)));
+			return;
+
+		case PROP_MARK_AS_READ_DELAY:
+			g_value_set_uint (
+				value,
+				e_mail_paned_get_mark_as_read_delay (
+				E_MAIL_PANED (object)));
+			return;
+
+		case PROP_MARK_AS_READ_ENABLED:
+			g_value_set_boolean (
+				value,
+				e_mail_paned_get_mark_as_read_enabled (
+				E_MAIL_PANED (object)));
+			return;
+
+		case PROP_MESSAGE_PANE:
+			g_value_set_object (
+				value,
+				e_mail_paned_get_message_pane (
+				E_MAIL_PANED (object)));
+			return;
+
+		case PROP_SHELL_BACKEND:
+			g_value_set_object (
+				value,
+				e_mail_paned_get_shell_backend (
+				E_MAIL_PANED (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+mail_paned_dispose (GObject *object)
+{
+	EMailPanedPrivate *priv;
+
+	priv = E_MAIL_PANED_GET_PRIVATE (object);
+
+	if (priv->shell_backend != NULL) {
+		g_object_unref (priv->shell_backend);
+		priv->shell_backend = NULL;
+	}
+
+	if (priv->formatter != NULL) {
+		g_object_unref (priv->formatter);
+		priv->formatter = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+mail_paned_finalize (GObject *object)
+{
+	EMailPanedPrivate *priv;
+
+	priv = E_MAIL_PANED_GET_PRIVATE (object);
+
+	if (priv->message_selected_timeout_id > 0)
+		g_source_remove (priv->message_selected_timeout_id);
+
+	g_free (priv->mark_as_read_message_uid);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+mail_paned_constructed (GObject *object)
+{
+	EMailPanedPrivate *priv;
+	EMailDisplay *display;
+	EMailFolderPane *folder_pane;
+	EMailMessagePane *message_pane;
+	GtkWidget *message_list;
+	GtkWidget *widget;
+
+	priv = E_MAIL_PANED_GET_PRIVATE (object);
+
+	display = E_MAIL_DISPLAY (EM_FORMAT_HTML (priv->formatter)->html);
+
+	widget = e_mail_folder_pane_new (priv->shell_backend);
+	gtk_paned_pack1 (GTK_PANED (object), widget, TRUE, FALSE);
+	folder_pane = E_MAIL_FOLDER_PANE (widget);
+	gtk_widget_show (widget);
+
+	widget = e_mail_message_pane_new (display);
+	gtk_paned_pack2 (GTK_PANED (object), widget, FALSE, FALSE);
+	message_pane = E_MAIL_MESSAGE_PANE (widget);
+	gtk_widget_show (widget);
+
+	message_list = e_mail_folder_pane_get_message_list (folder_pane);
+
+	/* Connect signals. */
+
+	g_signal_connect_swapped (
+		folder_pane, "notify::folder",
+		G_CALLBACK (mail_paned_folder_changed_cb), object);
+
+	g_signal_connect_swapped (
+		message_list, "message-selected",
+		G_CALLBACK (mail_paned_message_selected_cb), object);
+
+	e_binding_new (folder_pane, "folder", message_pane, "folder");
+}
+
+static void
+mail_paned_class_init (EMailPanedClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	g_type_class_add_private (class, sizeof (EMailPanedPrivate));
+
+	object_class = G_OBJECT_CLASS (class);
+	object_class->set_property = mail_paned_set_property;
+	object_class->get_property = mail_paned_get_property;
+	object_class->dispose = mail_paned_dispose;
+	object_class->finalize = mail_paned_finalize;
+	object_class->constructed = mail_paned_constructed;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_FOLDER_PANE,
+		g_param_spec_object (
+			"folder-pane",
+			NULL,
+			NULL,
+			E_TYPE_MAIL_FOLDER_PANE,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MARK_AS_READ_DELAY,
+		g_param_spec_uint (
+			"mark-as-read-delay",
+			NULL,
+			NULL,
+			0,
+			G_MAXUINT,
+			1500,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MARK_AS_READ_ENABLED,
+		g_param_spec_boolean (
+			"mark-as-read-enabled",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_MESSAGE_PANE,
+		g_param_spec_object (
+			"message-pane",
+			NULL,
+			NULL,
+			E_TYPE_MAIL_MESSAGE_PANE,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SHELL_BACKEND,
+		g_param_spec_object (
+			"shell-backend",
+			NULL,
+			NULL,
+			E_TYPE_SHELL_BACKEND,
+			G_PARAM_READWRITE |
+			G_PARAM_CONSTRUCT_ONLY));
+
+	signals[MARK_AS_READ] = g_signal_new (
+		"mark-as-read",
+		G_OBJECT_CLASS_TYPE (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EMailPanedClass, mark_as_read),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1,
+		G_TYPE_STRING);
+}
+
+static void
+mail_paned_init (EMailPaned *paned)
+{
+	paned->priv = E_MAIL_PANED_GET_PRIVATE (paned);
+
+	/* EMFormatHTMLDisplay is hard-wired to create its own
+	 * EMailDisplay instance, which we will share with the
+	 * EMailMessagePane widget.  Kind of confusing. */
+	paned->priv->formatter = em_format_html_display_new ();
+}
+
+GType
+e_mail_paned_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo type_info = {
+			sizeof (EMailPanedClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) mail_paned_class_init,
+			(GClassFinalizeFunc) NULL,
+			NULL,  /* class_data */
+			sizeof (EMailPaned),
+			0,     /* n_preallocs */
+			(GInstanceInitFunc) mail_paned_init,
+			NULL   /* value_table */
+		};
+
+		type = g_type_register_static (
+			E_TYPE_PANED, "EMailPaned", &type_info, 0);
+	}
+
+	return type;
+}
+
+GtkWidget *
+e_mail_paned_new (EShellBackend *shell_backend)
+{
+	g_return_val_if_fail (E_IS_SHELL_BACKEND (shell_backend), NULL);
+
+	return g_object_new (
+		E_TYPE_MAIL_PANED, "shell-backend", shell_backend, NULL);
+}
+
+EShellBackend *
+e_mail_paned_get_shell_backend (EMailPaned *paned)
+{
+	g_return_val_if_fail (E_IS_SHELL_BACKEND (paned), NULL);
+
+	return paned->priv->shell_backend;
+}
+
+EMailFolderPane *
+e_mail_paned_get_folder_pane (EMailPaned *paned)
+{
+	GtkWidget *child;
+
+	g_return_val_if_fail (E_IS_MAIL_PANED (paned), NULL);
+
+	child = gtk_paned_get_child1 (GTK_PANED (paned));
+
+	return E_MAIL_FOLDER_PANE (child);
+}
+
+EMailMessagePane *
+e_mail_paned_get_message_pane (EMailPaned *paned)
+{
+	GtkWidget *child;
+
+	g_return_val_if_fail (E_IS_MAIL_PANED (paned), NULL);
+
+	child = gtk_paned_get_child2 (GTK_PANED (paned));
+
+	return E_MAIL_MESSAGE_PANE (child);
+}
+
+guint
+e_mail_paned_get_mark_as_read_delay (EMailPaned *paned)
+{
+	g_return_val_if_fail (E_IS_MAIL_PANED (paned), 0);
+
+	return paned->priv->mark_as_read_delay;
+}
+
+void
+e_mail_paned_set_mark_as_read_delay (EMailPaned *paned,
+                                     guint mark_as_read_delay)
+{
+	g_return_if_fail (E_IS_MAIL_PANED (paned));
+
+	paned->priv->mark_as_read_delay = mark_as_read_delay;
+
+	g_object_notify (G_OBJECT (paned), "mark-as-read-delay");
+}
+
+gboolean
+e_mail_paned_get_mark_as_read_enabled (EMailPaned *paned)
+{
+	g_return_val_if_fail (E_IS_MAIL_PANED (paned), FALSE);
+
+	return paned->priv->mark_as_read_enabled;
+}
+
+void
+e_mail_paned_set_mark_as_read_enabled (EMailPaned *paned,
+                                       gboolean mark_as_read_enabled)
+{
+	g_return_if_fail (E_IS_MAIL_PANED (paned));
+
+	paned->priv->mark_as_read_enabled = mark_as_read_enabled;
+
+	g_object_notify (G_OBJECT (paned), "mark-as-read-enabled");
+}
+
diff --git a/mail/e-mail-paned.h b/mail/e-mail-paned.h
new file mode 100644
index 0000000..dc80003
--- /dev/null
+++ b/mail/e-mail-paned.h
@@ -0,0 +1,85 @@
+/*
+ * e-mail-paned.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#ifndef E_MAIL_PANED_H
+#define E_MAIL_PANED_H
+
+#include <misc/e-paned.h>
+#include <mail/e-mail-folder-pane.h>
+#include <mail/e-mail-message-pane.h>
+
+/* Standard GObject macros */
+#define E_TYPE_MAIL_PANED \
+	(e_mail_paned_get_type ())
+#define E_MAIL_PANED(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST \
+	((obj), E_TYPE_MAIL_PANED, EMailPaned))
+#define E_MAIL_PANED_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_CAST \
+	((cls), E_TYPE_MAIL_PANED, EMailPanedClass))
+#define E_IS_MAIL_PANED(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE \
+	((obj), E_TYPE_MAIL_PANED))
+#define E_IS_MAIL_PANED_CLASS(cls) \
+	(G_TYPE_CHECK_CLASS_TYPE \
+	((cls), E_TYPE_MAIL_PANED))
+#define E_MAIL_PANED_GET_CLASS(obj) \
+	(G_TYPE_INSTANCE_GET_CLASS \
+	((obj), E_TYPE_MAIL_PANED, EMailPanedClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EMailPaned EMailPaned;
+typedef struct _EMailPanedClass EMailPanedClass;
+typedef struct _EMailPanedPrivate EMailPanedPrivate;
+
+struct _EMailPaned {
+	EPaned parent;
+	EMailPanedPrivate *priv;
+};
+
+struct _EMailPanedClass {
+	EPanedClass parent_class;
+
+	/* Signals */
+	void		(*mark_as_read)		(EMailPaned *paned,
+						 const gchar *message_uid);
+};
+
+GType		e_mail_paned_get_type		(void);
+GtkWidget *	e_mail_paned_new		(EShellBackend *shell_backend);
+EShellBackend *	e_mail_paned_get_shell_backend	(EMailPaned *paned);
+EMailFolderPane *
+		e_mail_paned_get_folder_pane	(EMailPaned *paned);
+EMailMessagePane *
+		e_mail_paned_get_message_pane	(EMailPaned *paned);
+guint		e_mail_paned_get_mark_as_read_delay
+						(EMailPaned *paned);
+void		e_mail_paned_set_mark_as_read_delay
+						(EMailPaned *paned,
+						 guint mark_as_read_delay);
+gboolean	e_mail_paned_get_mark_as_read_enabled
+						(EMailPaned *paned);
+void		e_mail_paned_set_mark_as_read_enabled
+						(EMailPaned *paned,
+						 gboolean mark_as_read_enabled);
+void		e_mail_paned_changed		(EMailPaned *paned);
+
+G_END_DECLS
+
+#endif /* E_MAIL_PANED_H */
diff --git a/mail/e-mail-reader.c b/mail/e-mail-reader.c
index ad60195..81a518d 100644
--- a/mail/e-mail-reader.c
+++ b/mail/e-mail-reader.c
@@ -51,34 +51,7 @@
 #include "mail/mail-vfolder.h"
 #include "mail/message-list.h"
 
-#define E_MAIL_READER_GET_PRIVATE(obj) \
-	(mail_reader_get_private (G_OBJECT (obj)))
-
-typedef struct _EMailReaderPrivate EMailReaderPrivate;
-
-struct _EMailReaderPrivate {
-
-	/* This timer runs when the user selects a single message. */
-	guint message_selected_timeout_id;
-
-	/* This is the message UID to automatically mark as read
-	 * after a short period (specified by a user preference). */
-	gchar *mark_read_message_uid;
-
-	/* This is the ID of an asynchronous operation
-	 * to retrieve a message from a mail folder. */
-	gint retrieving_message_operation_id;
-
-	/* These flags work together to prevent message selection
-	 * restoration after a folder switch from automatically
-	 * marking the message as read.  We only want that to
-	 * happen when the -user- selects a message. */
-	guint folder_was_just_selected    : 1;
-	guint restoring_message_selection : 1;
-};
-
 enum {
-	CHANGED,
 	FOLDER_LOADED,
 	SHOW_SEARCH_BAR,
 	UPDATE_ACTIONS,
@@ -92,34 +65,6 @@ static GQuark quark_private;
 static guint signals[LAST_SIGNAL];
 
 static void
-mail_reader_finalize (EMailReaderPrivate *priv)
-{
-	if (priv->message_selected_timeout_id > 0)
-		g_source_remove (priv->message_selected_timeout_id);
-
-	g_free (priv->mark_read_message_uid);
-
-	g_slice_free (EMailReaderPrivate, priv);
-}
-
-static EMailReaderPrivate *
-mail_reader_get_private (GObject *object)
-{
-	EMailReaderPrivate *priv;
-
-	priv = g_object_get_qdata (object, quark_private);
-
-	if (G_UNLIKELY (priv == NULL)) {
-		priv = g_slice_new0 (EMailReaderPrivate);
-		g_object_set_qdata_full (
-			object, quark_private, priv,
-			(GDestroyNotify) mail_reader_finalize);
-	}
-
-	return priv;
-}
-
-static void
 action_mail_add_sender_cb (GtkAction *action,
                            EMailReader *reader)
 {
@@ -1764,276 +1709,6 @@ mail_reader_key_press_cb (EMailReader *reader,
 	return mail_reader_key_press_event_cb (reader, &event->key);
 }
 
-static gboolean
-mail_reader_message_read_cb (EMailReader *reader)
-{
-	EMailReaderPrivate *priv;
-	GtkWidget *message_list;
-	const gchar *cursor_uid;
-	const gchar *message_uid;
-
-	priv = E_MAIL_READER_GET_PRIVATE (reader);
-
-	message_uid = priv->mark_read_message_uid;
-	g_return_val_if_fail (message_uid != NULL, FALSE);
-
-	message_list = e_mail_reader_get_message_list (reader);
-	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
-
-	if (g_strcmp0 (cursor_uid, message_uid) == 0)
-		e_mail_reader_mark_as_read (reader, message_uid);
-
-	return FALSE;
-}
-
-static void
-update_webview_content (EMailReader *reader, const gchar *content)
-{
-	EMFormatHTMLDisplay *html_display;
-	EWebView *web_view;
-
-	g_return_if_fail (reader != NULL);
-	g_return_if_fail (content != NULL);
-
-	html_display = e_mail_reader_get_html_display (reader);
-	g_return_if_fail (html_display != NULL);
-
-	/* skip the progress message when it's formatting something */
-	if (em_format_busy (EM_FORMAT (html_display)))
-		return;
-
-	web_view = E_WEB_VIEW (EM_FORMAT_HTML (html_display)->html);
-	g_return_if_fail (web_view != NULL);
-
-	e_web_view_load_string (web_view, content);
-}
-
-static void
-mail_reader_message_loaded_cb (CamelFolder *folder,
-                               const gchar *message_uid,
-                               CamelMimeMessage *message,
-                               gpointer user_data,
-                               CamelException *ex)
-{
-	EMailReader *reader = user_data;
-	EMailReaderPrivate *priv;
-	EMFormatHTMLDisplay *html_display;
-	GtkWidget *message_list;
-	EShellBackend *shell_backend;
-	EShellSettings *shell_settings;
-	EShell *shell;
-	EMEvent *event;
-	EMEventTargetMessage *target;
-	const gchar *cursor_uid;
-	gboolean schedule_timeout;
-	gint timeout_interval;
-
-	priv = E_MAIL_READER_GET_PRIVATE (reader);
-
-	html_display = e_mail_reader_get_html_display (reader);
-	message_list = e_mail_reader_get_message_list (reader);
-
-	shell_backend = e_mail_reader_get_shell_backend (reader);
-	shell = e_shell_backend_get_shell (shell_backend);
-	shell_settings = e_shell_get_shell_settings (shell);
-
-	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
-
-	/* If the user picked a different message in the time it took
-	 * to fetch this message, then don't bother rendering it. */
-	if (g_strcmp0 (cursor_uid, message_uid) != 0)
-		goto exit;
-
-	/** @Event: message.reading
-	 * @Title: Viewing a message
-	 * @Target: EMEventTargetMessage
-	 *
-	 * message.reading is emitted whenever a user views a message.
-	 */
-	event = em_event_peek ();
-	target = em_event_target_new_message (
-		event, folder, message, message_uid, 0, NULL);
-	e_event_emit (
-		(EEvent *) event, "message.reading",
-		(EEventTarget *) target);
-
-	em_format_format (
-		EM_FORMAT (html_display), folder, message_uid, message);
-
-	/* Reset the shell view icon. */
-	e_shell_event (shell, "mail-icon", (gpointer) "evolution-mail");
-
-	/* Determine whether to mark the message as read. */
-	schedule_timeout =
-		(message != NULL) &&
-		e_shell_settings_get_boolean (
-			shell_settings, "mail-mark-seen") &&
-		!priv->restoring_message_selection;
-	timeout_interval =
-		e_shell_settings_get_int (
-		shell_settings, "mail-mark-seen-timeout");
-
-	g_free (priv->mark_read_message_uid);
-	priv->mark_read_message_uid = NULL;
-
-	if (MESSAGE_LIST (message_list)->seen_id > 0) {
-		g_source_remove (MESSAGE_LIST (message_list)->seen_id);
-		MESSAGE_LIST (message_list)->seen_id = 0;
-	}
-
-	if (schedule_timeout) {
-		priv->mark_read_message_uid = g_strdup (message_uid);
-		MESSAGE_LIST (message_list)->seen_id = g_timeout_add (
-			timeout_interval, (GSourceFunc)
-			mail_reader_message_read_cb, reader);
-
-	} else if (camel_exception_is_set (ex)) {
-		gchar *string;
-
-		if (ex->id != CAMEL_EXCEPTION_OPERATION_IN_PROGRESS) {
-			/* Display the error inline and clear the exception. */
-			string = g_strdup_printf (
-					"<h2>%s</h2><p>%s</p>",
-					_("Unable to retrieve message"),
-					ex->desc);
-		} else {
-			string = g_strdup_printf (_("Retrieving message '%s'"), cursor_uid);
-		}
-
-		update_webview_content (reader, string);
-		g_free (string);
-
-		camel_exception_clear (ex);
-	}
-
-	/* We referenced this in the call to mail_get_messagex(). */
-	g_object_unref (reader);
-
-exit:
-	priv->restoring_message_selection = FALSE;
-}
-
-static gboolean
-mail_reader_message_selected_timeout_cb (EMailReader *reader)
-{
-	EMailReaderPrivate *priv;
-	EMFormatHTMLDisplay *html_display;
-	GtkWidget *message_list;
-	CamelFolder *folder;
-	const gchar *cursor_uid;
-	const gchar *format_uid;
-
-	priv = E_MAIL_READER_GET_PRIVATE (reader);
-
-	folder = e_mail_reader_get_folder (reader);
-	html_display = e_mail_reader_get_html_display (reader);
-	message_list = e_mail_reader_get_message_list (reader);
-
-	cursor_uid = MESSAGE_LIST (message_list)->cursor_uid;
-	format_uid = EM_FORMAT (html_display)->uid;
-
-	if (MESSAGE_LIST (message_list)->last_sel_single) {
-		GtkWidget *widget;
-		gboolean html_display_visible;
-		gboolean selected_uid_changed;
-
-		/* Decide whether to download the full message now. */
-
-		widget = GTK_WIDGET (EM_FORMAT_HTML (html_display)->html);
-
-#if GTK_CHECK_VERSION(2,19,7)
-		html_display_visible = gtk_widget_get_mapped (widget);
-#else
-		html_display_visible = GTK_WIDGET_MAPPED (widget);
-#endif
-		selected_uid_changed = g_strcmp0 (cursor_uid, format_uid);
-
-		if (html_display_visible && selected_uid_changed) {
-			gint op_id;
-			gchar *string;
-			gboolean store_async;
-			MailMsgDispatchFunc disp_func;
-
-			string = g_strdup_printf (_("Retrieving message '%s'"), cursor_uid);
-			update_webview_content (reader, string);
-			g_free (string);
-
-			store_async = folder->parent_store->flags & CAMEL_STORE_ASYNC;
-
-			if (store_async)
-				disp_func = mail_msg_unordered_push;
-			else
-				disp_func = mail_msg_fast_ordered_push;
-
-			op_id = mail_get_messagex (
-				folder, cursor_uid,
-				mail_reader_message_loaded_cb,
-				g_object_ref (reader),
-				disp_func);
-
-			if (!store_async)
-				priv->retrieving_message_operation_id = op_id;
-		}
-	} else {
-		em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
-		priv->restoring_message_selection = FALSE;
-	}
-
-	priv->message_selected_timeout_id = 0;
-
-	return FALSE;
-}
-
-static void
-mail_reader_message_selected_cb (EMailReader *reader,
-                                 const gchar *uid)
-{
-	EMailReaderPrivate *priv;
-	MessageList *message_list;
-	gboolean store_async;
-	CamelFolder *folder;
-
-	priv = E_MAIL_READER_GET_PRIVATE (reader);
-
-	folder = e_mail_reader_get_folder (reader);
-	store_async = folder->parent_store->flags & CAMEL_STORE_ASYNC;
-
-	/* Cancel previous message retrieval if the store is not async. */
-	if (!store_async && priv->retrieving_message_operation_id > 0)
-		mail_msg_cancel (priv->retrieving_message_operation_id);
-
-	/* Cancel the seen timer. */
-	message_list = MESSAGE_LIST (e_mail_reader_get_message_list (reader));
-	if (message_list && message_list->seen_id) {
-		g_source_remove (message_list->seen_id);
-		message_list->seen_id = 0;
-	}
-
-	/* Cancel the message selected timer. */
-	if (priv->message_selected_timeout_id > 0) {
-		g_source_remove (priv->message_selected_timeout_id);
-		priv->message_selected_timeout_id = 0;
-	}
-
-	/* If a folder was just selected then we are now automatically
-	 * restoring the previous message selection.  We behave slightly
-	 * differently than if the user had selected the message. */
-	priv->restoring_message_selection = priv->folder_was_just_selected;
-	priv->folder_was_just_selected = FALSE;
-
-	/* Skip the timeout if we're restoring the previous message
-	 * selection.  The timeout is there for when we're scrolling
-	 * rapidly through the message list. */
-	if (priv->restoring_message_selection)
-		mail_reader_message_selected_timeout_cb (reader);
-	else
-		priv->message_selected_timeout_id = g_timeout_add (
-			100, (GSourceFunc)
-			mail_reader_message_selected_timeout_cb, reader);
-
-	e_mail_reader_changed (reader);
-}
-
 static void
 mail_reader_emit_folder_loaded (EMailReader *reader)
 {
@@ -2075,40 +1750,6 @@ mail_reader_set_folder (EMailReader *reader,
                         CamelFolder *folder,
                         const gchar *folder_uri)
 {
-	EMailReaderPrivate *priv;
-	EMFormatHTMLDisplay *html_display;
-	CamelFolder *previous_folder;
-	GtkWidget *message_list;
-	const gchar *previous_folder_uri;
-	gboolean outgoing;
-
-	priv = E_MAIL_READER_GET_PRIVATE (reader);
-
-	html_display = e_mail_reader_get_html_display (reader);
-	message_list = e_mail_reader_get_message_list (reader);
-
-	previous_folder = e_mail_reader_get_folder (reader);
-	previous_folder_uri = e_mail_reader_get_folder_uri (reader);
-
-	if (previous_folder != NULL)
-		mail_sync_folder (previous_folder, NULL, NULL);
-
-	/* Skip the rest if we're already viewing the folder. */
-	if (g_strcmp0 (folder_uri, previous_folder_uri) == 0)
-		return;
-
-	outgoing = folder != NULL && folder_uri != NULL && (
-		em_utils_folder_is_drafts (folder, folder_uri) ||
-		em_utils_folder_is_outbox (folder, folder_uri) ||
-		em_utils_folder_is_sent (folder, folder_uri));
-
-	em_format_format (EM_FORMAT (html_display), NULL, NULL, NULL);
-
-	priv->folder_was_just_selected = (folder != NULL);
-
-	message_list_set_folder (
-		MESSAGE_LIST (message_list), folder, folder_uri, outgoing);
-
 	mail_reader_emit_folder_loaded (reader);
 }
 
@@ -2490,14 +2131,6 @@ mail_reader_class_init (EMailReaderIface *iface)
 	iface->set_message = mail_reader_set_message;
 	iface->update_actions = mail_reader_update_actions;
 
-	signals[CHANGED] = g_signal_new (
-		"changed",
-		G_OBJECT_CLASS_TYPE (iface),
-		G_SIGNAL_RUN_FIRST,
-		0, NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
-
 	signals[FOLDER_LOADED] = g_signal_new (
 		"folder-loaded",
 		G_OBJECT_CLASS_TYPE (iface),
@@ -2704,10 +2337,6 @@ e_mail_reader_init (EMailReader *reader)
 		G_CALLBACK (mail_reader_key_press_event_cb), reader);
 
 	g_signal_connect_swapped (
-		message_list, "message-selected",
-		G_CALLBACK (mail_reader_message_selected_cb), reader);
-
-	g_signal_connect_swapped (
 		message_list, "message-list-built",
 		G_CALLBACK (mail_reader_emit_folder_loaded), reader);
 
@@ -2718,18 +2347,6 @@ e_mail_reader_init (EMailReader *reader)
 	g_signal_connect_swapped (
 		message_list, "key-press",
 		G_CALLBACK (mail_reader_key_press_cb), reader);
-
-	g_signal_connect_swapped (
-		message_list, "selection-change",
-		G_CALLBACK (e_mail_reader_changed), reader);
-}
-
-void
-e_mail_reader_changed (EMailReader *reader)
-{
-	g_return_if_fail (E_IS_MAIL_READER (reader));
-
-	g_signal_emit (reader, signals[CHANGED], 0);
 }
 
 guint32
diff --git a/mail/e-mail-reader.h b/mail/e-mail-reader.h
index a79d7f5..ed7d4dd 100644
--- a/mail/e-mail-reader.h
+++ b/mail/e-mail-reader.h
@@ -107,7 +107,6 @@ struct _EMailReaderIface {
 
 GType		e_mail_reader_get_type		(void);
 void		e_mail_reader_init		(EMailReader *reader);
-void		e_mail_reader_changed		(EMailReader *reader);
 guint32		e_mail_reader_check_state	(EMailReader *reader);
 void		e_mail_reader_update_actions	(EMailReader *reader);
 GtkAction *	e_mail_reader_get_action	(EMailReader *reader,
diff --git a/mail/message-list.c b/mail/message-list.c
index 6526950..8ff4ec4 100644
--- a/mail/message-list.c
+++ b/mail/message-list.c
@@ -2520,12 +2520,6 @@ message_list_finalize (GObject *object)
 }
 
 static void
-message_list_built (MessageList *message_list)
-{
-	gtk_widget_grab_focus (GTK_WIDGET (message_list));
-}
-
-static void
 message_list_selectable_update_actions (ESelectable *selectable,
                                         EFocusTracker *focus_tracker,
                                         GdkAtom *clipboard_targets,
@@ -2566,8 +2560,6 @@ message_list_class_init (MessageListClass *class)
 	gtk_object_class = GTK_OBJECT_CLASS (class);
 	gtk_object_class->destroy = message_list_destroy;
 
-	class->message_list_built = message_list_built;
-
 	/* Inherited from ESelectableInterface */
 	g_object_class_override_property (
 		object_class,
diff --git a/modules/mail/e-mail-shell-content.c b/modules/mail/e-mail-shell-content.c
index 17eb613..e5444d4 100644
--- a/modules/mail/e-mail-shell-content.c
+++ b/modules/mail/e-mail-shell-content.c
@@ -30,16 +30,15 @@
 #include "e-util/gconf-bridge.h"
 #include "widgets/menus/gal-view-etable.h"
 #include "widgets/menus/gal-view-instance.h"
-#include "widgets/misc/e-paned.h"
-#include "widgets/misc/e-preview-pane.h"
-#include "widgets/misc/e-search-bar.h"
 
 #include "em-utils.h"
 #include "mail-config.h"
 #include "mail-ops.h"
 #include "message-list.h"
 
+#include "e-mail-paned.h"
 #include "e-mail-reader.h"
+#include "e-mail-reader-utils.h"
 #include "e-mail-shell-backend.h"
 #include "e-mail-shell-view-actions.h"
 
@@ -53,11 +52,7 @@
 
 struct _EMailShellContentPrivate {
 	GtkWidget *paned;
-	GtkWidget *scrolled_window;
-	GtkWidget *message_list;
-	GtkWidget *search_bar;
 
-	EMFormatHTMLDisplay *html_display;
 	GalViewInstance *view_instance;
 	GtkOrientation orientation;
 
@@ -327,26 +322,6 @@ mail_shell_content_dispose (GObject *object)
 		priv->paned = NULL;
 	}
 
-	if (priv->scrolled_window != NULL) {
-		g_object_unref (priv->scrolled_window);
-		priv->scrolled_window = NULL;
-	}
-
-	if (priv->message_list != NULL) {
-		g_object_unref (priv->message_list);
-		priv->message_list = NULL;
-	}
-
-	if (priv->search_bar != NULL) {
-		g_object_unref (priv->search_bar);
-		priv->search_bar = NULL;
-	}
-
-	if (priv->html_display != NULL) {
-		g_object_unref (priv->html_display);
-		priv->html_display = NULL;
-	}
-
 	if (priv->view_instance != NULL) {
 		g_object_unref (priv->view_instance);
 		priv->view_instance = NULL;
@@ -363,17 +338,16 @@ mail_shell_content_constructed (GObject *object)
 	EShellContent *shell_content;
 	EShellBackend *shell_backend;
 	EShellView *shell_view;
-	ESearchBar *search_bar;
+	EShellSettings *shell_settings;
+	EShell *shell;
 	EMailReader *reader;
 	GtkWidget *message_list;
 	GConfBridge *bridge;
 	GtkWidget *container;
 	GtkWidget *widget;
-	EWebView *web_view;
 	const gchar *key;
 
 	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (object);
-	priv->html_display = em_format_html_display_new ();
 
 	/* Chain up to parent's constructed() method. */
 	G_OBJECT_CLASS (parent_class)->constructed (object);
@@ -382,55 +356,38 @@ mail_shell_content_constructed (GObject *object)
 	shell_view = e_shell_content_get_shell_view (shell_content);
 	shell_backend = e_shell_view_get_shell_backend (shell_view);
 
-	web_view = E_WEB_VIEW (EM_FORMAT_HTML (priv->html_display)->html);
+	shell = e_shell_backend_get_shell (shell_backend);
+	shell_settings = e_shell_get_shell_settings (shell);
 
 	/* Build content widgets. */
 
 	container = GTK_WIDGET (object);
 
-	widget = e_paned_new (GTK_ORIENTATION_VERTICAL);
+	widget = e_mail_paned_new (shell_backend);
 	gtk_container_add (GTK_CONTAINER (container), widget);
 	priv->paned = g_object_ref (widget);
 	gtk_widget_show (widget);
 
-	e_binding_new (object, "orientation", widget, "orientation");
-
-	container = priv->paned;
-
-	widget = gtk_scrolled_window_new (NULL, NULL);
-	gtk_scrolled_window_set_policy (
-		GTK_SCROLLED_WINDOW (widget),
-		GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
-	gtk_scrolled_window_set_shadow_type (
-		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
-	priv->scrolled_window = g_object_ref (widget);
-	gtk_paned_pack1 (GTK_PANED (container), widget, TRUE, FALSE);
-	gtk_widget_show (widget);
-
-	container = widget;
+	g_signal_connect_swapped (
+		priv->paned, "mark-as-read",
+		G_CALLBACK (e_mail_reader_mark_as_read), object);
 
-	widget = message_list_new (shell_backend);
-	gtk_container_add (GTK_CONTAINER (container), widget);
-	priv->message_list = g_object_ref (widget);
-	gtk_widget_show (widget);
+	e_binding_new (
+		object, "orientation",
+		widget, "orientation");
 
-	container = priv->paned;
+	e_binding_new (
+		shell_settings, "mail-mark-seen",
+		widget, "mark-as-read-enabled");
 
-	gtk_widget_show (GTK_WIDGET (web_view));
+	e_binding_new (
+		shell_settings, "mail-mark-seen-timeout",
+		widget, "mark-as-read-delay");
 
-	widget = e_preview_pane_new (web_view);
-	gtk_paned_pack2 (GTK_PANED (container), widget, FALSE, FALSE);
-	gtk_widget_show (widget);
+	widget = gtk_paned_get_child2 (GTK_PANED (priv->paned));
 
 	e_binding_new (object, "preview-visible", widget, "visible");
 
-	search_bar = e_preview_pane_get_search_bar (E_PREVIEW_PANE (widget));
-	priv->search_bar = g_object_ref (search_bar);
-
-	g_signal_connect_swapped (
-		search_bar, "changed",
-		G_CALLBACK (em_format_redraw), priv->html_display);
-
 	/* Load the view instance. */
 
 	e_mail_shell_content_update_view_instance (
@@ -497,20 +454,34 @@ static EMFormatHTMLDisplay *
 mail_shell_content_get_html_display (EMailReader *reader)
 {
 	EMailShellContentPrivate *priv;
+	EMailMessagePane *message_pane;
+	EMFormatHTML *formatter;
+	EMailDisplay *display;
+	EMailPaned *paned;
 
 	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 
-	return priv->html_display;
+	paned = E_MAIL_PANED (priv->paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+	display = e_mail_message_pane_get_display (message_pane);
+	formatter = e_mail_display_get_formatter (display);
+
+	return EM_FORMAT_HTML_DISPLAY (formatter);
 }
 
 static GtkWidget *
 mail_shell_content_get_message_list (EMailReader *reader)
 {
 	EMailShellContentPrivate *priv;
+	EMailFolderPane *folder_pane;
+	EMailPaned *paned;
 
 	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 
-	return priv->message_list;
+	paned = E_MAIL_PANED (priv->paned);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+
+	return e_mail_folder_pane_get_message_list (folder_pane);
 }
 
 static GtkMenu *
@@ -567,6 +538,8 @@ mail_shell_content_set_folder (EMailReader *reader,
 	EShellContent *shell_content;
 	EMailShellContentPrivate *priv;
 	EMailReaderIface *default_iface;
+	EMailPaned *paned;
+	EMailFolderPane *folder_pane;
 	GtkWidget *message_list;
 	CamelFolder *old_folder;
 	GKeyFile *key_file;
@@ -590,6 +563,11 @@ mail_shell_content_set_folder (EMailReader *reader,
 	default_iface = g_type_default_interface_peek (E_TYPE_MAIL_READER);
 	default_iface->set_folder (reader, folder, folder_uri);
 
+	paned = E_MAIL_PANED (priv->paned);
+	folder_pane = e_mail_paned_get_folder_pane (paned);
+
+	e_mail_folder_pane_set_folder (folder_pane, folder, folder_uri);
+
 	if (folder == NULL)
 		goto exit;
 
@@ -647,10 +625,15 @@ static void
 mail_shell_content_show_search_bar (EMailReader *reader)
 {
 	EMailShellContentPrivate *priv;
+	EMailMessagePane *message_pane;
+	EMailPaned *paned;
 
 	priv = E_MAIL_SHELL_CONTENT_GET_PRIVATE (reader);
 
-	gtk_widget_show (priv->search_bar);
+	paned = E_MAIL_PANED (priv->paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	e_preview_pane_show_search_bar (E_PREVIEW_PANE (message_pane));
 }
 
 static void
@@ -914,12 +897,19 @@ void
 e_mail_shell_content_set_search_strings (EMailShellContent *mail_shell_content,
                                          GSList *search_strings)
 {
+	EMailPaned *paned;
 	ESearchBar *search_bar;
+	EPreviewPane *preview_pane;
+	EMailMessagePane *message_pane;
 	ESearchingTokenizer *tokenizer;
 
 	g_return_if_fail (E_IS_MAIL_SHELL_CONTENT (mail_shell_content));
 
-	search_bar = E_SEARCH_BAR (mail_shell_content->priv->search_bar);
+	paned = E_MAIL_PANED (mail_shell_content->priv->paned);
+	message_pane = e_mail_paned_get_message_pane (paned);
+
+	preview_pane = E_PREVIEW_PANE (message_pane);
+	search_bar = e_preview_pane_get_search_bar (preview_pane);
 	tokenizer = e_search_bar_get_tokenizer (search_bar);
 
 	e_searching_tokenizer_set_secondary_case_sensitivity (tokenizer, FALSE);
diff --git a/modules/mail/e-mail-shell-content.h b/modules/mail/e-mail-shell-content.h
index 4be7be2..f750178 100644
--- a/modules/mail/e-mail-shell-content.h
+++ b/modules/mail/e-mail-shell-content.h
@@ -75,7 +75,7 @@ gboolean	e_mail_shell_content_get_preview_visible
 					(EMailShellContent *mail_shell_content);
 void		e_mail_shell_content_set_preview_visible
 					(EMailShellContent *mail_shell_content,
-						 gboolean preview_visible);
+					 gboolean preview_visible);
 EShellSearchbar *
 		e_mail_shell_content_get_searchbar
 					(EMailShellContent *mail_shell_content);
diff --git a/modules/mail/e-mail-shell-view-private.c b/modules/mail/e-mail-shell-view-private.c
index 00dcb2f..1b56209 100644
--- a/modules/mail/e-mail-shell-view-private.c
+++ b/modules/mail/e-mail-shell-view-private.c
@@ -249,8 +249,7 @@ mail_shell_view_popup_event_cb (EMailShellView *mail_shell_view,
 }
 
 static void
-mail_shell_view_reader_changed_cb (EMailShellView *mail_shell_view,
-                                   EMailReader *reader)
+mail_shell_view_update (EMailShellView *mail_shell_view)
 {
 	e_shell_view_update_actions (E_SHELL_VIEW (mail_shell_view));
 	e_mail_shell_view_update_sidebar (mail_shell_view);
@@ -510,6 +509,11 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 		mail_shell_view);
 
 	g_signal_connect_swapped (
+		message_list, "message-selected",
+		G_CALLBACK (mail_shell_view_update),
+		mail_shell_view);
+
+	g_signal_connect_swapped (
 		message_list, "popup-menu",
 		G_CALLBACK (mail_shell_view_message_list_popup_menu_cb),
 		mail_shell_view);
@@ -520,8 +524,8 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 		mail_shell_view);
 
 	g_signal_connect_swapped (
-		reader, "changed",
-		G_CALLBACK (mail_shell_view_reader_changed_cb),
+		message_list, "selection-change",
+		G_CALLBACK (mail_shell_view_update),
 		mail_shell_view);
 
 	g_signal_connect_swapped (
@@ -532,7 +536,7 @@ e_mail_shell_view_private_constructed (EMailShellView *mail_shell_view)
 	/* Use the same callback as "changed". */
 	g_signal_connect_swapped (
 		reader, "folder-loaded",
-		G_CALLBACK (mail_shell_view_reader_changed_cb),
+		G_CALLBACK (mail_shell_view_update),
 		mail_shell_view);
 
 	g_signal_connect_swapped (
diff --git a/widgets/misc/e-preview-pane.c b/widgets/misc/e-preview-pane.c
index 240bfbd..67ec8a8 100644
--- a/widgets/misc/e-preview-pane.c
+++ b/widgets/misc/e-preview-pane.c
@@ -133,7 +133,7 @@ preview_pane_constructed (GObject *object)
 		GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN);
 	gtk_box_pack_start (GTK_BOX (object), widget, TRUE, TRUE, 0);
 	gtk_container_add (GTK_CONTAINER (widget), priv->web_view);
-	gtk_widget_show (widget);
+	gtk_widget_show_all (widget);
 
 	widget = e_search_bar_new (E_WEB_VIEW (priv->web_view));
 	gtk_box_pack_start (GTK_BOX (object), widget, FALSE, FALSE, 0);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]