diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index b3df15d..a3722ed 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -124,6 +124,9 @@ NOINST_H_FILES =			\
 	gedit-tab-label.h		\
 	gedittextregion.h		\
 	gedit-ui.h			\
+	gedit-undo-manager.h		\
+	gedit-view-frame.h		\
+	gedit-view-holder.h		\
 	gedit-window-private.h
 
 INST_H_FILES =				\
@@ -205,8 +208,11 @@ libgedit_c_files =			\
 	gedit-style-scheme-manager.c	\
 	gedit-tab.c 			\
 	gedit-tab-label.c		\
+	gedit-undo-manager.c		\
 	gedit-utils.c 			\
 	gedit-view.c 			\
+	gedit-view-frame.c		\
+	gedit-view-holder.c		\
 	gedit-window.c			\
 	gedittextregion.c
 
diff --git a/gedit/gedit-commands-view.c b/gedit/gedit-commands-view.c
index 98a8c20..cd914ce 100644
--- a/gedit/gedit-commands-view.c
+++ b/gedit/gedit-commands-view.c
@@ -139,4 +139,37 @@ _gedit_cmd_view_leave_fullscreen_mode (GtkAction   *action,
 					   window);
 }
 
+void
+_gedit_cmd_view_split_horizontally (GtkAction   *action,
+				    GeditWindow *window)
+{
+	GeditTab *tab;
+
+	tab = gedit_window_get_active_tab (window);
+
+	_gedit_tab_split (tab, GTK_ORIENTATION_HORIZONTAL);
+}
+
+void
+_gedit_cmd_view_split_vertically (GtkAction   *action,
+				  GeditWindow *window)
+{
+	GeditTab *tab;
+
+	tab = gedit_window_get_active_tab (window);
+
+	_gedit_tab_split (tab, GTK_ORIENTATION_VERTICAL);
+}
+
+void
+_gedit_cmd_view_unsplit (GtkAction   *action,
+			 GeditWindow *window)
+{
+	GeditTab *tab;
+
+	tab = gedit_window_get_active_tab (window);
+
+	_gedit_tab_unsplit (tab);
+}
+
 /* ex:ts=8:noet: */
diff --git a/gedit/gedit-commands.h b/gedit/gedit-commands.h
index 8d1b3ef..32c8b14 100644
--- a/gedit/gedit-commands.h
+++ b/gedit/gedit-commands.h
@@ -123,6 +123,12 @@ void		_gedit_cmd_view_toggle_fullscreen_mode	(GtkAction   *action,
 							 GeditWindow *window);
 void		_gedit_cmd_view_leave_fullscreen_mode	(GtkAction   *action,
 							 GeditWindow *window);
+void		_gedit_cmd_view_split_horizontally	(GtkAction   *action,
+							 GeditWindow *window);
+void		_gedit_cmd_view_split_vertically	(GtkAction   *action,
+							 GeditWindow *window);
+void		_gedit_cmd_view_unsplit			(GtkAction   *action,
+							 GeditWindow *window);
 
 void		_gedit_cmd_search_find			(GtkAction   *action,
 							 GeditWindow *window);
diff --git a/gedit/gedit-document.c b/gedit/gedit-document.c
index e9ff43b..173bc1e 100644
--- a/gedit/gedit-document.c
+++ b/gedit/gedit-document.c
@@ -174,6 +174,7 @@ enum {
 	SAVING,
 	SAVED,
 	SEARCH_HIGHLIGHT_UPDATED,
+	SYNC_DOCUMENTS,
 	LAST_SIGNAL
 };
 
@@ -736,6 +737,21 @@ gedit_document_class_init (GeditDocumentClass *klass)
 			      GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE,
 			      GTK_TYPE_TEXT_ITER | G_SIGNAL_TYPE_STATIC_SCOPE);
 
+	/* This signal is used to sync splitted documents. This signal is
+	 * private and should not be used except for the tab.
+	 * NOTE: When an attribute needs to be sync this signal needs to be
+	         emitted.
+	 */
+	document_signals[SYNC_DOCUMENTS] =
+		g_signal_new ("sync-documents",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+
 	g_type_class_add_private (object_class, sizeof (GeditDocumentPrivate));
 }
 
@@ -1527,6 +1543,8 @@ document_loader_loaded (GeditDocumentLoader *loader,
 		}
 
 		gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc), &iter);
+
+		g_signal_emit (doc, document_signals[SYNC_DOCUMENTS], 0);
 	}
 
 	/* special case creating a named new doc */
@@ -1751,6 +1769,9 @@ document_saver_saving (GeditDocumentSaver *saver,
 			set_encoding (doc, 
 				      doc->priv->requested_encoding, 
 				      TRUE);
+
+			/* We need to sync the docs after saving */
+			g_signal_emit (doc, document_signals[SYNC_DOCUMENTS], 0);
 		}
 
 		g_signal_emit (doc,
@@ -3085,4 +3106,22 @@ gedit_document_set_metadata (GeditDocument *doc,
 }
 #endif
 
+void
+_gedit_document_sync_documents (GeditDocument *doc1,
+				GeditDocument *doc2)
+{
+	if (doc2->priv->untitled_number > 0 &&
+	    doc2->priv->untitled_number != doc1->priv->untitled_number)
+	{
+		release_untitled_number (doc2->priv->untitled_number);
+		doc2->priv->untitled_number = doc1->priv->untitled_number;
+	}
+
+	doc2->priv->encoding = gedit_encoding_copy (doc1->priv->encoding);
+	doc2->priv->mtime = doc1->priv->mtime;
+	doc2->priv->time_of_last_save_or_load = doc1->priv->time_of_last_save_or_load;
+	doc2->priv->readonly = doc1->priv->readonly;
+	doc2->priv->last_save_was_manually = doc1->priv->last_save_was_manually;
+}
+
 /* ex:ts=8:noet: */
diff --git a/gedit/gedit-document.h b/gedit/gedit-document.h
index 6d31a46..8861a51 100644
--- a/gedit/gedit-document.h
+++ b/gedit/gedit-document.h
@@ -175,6 +175,8 @@ struct _GeditDocumentClass
 					(GeditDocument    *document,
 					 GtkTextIter      *start,
 					 GtkTextIter      *end);
+
+	void (* sync_docs)		(GeditDocument    *document);
 };
 
 
@@ -317,20 +319,23 @@ void		 gedit_document_set_metadata	(GeditDocument       *doc,
 /* 
  * Non exported functions
  */
-void		 _gedit_document_set_readonly 	(GeditDocument       *doc,
+void		_gedit_document_set_readonly	(GeditDocument       *doc,
 						 gboolean             readonly);
 
-glong		 _gedit_document_get_seconds_since_last_save_or_load 
+glong		_gedit_document_get_seconds_since_last_save_or_load
 						(GeditDocument       *doc);
 
 /* Note: this is a sync stat: use only on local files */
 gboolean	_gedit_document_check_externally_modified
 						(GeditDocument       *doc);
 
-void		_gedit_document_search_region   (GeditDocument       *doc,
+void		_gedit_document_search_region	(GeditDocument       *doc,
 						 const GtkTextIter   *start,
 						 const GtkTextIter   *end);
-						  
+
+void		_gedit_document_sync_documents	(GeditDocument       *doc1,
+						 GeditDocument       *doc2);
+
 /* Search macros */
 #define GEDIT_SEARCH_IS_DONT_SET_FLAGS(sflags) ((sflags & GEDIT_SEARCH_DONT_SET_FLAGS) != 0)
 #define GEDIT_SEARCH_SET_DONT_SET_FLAGS(sflags,state) ((state == TRUE) ? \
diff --git a/gedit/gedit-tab.c b/gedit/gedit-tab.c
index 6186d43..5e5bae6 100644
--- a/gedit/gedit-tab.c
+++ b/gedit/gedit-tab.c
@@ -44,6 +44,8 @@
 #include "gedit-debug.h"
 #include "gedit-enum-types.h"
 #include "gedit-settings.h"
+#include "gedit-marshal.h"
+#include "gedit-view-holder.h"
 
 #define GEDIT_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_TAB, GeditTabPrivate))
 
@@ -53,9 +55,8 @@ struct _GeditTabPrivate
 {
 	GSettings	       *editor;
 	GeditTabState	        state;
-	
-	GtkWidget	       *view;
-	GtkWidget	       *view_scrolled_window;
+
+	GeditViewHolder        *holder;
 
 	GtkWidget	       *info_bar;
 	GtkWidget	       *print_preview;
@@ -75,9 +76,9 @@ struct _GeditTabPrivate
 
 	GeditDocumentSaveFlags	save_flags;
 
-        gint                    auto_save_interval;
-        guint                   auto_save_timeout;
-        
+	gint                    auto_save_interval;
+	guint                   auto_save_timeout;
+
 	gint	                not_editable : 1;
 	gint                    auto_save : 1;
 
@@ -98,6 +99,7 @@ enum
 /* Signals */
 enum
 {
+	ACTIVE_VIEW_CHANGED,
 	DROP_URIS,
 	LAST_SIGNAL
 };
@@ -334,6 +336,18 @@ gedit_tab_class_init (GeditTabClass *klass)
 							   G_PARAM_READWRITE |
 							   G_PARAM_STATIC_STRINGS));
 
+	signals[ACTIVE_VIEW_CHANGED] =
+		g_signal_new ("active-view-changed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (GeditTabClass, active_view_changed),
+			      NULL, NULL,
+			      gedit_marshal_VOID__OBJECT_OBJECT,
+			      G_TYPE_NONE,
+			      2,
+			      GEDIT_TYPE_VIEW,
+			      GEDIT_TYPE_VIEW);
+
 	signals[DROP_URIS] =
 		g_signal_new ("drop-uris",
 			      G_TYPE_FROM_CLASS (object_class),
@@ -365,16 +379,9 @@ gedit_tab_get_state (GeditTab *tab)
 }
 
 static void
-set_cursor_according_to_state (GtkTextView   *view,
-			       GeditTabState  state)
+set_cursor_according_to_state (GeditViewHolder *holder,
+			       GeditTabState    state)
 {
-	GdkCursor *cursor;
-	GdkWindow *text_window;
-	GdkWindow *left_window;
-
-	text_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT);
-	left_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);
-
 	if ((state == GEDIT_TAB_STATE_LOADING)          ||
 	    (state == GEDIT_TAB_STATE_REVERTING)        ||
 	    (state == GEDIT_TAB_STATE_SAVING)           ||
@@ -382,29 +389,11 @@ set_cursor_according_to_state (GtkTextView   *view,
 	    (state == GEDIT_TAB_STATE_PRINT_PREVIEWING) ||
 	    (state == GEDIT_TAB_STATE_CLOSING))
 	{
-		cursor = gdk_cursor_new_for_display (
-				gtk_widget_get_display (GTK_WIDGET (view)),
-				GDK_WATCH);
-
-		if (text_window != NULL)
-			gdk_window_set_cursor (text_window, cursor);
-		if (left_window != NULL)
-			gdk_window_set_cursor (left_window, cursor);
-
-		gdk_cursor_unref (cursor);
+		gedit_view_holder_set_cursor (holder, GDK_WATCH);
 	}
 	else
 	{
-		cursor = gdk_cursor_new_for_display (
-				gtk_widget_get_display (GTK_WIDGET (view)),
-				GDK_XTERM);
-
-		if (text_window != NULL)
-			gdk_window_set_cursor (text_window, cursor);
-		if (left_window != NULL)
-			gdk_window_set_cursor (left_window, NULL);
-
-		gdk_cursor_unref (cursor);
+		gedit_view_holder_set_cursor (holder, GDK_XTERM);
 	}
 }
 
@@ -412,32 +401,43 @@ static void
 view_realized (GtkTextView *view,
 	       GeditTab    *tab)
 {
-	set_cursor_according_to_state (view, tab->priv->state);
+	set_cursor_according_to_state (tab->priv->holder, tab->priv->state);
 }
 
 static void
-set_view_properties_according_to_state (GeditTab      *tab,
-					GeditTabState  state)
+set_view_properties_according_to_state (GeditTab *tab)
 {
-	gboolean val;
+	GSList *frames, *l;
 	gboolean hl_current_line;
-	
+
 	hl_current_line = g_settings_get_boolean (tab->priv->editor,
-						  GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE);
+							  GEDIT_SETTINGS_HIGHLIGHT_CURRENT_LINE);
+
+	frames = gedit_view_holder_get_frames (tab->priv->holder);
+
+	for (l = frames; l != NULL; l = g_slist_next (l))
+	{
+		GeditViewFrame *frame = GEDIT_VIEW_FRAME (l->data);
+		GtkTextView *view;
+		gboolean val;
+
+		view = GTK_TEXT_VIEW (gedit_view_frame_get_view (frame));
 
-	val = ((state == GEDIT_TAB_STATE_NORMAL) &&
-	       (tab->priv->print_preview == NULL) &&
-	       !tab->priv->not_editable);
-	gtk_text_view_set_editable (GTK_TEXT_VIEW (tab->priv->view), val);
+		val = ((tab->priv->state == GEDIT_TAB_STATE_NORMAL) &&
+		       (tab->priv->print_preview == NULL) &&
+		       !tab->priv->not_editable);
+		gtk_text_view_set_editable (view, val);
 
-	val = ((state != GEDIT_TAB_STATE_LOADING) &&
-	       (state != GEDIT_TAB_STATE_CLOSING));
-	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (tab->priv->view), val);
+		val = ((tab->priv->state != GEDIT_TAB_STATE_LOADING) &&
+		       (tab->priv->state != GEDIT_TAB_STATE_CLOSING));
+		gtk_text_view_set_cursor_visible (view, val);
 
-	val = ((state != GEDIT_TAB_STATE_LOADING) &&
-	       (state != GEDIT_TAB_STATE_CLOSING) &&
-	       (hl_current_line));
-	gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (tab->priv->view), val);
+		val = ((tab->priv->state != GEDIT_TAB_STATE_LOADING) &&
+		       (tab->priv->state != GEDIT_TAB_STATE_CLOSING) &&
+		       (hl_current_line));
+		gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (view),
+							    val);
+	}
 }
 
 static void
@@ -452,23 +452,22 @@ gedit_tab_set_state (GeditTab      *tab,
 
 	tab->priv->state = state;
 
-	set_view_properties_according_to_state (tab, state);
+	set_view_properties_according_to_state (tab);
 
 	if ((state == GEDIT_TAB_STATE_LOADING_ERROR) || /* FIXME: add other states if needed */
-	    (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW))
+		    (state == GEDIT_TAB_STATE_SHOWING_PRINT_PREVIEW))
 	{
-		gtk_widget_hide (tab->priv->view_scrolled_window);
+		gtk_widget_hide (GTK_WIDGET (tab->priv->holder));
 	}
-	else
+	else if (tab->priv->print_preview == NULL)
 	{
-		if (tab->priv->print_preview == NULL)
-			gtk_widget_show (tab->priv->view_scrolled_window);
+		gtk_widget_show (GTK_WIDGET (tab->priv->holder));
 	}
 
-	set_cursor_according_to_state (GTK_TEXT_VIEW (tab->priv->view),
+	set_cursor_according_to_state (tab->priv->holder,
 				       state);
 
-	g_object_notify (G_OBJECT (tab), "state");		
+	g_object_notify (G_OBJECT (tab), "state");
 }
 
 static void 
@@ -497,6 +496,34 @@ static void
 document_modified_changed (GtkTextBuffer *document,
 			   GeditTab      *tab)
 {
+	GSList *frames, *l;
+	gboolean modified;
+
+	/* Sync all the docs */
+	modified = gtk_text_buffer_get_modified (document);
+
+	frames = gedit_view_holder_get_frames (tab->priv->holder);
+
+	for (l = frames; l != NULL; l = g_slist_next (l))
+	{
+		GeditViewFrame *frame = GEDIT_VIEW_FRAME (l->data);
+		GeditDocument *doc;
+
+		if (gedit_view_holder_get_active_frame (tab->priv->holder) == frame)
+			continue;
+
+		doc = gedit_view_frame_get_document (frame);
+
+		g_signal_handlers_block_by_func (doc,
+						 document_modified_changed,
+						 tab);
+		gtk_text_buffer_set_modified (GTK_TEXT_BUFFER (doc),
+					      modified);
+		g_signal_handlers_unblock_by_func (doc,
+						   document_modified_changed,
+						   tab);
+	}
+
 	g_object_notify (G_OBJECT (tab), "name");
 }
 
@@ -1070,9 +1097,6 @@ document_loaded (GeditDocument *document,
 			gtk_widget_show (emsg);
 		}
 
-		/* Scroll to the cursor when the document is loaded */
-		gedit_view_scroll_to_cursor (GEDIT_VIEW (tab->priv->view));
-
 		all_documents = gedit_app_get_documents (gedit_app_get_default ());
 
 		for (l = all_documents; l != NULL; l = g_list_next (l))
@@ -1553,80 +1577,21 @@ on_drop_uris (GeditView *view,
 	g_signal_emit (G_OBJECT (tab), signals[DROP_URIS], 0, uri_list);
 }
 
-static GMountOperation *
-tab_mount_operation_factory (GeditDocument *doc,
-			     gpointer       userdata)
-{
-	GeditTab *tab = GEDIT_TAB (userdata);
-	GtkWidget *window;
-
-	window = gtk_widget_get_toplevel (GTK_WIDGET (tab));
-	return gtk_mount_operation_new (GTK_WINDOW (window));
-}
-
 static void
-gedit_tab_init (GeditTab *tab)
+on_frame_added (GeditViewHolder *holder,
+		GeditViewFrame  *frame,
+		GeditTab        *tab)
 {
-	GtkWidget *sw;
 	GeditDocument *doc;
-	GeditLockdownMask lockdown;
-	gboolean auto_save;
-	gint auto_save_interval;
-
-	tab->priv = GEDIT_TAB_GET_PRIVATE (tab);
-
-	tab->priv->editor = g_settings_new ("org.gnome.gedit.preferences.editor");
-
-	tab->priv->state = GEDIT_TAB_STATE_NORMAL;
-
-	tab->priv->not_editable = FALSE;
-
-	tab->priv->save_flags = 0;
-
-	tab->priv->ask_if_externally_modified = TRUE;
-	
-	/* Create the scrolled window */
-	sw = gtk_scrolled_window_new (NULL, NULL);
-	tab->priv->view_scrolled_window = sw;
-
-	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-					GTK_POLICY_AUTOMATIC,
-					GTK_POLICY_AUTOMATIC);
-
-	/* Manage auto save data */
-	auto_save = g_settings_get_boolean (tab->priv->editor,
-					    GEDIT_SETTINGS_AUTO_SAVE);
-	g_settings_get (tab->priv->editor, GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
-			"u", &auto_save_interval);
-	
-	lockdown = gedit_app_get_lockdown (gedit_app_get_default ());
-	tab->priv->auto_save = auto_save &&
-			       !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK);
-	tab->priv->auto_save = (tab->priv->auto_save != FALSE);
+	GeditView *view;
 
-	tab->priv->auto_save_interval = auto_save_interval;
-	/* FIXME
-	if (tab->priv->auto_save_interval <= 0)
-		tab->priv->auto_save_interval = GPM_DEFAULT_AUTO_SAVE_INTERVAL;*/
+	gedit_debug (DEBUG_TAB);
 
-	/* Create the view */
-	doc = gedit_document_new ();
+	doc = gedit_view_frame_get_document (frame);
 	g_object_set_data (G_OBJECT (doc), GEDIT_TAB_KEY, tab);
 
-	_gedit_document_set_mount_operation_factory (doc,
-						     tab_mount_operation_factory,
-						     tab);
-
-	tab->priv->view = gedit_view_new (doc);
-	g_object_unref (doc);
-	gtk_widget_show (tab->priv->view);
-	g_object_set_data (G_OBJECT (tab->priv->view), GEDIT_TAB_KEY, tab);
-
-	gtk_box_pack_end (GTK_BOX (tab), sw, TRUE, TRUE, 0);
-	gtk_container_add (GTK_CONTAINER (sw), tab->priv->view);
-	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
-					     GTK_SHADOW_IN);	
-	gtk_widget_show (sw);
+	view = gedit_view_frame_get_view (frame);
+	g_object_set_data (G_OBJECT (view), GEDIT_TAB_KEY, tab);
 
 	g_signal_connect (doc,
 			  "notify::location",
@@ -1657,22 +1622,89 @@ gedit_tab_init (GeditTab *tab)
 			  G_CALLBACK (document_saved),
 			  tab);
 
-	g_signal_connect_after (tab->priv->view,
+	g_signal_connect_after (view,
 				"focus-in-event",
 				G_CALLBACK (view_focused_in),
 				tab);
-
-	g_signal_connect_after (tab->priv->view,
+	g_signal_connect_after (view,
 				"realize",
 				G_CALLBACK (view_realized),
 				tab);
-
-	g_signal_connect (tab->priv->view,
+	g_signal_connect (view,
 			  "drop-uris",
 			  G_CALLBACK (on_drop_uris),
 			  tab);
 }
 
+static void
+on_active_frame_changed (GeditViewHolder *holder,
+			 GeditViewFrame  *old_frame,
+			 GeditViewFrame  *new_frame,
+			 GeditTab        *tab)
+{
+	GeditView *old_view, *new_view;
+
+	old_view = gedit_view_frame_get_view (old_frame);
+	new_view = gedit_view_frame_get_view (new_frame);
+
+	g_signal_emit (G_OBJECT (tab), signals[ACTIVE_VIEW_CHANGED], 0,
+	               old_view, new_view);
+}
+
+static void
+gedit_tab_init (GeditTab *tab)
+{
+	GeditLockdownMask lockdown;
+	gboolean auto_save;
+	gint auto_save_interval;
+
+	tab->priv = GEDIT_TAB_GET_PRIVATE (tab);
+
+	tab->priv->editor = g_settings_new ("org.gnome.gedit.preferences.editor");
+
+	tab->priv->state = GEDIT_TAB_STATE_NORMAL;
+
+	tab->priv->not_editable = FALSE;
+
+	tab->priv->save_flags = 0;
+
+	tab->priv->ask_if_externally_modified = TRUE;
+
+	/* Manage auto save data */
+	auto_save = g_settings_get_boolean (tab->priv->editor,
+					    GEDIT_SETTINGS_AUTO_SAVE);
+	g_settings_get (tab->priv->editor, GEDIT_SETTINGS_AUTO_SAVE_INTERVAL,
+			"u", &auto_save_interval);
+	
+	lockdown = gedit_app_get_lockdown (gedit_app_get_default ());
+	tab->priv->auto_save = auto_save &&
+			       !(lockdown & GEDIT_LOCKDOWN_SAVE_TO_DISK);
+	tab->priv->auto_save = (tab->priv->auto_save != FALSE);
+
+	tab->priv->auto_save_interval = auto_save_interval;
+
+	/* Create the view holder */
+	tab->priv->holder = gedit_view_holder_new ();
+	gtk_widget_show (GTK_WIDGET (tab->priv->holder));
+
+	gtk_box_pack_end (GTK_BOX (tab), GTK_WIDGET (tab->priv->holder),
+			  TRUE, TRUE, 0);
+
+	g_signal_connect (tab->priv->holder,
+			  "frame-added",
+			  G_CALLBACK (on_frame_added),
+			  tab);
+	g_signal_connect (tab->priv->holder,
+			  "active-frame-changed",
+			  G_CALLBACK (on_active_frame_changed),
+			  tab);
+
+	/* Connect the signals for the active frame */
+	on_frame_added (tab->priv->holder,
+			gedit_view_holder_get_active_frame (tab->priv->holder),
+			tab);
+}
+
 GtkWidget *
 _gedit_tab_new (void)
 {
@@ -1737,9 +1769,13 @@ _gedit_tab_new_from_stream (GInputStream        *stream,
 GeditView *
 gedit_tab_get_view (GeditTab *tab)
 {
+	GeditViewFrame *frame;
+
 	g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
 
-	return GEDIT_VIEW (tab->priv->view);
+	frame = gedit_view_holder_get_active_frame (tab->priv->holder);
+
+	return gedit_view_frame_get_view (frame);
 }
 
 /**
@@ -1753,10 +1789,13 @@ gedit_tab_get_view (GeditTab *tab)
 GeditDocument *
 gedit_tab_get_document (GeditTab *tab)
 {
+	GeditViewFrame *frame;
+
 	g_return_val_if_fail (GEDIT_IS_TAB (tab), NULL);
 
-	return GEDIT_DOCUMENT (gtk_text_view_get_buffer (
-					GTK_TEXT_VIEW (tab->priv->view)));
+	frame = gedit_view_holder_get_active_frame (tab->priv->holder);
+
+	return gedit_view_frame_get_document (frame);
 }
 
 #define MAX_DOC_NAME_LENGTH 40
@@ -2951,4 +2990,29 @@ gedit_tab_set_info_bar (GeditTab  *tab,
 	set_info_bar (tab, info_bar);
 }
 
+void
+_gedit_tab_split (GeditTab       *tab,
+		  GtkOrientation  orientation)
+{
+	gedit_view_holder_split (tab->priv->holder, orientation);
+}
+
+void
+_gedit_tab_unsplit (GeditTab *tab)
+{
+	gedit_view_holder_unsplit (tab->priv->holder);
+}
+
+gboolean
+_gedit_tab_can_unsplit (GeditTab *tab)
+{
+	return gedit_view_holder_can_unsplit (tab->priv->holder);
+}
+
+gboolean
+_gedit_tab_can_split (GeditTab *tab)
+{
+	return gedit_view_holder_can_split (tab->priv->holder);
+}
+
 /* ex:ts=8:noet: */
diff --git a/gedit/gedit-tab.h b/gedit/gedit-tab.h
index 1b45989..a20401a 100644
--- a/gedit/gedit-tab.h
+++ b/gedit/gedit-tab.h
@@ -92,8 +92,12 @@ struct _GeditTabClass
 {
 	GtkVBoxClass parent_class;
 
-	void (* drop_uris)	(GeditView *view,
-				 gchar    **uri_list);
+	void (* active_view_changed) (GeditTab  *tab,
+	                              GeditView *old_view,
+	                              GeditView *new_view);
+
+	void (* drop_uris)           (GeditView *view,
+	                              gchar    **uri_list);
 };
 
 /*
@@ -175,6 +179,11 @@ void		 _gedit_tab_mark_for_closing	(GeditTab	     *tab);
 
 gboolean	 _gedit_tab_can_close		(GeditTab	     *tab);
 
+void		 _gedit_tab_unsplit		(GeditTab            *tab);
+gboolean	 _gedit_tab_can_unsplit		(GeditTab            *tab);
+gboolean	 _gedit_tab_can_split		(GeditTab            *tab);
+void		 _gedit_tab_split		(GeditTab            *tab,
+						 GtkOrientation       orientation);
 
 G_END_DECLS
 
diff --git a/gedit/gedit-ui.h b/gedit/gedit-ui.h
index 3477e32..baaee6a 100644
--- a/gedit/gedit-ui.h
+++ b/gedit/gedit-ui.h
@@ -106,6 +106,13 @@ static const GtkActionEntry gedit_menu_entries[] =
 
 	/* View menu */
 	{ "ViewHighlightMode", NULL, N_("_Highlight Mode") },
+	{ "ViewSplit", NULL, N_("S_plit") },
+	{ "SplitHorizontal", NULL, N_("Split _Horizontally"), NULL,
+	  N_("Split Horizontally"), G_CALLBACK (_gedit_cmd_view_split_horizontally) },
+	{ "SplitVertical", NULL, N_("Split _Vertically"), NULL,
+	  N_("Split Vertically"), G_CALLBACK (_gedit_cmd_view_split_vertically) },
+	{ "SplitUnsplit", NULL, N_("_Unsplit"), NULL,
+	  N_("Unsplit"), G_CALLBACK (_gedit_cmd_view_unsplit) },
 
 	/* Search menu */
 	{ "SearchFind", GTK_STOCK_FIND, N_("_Find..."), "<control>F",
diff --git a/gedit/gedit-ui.xml b/gedit/gedit-ui.xml
index a97e679..19abb3c 100644
--- a/gedit/gedit-ui.xml
+++ b/gedit/gedit-ui.xml
@@ -83,6 +83,13 @@
       <separator/>
       <menuitem name="ViewFullscreenMenu" action="ViewFullscreen"/>
       <separator/>
+      <menu name="ViewSplitMenu" action="ViewSplit">
+        <menuitem action="SplitHorizontal"/>
+        <menuitem action="SplitVertical"/>
+        <separator/>
+        <menuitem action="SplitUnsplit"/>
+      </menu>
+      <separator/>
       <menu name="ViewHighlightModeMenu" action="ViewHighlightMode">
         <placeholder name="LanguagesMenuPlaceholder">
         </placeholder>
diff --git a/gedit/gedit-undo-manager.c b/gedit/gedit-undo-manager.c
new file mode 100644
index 0000000..db3eb6b
--- /dev/null
+++ b/gedit/gedit-undo-manager.c
@@ -0,0 +1,1222 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gtksourceundomanager.c
+ * This file is part of GeditView
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005  Paolo Maggi
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gedit-undo-manager.h"
+#include <gtksourceview/gtksourceundomanager.h>
+
+#define DEFAULT_MAX_UNDO_LEVELS		-1
+
+/*
+ * The old code which used a GSList and g_slist_nth_element
+ * was way too slow for many operations (search/replace, hit Ctrl-Z,
+ * see gedit freezes). GSList was replaced with a GPtrArray with
+ * minimal changes to the code: to avoid insertions at the beginning
+ * of the array it uses array beginning as the list end and vice versa;
+ * hence bunch of ugly action_list_* functions.
+ * FIXME: so, somebody please rewrite this stuff using some nice data
+ * structures or something.
+ */
+
+typedef struct _GeditUndoAction  		GeditUndoAction;
+typedef struct _GeditUndoInsertAction		GeditUndoInsertAction;
+typedef struct _GeditUndoDeleteAction		GeditUndoDeleteAction;
+
+typedef enum
+{
+	GEDIT_UNDO_ACTION_INSERT,
+	GEDIT_UNDO_ACTION_DELETE
+} GeditUndoActionType;
+
+/*
+ * We use offsets instead of GtkTextIters because the last ones
+ * require to much memory in this context without giving us any advantage.
+ */
+
+struct _GeditUndoInsertAction
+{
+	gint   pos;
+	gchar *text;
+	gint   length;
+	gint   chars;
+};
+
+struct _GeditUndoDeleteAction
+{
+	gint   start;
+	gint   end;
+	gchar *text;
+	gboolean forward;
+};
+
+struct _GeditUndoAction
+{
+	GeditUndoActionType action_type;
+
+	union
+	{
+		GeditUndoInsertAction  insert;
+		GeditUndoDeleteAction  delete;
+	} action;
+
+	gint order_in_group;
+
+	/* It is TRUE whether the action can be merged with the following action. */
+	guint mergeable : 1;
+
+	/* It is TRUE whether the action is marked as "modified".
+	 * An action is marked as "modified" if it changed the
+	 * state of the buffer from "not modified" to "modified". Only the first
+	 * action of a group can be marked as modified.
+	 * There can be a single action marked as "modified" in the actions list.
+	 */
+	guint modified  : 1;
+};
+
+/* INVALID is a pointer to an invalid action */
+#define INVALID ((void *) "IA")
+
+enum
+{
+	INSERT_TEXT,
+	DELETE_RANGE,
+	BEGIN_USER_ACTION,
+	MODIFIED_CHANGED,
+	NUM_SIGNALS
+};
+
+struct _GeditUndoManagerPrivate
+{
+	GtkTextBuffer *buffer;
+
+	GPtrArray *actions;
+	gint next_redo;
+
+	gint actions_in_current_group;
+	gint running_not_undoable_actions;
+	gint num_of_groups;
+	gint max_undo_levels;
+
+	/* Pointer to the action (in the action list) marked as "modified".
+	 * It is NULL when no action is marked as "modified".
+	 * It is INVALID when the action marked as "modified" has been removed
+	 * from the action list (freeing the list or resizing it) */
+	GeditUndoAction *modified_action;
+
+	guint buffer_signals[NUM_SIGNALS];
+
+	guint can_undo : 1;
+	guint can_redo : 1;
+
+	/* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
+	 * the state of the buffer changed from "not modified" to "modified".
+	 */
+	guint modified_undoing_group : 1;
+};
+
+/* Properties */
+enum
+{
+	PROP_0,
+	PROP_BUFFER,
+	PROP_MAX_UNDO_LEVELS
+};
+
+static void insert_text_handler       (GtkTextBuffer         *buffer,
+                                       GtkTextIter           *pos,
+                                       const gchar           *text,
+                                       gint                   length,
+                                       GeditUndoManager      *um);
+
+static void delete_range_handler      (GtkTextBuffer         *buffer,
+                                       GtkTextIter           *start,
+                                       GtkTextIter           *end,
+                                       GeditUndoManager      *um);
+
+static void begin_user_action_handler (GtkTextBuffer         *buffer,
+                                       GeditUndoManager      *um);
+
+static void modified_changed_handler  (GtkTextBuffer         *buffer,
+                                       GeditUndoManager      *um);
+
+static void free_action_list          (GeditUndoManager      *um);
+
+static void add_action                (GeditUndoManager      *um,
+                                       const GeditUndoAction *undo_action);
+static void free_first_n_actions      (GeditUndoManager      *um,
+                                       gint                   n);
+static void check_list_size           (GeditUndoManager      *um);
+
+static gboolean merge_action          (GeditUndoManager      *um,
+                                       const GeditUndoAction *undo_action);
+
+static void gedit_undo_manager_iface_init (GtkSourceUndoManagerIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GeditUndoManager, gedit_undo_manager, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GTK_TYPE_SOURCE_UNDO_MANAGER,
+                                                gedit_undo_manager_iface_init))
+
+static void
+gedit_undo_manager_finalize (GObject *object)
+{
+	GeditUndoManager *manager;
+
+	manager = GEDIT_UNDO_MANAGER (object);
+
+	free_action_list (manager);
+	g_ptr_array_free (manager->priv->actions, TRUE);
+
+	G_OBJECT_CLASS (gedit_undo_manager_parent_class)->finalize (object);
+}
+
+static void
+clear_undo (GeditUndoManager *manager)
+{
+	free_action_list (manager);
+
+	manager->priv->next_redo = -1;
+
+	if (manager->priv->can_undo)
+	{
+		manager->priv->can_undo = FALSE;
+		gtk_source_undo_manager_can_undo_changed (GTK_SOURCE_UNDO_MANAGER (manager));
+	}
+
+	if (manager->priv->can_redo)
+	{
+		manager->priv->can_redo = FALSE;
+		gtk_source_undo_manager_can_redo_changed (GTK_SOURCE_UNDO_MANAGER (manager));
+	}
+}
+
+static void
+buffer_notify (GeditUndoManager *manager,
+               gpointer          where_the_object_was)
+{
+	manager->priv->buffer = NULL;
+}
+
+static void
+set_buffer (GeditUndoManager *manager,
+            GtkTextBuffer    *buffer)
+{
+	if (buffer == manager->priv->buffer)
+	{
+		return;
+	}
+
+	if (manager->priv->buffer != NULL)
+	{
+		gint i;
+
+		for (i = 0; i < NUM_SIGNALS; ++i)
+		{
+			g_signal_handler_disconnect (manager->priv->buffer,
+			                             manager->priv->buffer_signals[i]);
+		}
+
+		g_object_weak_unref (G_OBJECT (manager->priv->buffer),
+		                     (GWeakNotify)buffer_notify,
+		                     manager);
+		manager->priv->buffer = NULL;
+	}
+
+	if (buffer != NULL)
+	{
+		manager->priv->buffer = buffer;
+		g_object_weak_ref (G_OBJECT (buffer),
+		                   (GWeakNotify)buffer_notify,
+		                   manager);
+
+		manager->priv->buffer_signals[INSERT_TEXT] =
+			g_signal_connect (buffer,
+			                  "insert-text",
+			                  G_CALLBACK (insert_text_handler),
+			                  manager);
+
+		manager->priv->buffer_signals[DELETE_RANGE] =
+			g_signal_connect (buffer,
+			                  "delete-range",
+			                  G_CALLBACK (delete_range_handler),
+			                  manager);
+
+		manager->priv->buffer_signals[BEGIN_USER_ACTION] =
+			g_signal_connect (buffer,
+			                  "begin-user-action",
+			                  G_CALLBACK (begin_user_action_handler),
+			                  manager);
+
+		manager->priv->buffer_signals[MODIFIED_CHANGED] =
+			g_signal_connect (buffer,
+			                  "modified-changed",
+			                  G_CALLBACK (modified_changed_handler),
+			                  manager);
+	}
+}
+
+static void
+set_max_undo_levels (GeditUndoManager *manager,
+                     gint              max_undo_levels)
+{
+	gint old_levels;
+
+	old_levels = manager->priv->max_undo_levels;
+	manager->priv->max_undo_levels = max_undo_levels;
+
+	if (max_undo_levels < 1)
+		return;
+
+	if (old_levels > max_undo_levels)
+	{
+		/* strip redo actions first */
+		while (manager->priv->next_redo >= 0 &&
+		       (manager->priv->num_of_groups > max_undo_levels))
+		{
+			free_first_n_actions (manager, 1);
+			manager->priv->next_redo--;
+		}
+
+		/* now remove undo actions if necessary */
+		check_list_size (manager);
+
+		/* emit "can_undo" and/or "can_redo" if appropiate */
+		if (manager->priv->next_redo < 0 && manager->priv->can_redo)
+		{
+			manager->priv->can_redo = FALSE;
+			gtk_source_undo_manager_can_redo_changed (GTK_SOURCE_UNDO_MANAGER (manager));
+		}
+
+		if (manager->priv->can_undo &&
+		    manager->priv->next_redo >= (gint)manager->priv->actions->len - 1)
+		{
+			manager->priv->can_undo = FALSE;
+			gtk_source_undo_manager_can_undo_changed (GTK_SOURCE_UNDO_MANAGER (manager));
+		}
+	}
+}
+
+static void
+gedit_undo_manager_dispose (GObject *object)
+{
+	GeditUndoManager *manager;
+
+	manager = GEDIT_UNDO_MANAGER (object);
+
+	if (manager->priv->buffer != NULL)
+	{
+		/* Clear the buffer */
+		set_buffer (manager, NULL);
+	}
+
+	G_OBJECT_CLASS (gedit_undo_manager_parent_class)->dispose (object);
+}
+
+static void
+gedit_undo_manager_set_property (GObject      *object,
+                                 guint         prop_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+	GeditUndoManager *self = GEDIT_UNDO_MANAGER (object);
+	GtkTextBuffer *buffer;
+	
+	switch (prop_id)
+	{
+		case PROP_BUFFER:
+			buffer = g_value_get_object (value);
+		
+			if (GTK_IS_TEXT_BUFFER (buffer))
+			{
+				set_buffer (self, buffer);
+			}
+		break;
+		case PROP_MAX_UNDO_LEVELS:
+			gedit_undo_manager_set_max_undo_levels (self,
+			                                        g_value_get_int (value));
+		break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gedit_undo_manager_get_property (GObject    *object,
+                                 guint       prop_id,
+                                 GValue     *value,
+                                 GParamSpec *pspec)
+{
+	GeditUndoManager *self = GEDIT_UNDO_MANAGER (object);
+	
+	switch (prop_id)
+	{
+		case PROP_BUFFER:
+			g_value_set_object (value, self->priv->buffer);
+		break;
+		case PROP_MAX_UNDO_LEVELS:
+			g_value_set_int (value, self->priv->max_undo_levels);
+		break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gedit_undo_manager_class_init (GeditUndoManagerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = gedit_undo_manager_finalize;
+	object_class->dispose = gedit_undo_manager_dispose;
+
+	object_class->set_property = gedit_undo_manager_set_property;
+	object_class->get_property = gedit_undo_manager_get_property;
+
+	g_object_class_install_property (object_class,
+	                                 PROP_BUFFER,
+	                                 g_param_spec_object ("buffer",
+	                                                      _("Buffer"),
+	                                                      _("The text buffer to add undo support on"),
+	                                                      GTK_TYPE_TEXT_BUFFER,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class,
+	                                 PROP_MAX_UNDO_LEVELS,
+	                                 g_param_spec_int ("max-undo-levels",
+	                                                   _("Maximum Undo Levels"),
+	                                                   _("Number of undo levels for "
+	                                                     "the buffer"),
+	                                                   -1,
+	                                                   G_MAXINT,
+	                                                   DEFAULT_MAX_UNDO_LEVELS,
+	                                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+	g_type_class_add_private (object_class, sizeof (GeditUndoManagerPrivate));
+}
+
+static void
+gedit_undo_manager_init (GeditUndoManager *um)
+{
+	um->priv = G_TYPE_INSTANCE_GET_PRIVATE (um, GEDIT_TYPE_UNDO_MANAGER,
+	                                        GeditUndoManagerPrivate);
+
+	um->priv->actions = g_ptr_array_new ();
+}
+
+static void
+end_not_undoable_action_internal (GeditUndoManager *manager)
+{
+	g_return_if_fail (manager->priv->running_not_undoable_actions > 0);
+
+	--manager->priv->running_not_undoable_actions;
+}
+
+/* Interface implementations */
+static void
+gedit_undo_manager_begin_not_undoable_action_impl (GtkSourceUndoManager *manager)
+{
+	GeditUndoManager *manager_default;
+
+	manager_default = GEDIT_UNDO_MANAGER (manager);
+	++manager_default->priv->running_not_undoable_actions;
+}
+
+static void
+gedit_undo_manager_end_not_undoable_action_impl (GtkSourceUndoManager *manager)
+{
+	GeditUndoManager *manager_default;
+
+	manager_default = GEDIT_UNDO_MANAGER (manager);
+	end_not_undoable_action_internal (manager_default);
+
+	if (manager_default->priv->running_not_undoable_actions == 0)
+	{
+		clear_undo (manager_default);
+	}
+}
+
+static gboolean
+gedit_undo_manager_can_undo_impl (GtkSourceUndoManager *manager)
+{
+	return GEDIT_UNDO_MANAGER (manager)->priv->can_undo;
+}
+
+static gboolean
+gedit_undo_manager_can_redo_impl (GtkSourceUndoManager *manager)
+{
+	return GEDIT_UNDO_MANAGER (manager)->priv->can_redo;
+}
+
+static void
+set_cursor (GtkTextBuffer *buffer,
+            gint           cursor)
+{
+	GtkTextIter iter;
+
+	/* Place the cursor at the requested position */
+	gtk_text_buffer_get_iter_at_offset (buffer, &iter, cursor);
+	gtk_text_buffer_place_cursor (buffer, &iter);
+}
+
+static void
+insert_text (GtkTextBuffer *buffer,
+             gint           pos,
+             const gchar   *text,
+             gint           len)
+{
+	GtkTextIter iter;
+
+	gtk_text_buffer_get_iter_at_offset (buffer, &iter, pos);
+	gtk_text_buffer_insert (buffer, &iter, text, len);
+}
+
+static void
+delete_text (GtkTextBuffer *buffer,
+             gint           start,
+             gint           end)
+{
+	GtkTextIter start_iter;
+	GtkTextIter end_iter;
+
+	gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+
+	if (end < 0)
+		gtk_text_buffer_get_end_iter (buffer, &end_iter);
+	else
+		gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+	gtk_text_buffer_delete (buffer, &start_iter, &end_iter);
+}
+
+static gchar *
+get_chars (GtkTextBuffer *buffer,
+           gint           start,
+           gint           end)
+{
+	GtkTextIter start_iter;
+	GtkTextIter end_iter;
+
+	gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+
+	if (end < 0)
+		gtk_text_buffer_get_end_iter (buffer, &end_iter);
+	else
+		gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+	return gtk_text_buffer_get_slice (buffer, &start_iter, &end_iter, TRUE);
+}
+
+static GeditUndoAction *
+action_list_nth_data (GPtrArray *array,
+                      gint       n)
+{
+	if (n < 0 || n >= (gint)array->len)
+		return NULL;
+	else
+		return array->pdata[array->len - 1 - n];
+}
+
+static void
+action_list_prepend (GPtrArray           *array,
+                     GeditUndoAction *action)
+{
+	g_ptr_array_add (array, action);
+}
+
+static GeditUndoAction *
+action_list_last_data (GPtrArray *array)
+{
+	if (array->len != 0)
+		return array->pdata[0];
+	else
+		return NULL;
+}
+
+static void
+action_list_delete_last (GPtrArray *array)
+{
+	if (array->len != 0)
+	{
+		memmove (&array->pdata[0], &array->pdata[1], (array->len - 1)*sizeof (gpointer));
+		g_ptr_array_set_size (array, array->len - 1);
+	}
+}
+
+static void
+gedit_undo_manager_undo_impl (GtkSourceUndoManager *manager)
+{
+	GeditUndoManager *manager_default;
+	GeditUndoAction *undo_action;
+	gboolean modified = FALSE;
+	gint cursor_pos = -1;
+
+	manager_default = GEDIT_UNDO_MANAGER (manager);
+
+	g_return_if_fail (manager_default->priv->can_undo);
+
+	manager_default->priv->modified_undoing_group = FALSE;
+
+	gtk_source_undo_manager_begin_not_undoable_action (manager);
+
+	do
+	{
+		undo_action = action_list_nth_data (manager_default->priv->actions,
+		                                    manager_default->priv->next_redo + 1);
+
+		g_return_if_fail (undo_action != NULL);
+
+		/* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */
+		g_return_if_fail ((undo_action->order_in_group <= 1) ||
+				  ((undo_action->order_in_group > 1) && !undo_action->modified));
+
+		if (undo_action->order_in_group <= 1)
+		{
+			/* Set modified to TRUE only if the buffer did not change its state from
+			 * "not modified" to "modified" undoing an action (with order_in_group > 1)
+			 * in current group. */
+			modified = (undo_action->modified &&
+			            !manager_default->priv->modified_undoing_group);
+		}
+
+		switch (undo_action->action_type)
+		{
+			case GEDIT_UNDO_ACTION_DELETE:
+				insert_text (manager_default->priv->buffer,
+				             undo_action->action.delete.start,
+				             undo_action->action.delete.text,
+				             strlen (undo_action->action.delete.text));
+
+				if (undo_action->action.delete.forward)
+					cursor_pos = undo_action->action.delete.start;
+				else
+					cursor_pos = undo_action->action.delete.end;
+
+				break;
+
+			case GEDIT_UNDO_ACTION_INSERT:
+				delete_text (manager_default->priv->buffer,
+				             undo_action->action.insert.pos,
+				             undo_action->action.insert.pos +
+				             undo_action->action.insert.chars);
+
+				cursor_pos = undo_action->action.insert.pos;
+				break;
+
+			default:
+				/* Unknown action type. */
+				g_return_if_reached ();
+		}
+
+		++manager_default->priv->next_redo;
+
+	} while (undo_action->order_in_group > 1);
+
+	if (cursor_pos >= 0)
+		set_cursor (manager_default->priv->buffer, cursor_pos);
+
+	if (modified)
+	{
+		--manager_default->priv->next_redo;
+		gtk_text_buffer_set_modified (manager_default->priv->buffer, FALSE);
+		++manager_default->priv->next_redo;
+	}
+
+	/* FIXME: why does this call the internal one ? */
+	end_not_undoable_action_internal (manager_default);
+
+	manager_default->priv->modified_undoing_group = FALSE;
+
+	if (!manager_default->priv->can_redo)
+	{
+		manager_default->priv->can_redo = TRUE;
+		gtk_source_undo_manager_can_redo_changed (manager);
+	}
+
+	if (manager_default->priv->next_redo >= (gint)manager_default->priv->actions->len - 1)
+	{
+		manager_default->priv->can_undo = FALSE;
+		gtk_source_undo_manager_can_undo_changed (manager);
+	}
+}
+
+static void
+gedit_undo_manager_redo_impl (GtkSourceUndoManager *manager)
+{
+	GeditUndoManager *manager_default;
+	GeditUndoAction *undo_action;
+	gboolean modified = FALSE;
+	gint cursor_pos = -1;
+
+	manager_default = GEDIT_UNDO_MANAGER (manager);
+
+	g_return_if_fail (manager_default->priv->can_redo);
+
+	undo_action = action_list_nth_data (manager_default->priv->actions,
+	                                    manager_default->priv->next_redo);
+	g_return_if_fail (undo_action != NULL);
+
+	gtk_source_undo_manager_begin_not_undoable_action (manager);
+
+	do
+	{
+		if (undo_action->modified)
+		{
+			g_return_if_fail (undo_action->order_in_group <= 1);
+			modified = TRUE;
+		}
+
+		--manager_default->priv->next_redo;
+
+		switch (undo_action->action_type)
+		{
+			case GEDIT_UNDO_ACTION_DELETE:
+				delete_text (manager_default->priv->buffer,
+				             undo_action->action.delete.start,
+				             undo_action->action.delete.end);
+
+				cursor_pos = undo_action->action.delete.start;
+
+				break;
+
+			case GEDIT_UNDO_ACTION_INSERT:
+				cursor_pos = undo_action->action.insert.pos +
+				             undo_action->action.insert.length;
+
+				insert_text (manager_default->priv->buffer,
+				             undo_action->action.insert.pos,
+				             undo_action->action.insert.text,
+				             undo_action->action.insert.length);
+
+				break;
+
+			default:
+				/* Unknown action type */
+				++manager_default->priv->next_redo;
+				g_return_if_reached ();
+		}
+
+		if (manager_default->priv->next_redo < 0)
+			undo_action = NULL;
+		else
+			undo_action = action_list_nth_data (manager_default->priv->actions,
+			                                    manager_default->priv->next_redo);
+
+	} while ((undo_action != NULL) && (undo_action->order_in_group > 1));
+
+	if (cursor_pos >= 0)
+		set_cursor (manager_default->priv->buffer, cursor_pos);
+
+	if (modified)
+	{
+		++manager_default->priv->next_redo;
+		gtk_text_buffer_set_modified (manager_default->priv->buffer, FALSE);
+		--manager_default->priv->next_redo;
+	}
+
+	/* FIXME: why is this only internal ?*/
+	end_not_undoable_action_internal (manager_default);
+
+	if (manager_default->priv->next_redo < 0)
+	{
+		manager_default->priv->can_redo = FALSE;
+		gtk_source_undo_manager_can_redo_changed (manager);
+	}
+
+	if (!manager_default->priv->can_undo)
+	{
+		manager_default->priv->can_undo = TRUE;
+		gtk_source_undo_manager_can_undo_changed (manager);
+	}
+}
+
+static void
+gedit_undo_action_free (GeditUndoAction *action)
+{
+	if (action == NULL)
+		return;
+
+	if (action->action_type == GEDIT_UNDO_ACTION_INSERT)
+		g_free (action->action.insert.text);
+	else if (action->action_type == GEDIT_UNDO_ACTION_DELETE)
+		g_free (action->action.delete.text);
+	else
+		g_return_if_reached ();
+
+	g_free (action);
+}
+
+static void
+free_action_list (GeditUndoManager *um)
+{
+	gint i;
+
+	for (i = (gint)um->priv->actions->len - 1; i >= 0; i--)
+	{
+		GeditUndoAction *action = um->priv->actions->pdata[i];
+
+		if (action->order_in_group == 1)
+			--um->priv->num_of_groups;
+
+		if (action->modified)
+			um->priv->modified_action = INVALID;
+
+		gedit_undo_action_free (action);
+	}
+
+	/* Some arbitrary limit, to avoid wasting space */
+	if (um->priv->actions->len > 2048)
+	{
+		g_ptr_array_free (um->priv->actions, TRUE);
+		um->priv->actions = g_ptr_array_new ();
+	}
+	else
+	{
+		g_ptr_array_set_size (um->priv->actions, 0);
+	}
+}
+
+static void
+insert_text_handler (GtkTextBuffer               *buffer,
+                     GtkTextIter                 *pos,
+                     const gchar                 *text,
+                     gint                         length,
+                     GeditUndoManager *manager)
+{
+	GeditUndoAction undo_action;
+
+	if (manager->priv->running_not_undoable_actions > 0)
+		return;
+
+	undo_action.action_type = GEDIT_UNDO_ACTION_INSERT;
+
+	undo_action.action.insert.pos    = gtk_text_iter_get_offset (pos);
+	undo_action.action.insert.text   = (gchar*) text;
+	undo_action.action.insert.length = length;
+	undo_action.action.insert.chars  = g_utf8_strlen (text, length);
+
+	if ((undo_action.action.insert.chars > 1) || (g_utf8_get_char (text) == '\n'))
+
+		undo_action.mergeable = FALSE;
+	else
+		undo_action.mergeable = TRUE;
+
+	undo_action.modified = FALSE;
+
+	add_action (manager, &undo_action);
+}
+
+static void
+delete_range_handler (GtkTextBuffer               *buffer,
+                      GtkTextIter                 *start,
+                      GtkTextIter                 *end,
+                      GeditUndoManager *um)
+{
+	GeditUndoAction undo_action;
+	GtkTextIter insert_iter;
+
+	if (um->priv->running_not_undoable_actions > 0)
+		return;
+
+	undo_action.action_type = GEDIT_UNDO_ACTION_DELETE;
+
+	gtk_text_iter_order (start, end);
+
+	undo_action.action.delete.start  = gtk_text_iter_get_offset (start);
+	undo_action.action.delete.end    = gtk_text_iter_get_offset (end);
+
+	undo_action.action.delete.text   = get_chars (
+						buffer,
+						undo_action.action.delete.start,
+						undo_action.action.delete.end);
+
+	/* figure out if the user used the Delete or the Backspace key */
+	gtk_text_buffer_get_iter_at_mark (buffer, &insert_iter,
+					  gtk_text_buffer_get_insert (buffer));
+	if (gtk_text_iter_get_offset (&insert_iter) <= undo_action.action.delete.start)
+		undo_action.action.delete.forward = TRUE;
+	else
+		undo_action.action.delete.forward = FALSE;
+
+	if (((undo_action.action.delete.end - undo_action.action.delete.start) > 1) ||
+	     (g_utf8_get_char (undo_action.action.delete.text  ) == '\n'))
+		undo_action.mergeable = FALSE;
+	else
+		undo_action.mergeable = TRUE;
+
+	undo_action.modified = FALSE;
+
+	add_action (um, &undo_action);
+
+	g_free (undo_action.action.delete.text);
+
+}
+
+static void
+begin_user_action_handler (GtkTextBuffer    *buffer,
+                           GeditUndoManager *um)
+{
+	if (um->priv->running_not_undoable_actions > 0)
+		return;
+
+	um->priv->actions_in_current_group = 0;
+}
+
+static void
+add_action (GeditUndoManager      *um,
+            const GeditUndoAction *undo_action)
+{
+	GeditUndoAction* action;
+
+	if (um->priv->next_redo >= 0)
+	{
+		free_first_n_actions (um, um->priv->next_redo + 1);
+	}
+
+	um->priv->next_redo = -1;
+
+	if (!merge_action (um, undo_action))
+	{
+		action = g_new (GeditUndoAction, 1);
+		*action = *undo_action;
+
+		if (action->action_type == GEDIT_UNDO_ACTION_INSERT)
+			action->action.insert.text = g_strndup (undo_action->action.insert.text, undo_action->action.insert.length);
+		else if (action->action_type == GEDIT_UNDO_ACTION_DELETE)
+			action->action.delete.text = g_strdup (undo_action->action.delete.text);
+		else
+		{
+			g_free (action);
+			g_return_if_reached ();
+		}
+
+		++um->priv->actions_in_current_group;
+		action->order_in_group = um->priv->actions_in_current_group;
+
+		if (action->order_in_group == 1)
+			++um->priv->num_of_groups;
+
+		action_list_prepend (um->priv->actions, action);
+	}
+
+	check_list_size (um);
+
+	if (!um->priv->can_undo)
+	{
+		um->priv->can_undo = TRUE;
+		gtk_source_undo_manager_can_undo_changed (GTK_SOURCE_UNDO_MANAGER (um));
+	}
+
+	if (um->priv->can_redo)
+	{
+		um->priv->can_redo = FALSE;
+		gtk_source_undo_manager_can_redo_changed (GTK_SOURCE_UNDO_MANAGER (um));
+	}
+}
+
+static void
+free_first_n_actions (GeditUndoManager *um,
+                      gint              n)
+{
+	gint i;
+
+	if (um->priv->actions->len == 0)
+		return;
+
+	for (i = 0; i < n; i++)
+	{
+		GeditUndoAction *action = um->priv->actions->pdata[um->priv->actions->len - 1];
+
+		if (action->order_in_group == 1)
+			--um->priv->num_of_groups;
+
+		if (action->modified)
+			um->priv->modified_action = INVALID;
+
+		gedit_undo_action_free (action);
+
+		g_ptr_array_set_size (um->priv->actions, um->priv->actions->len - 1);
+
+		if (um->priv->actions->len == 0)
+			return;
+	}
+}
+
+static void
+check_list_size (GeditUndoManager *um)
+{
+	gint undo_levels;
+
+	undo_levels = um->priv->max_undo_levels;
+
+	if (undo_levels < 1)
+		return;
+
+	if (um->priv->num_of_groups > undo_levels)
+	{
+		GeditUndoAction *undo_action;
+
+		undo_action = action_list_last_data (um->priv->actions);
+
+		do
+		{
+			if (undo_action->order_in_group == 1)
+				--um->priv->num_of_groups;
+
+			if (undo_action->modified)
+				um->priv->modified_action = INVALID;
+
+			gedit_undo_action_free (undo_action);
+
+			action_list_delete_last (um->priv->actions);
+
+			undo_action = action_list_last_data (um->priv->actions);
+			g_return_if_fail (undo_action != NULL);
+
+		} while ((undo_action->order_in_group > 1) ||
+			 (um->priv->num_of_groups > undo_levels));
+	}
+}
+
+/**
+ * gedit_undo_manager_merge_action:
+ * @um: a #GeditUndoManager.
+ * @undo_action: a #GeditUndoAction.
+ *
+ * This function tries to merge the undo action at the top of
+ * the stack with a new undo action. So when we undo for example
+ * typing, we can undo the whole word and not each letter by itself.
+ *
+ * Return Value: %TRUE is merge was sucessful, %FALSE otherwise.
+ **/
+static gboolean
+merge_action (GeditUndoManager      *um,
+              const GeditUndoAction *undo_action)
+{
+	GeditUndoAction *last_action;
+
+	g_return_val_if_fail (GTK_IS_SOURCE_UNDO_MANAGER (um), FALSE);
+	g_return_val_if_fail (um->priv != NULL, FALSE);
+
+	if (um->priv->actions->len == 0)
+		return FALSE;
+
+	last_action = action_list_nth_data (um->priv->actions, 0);
+
+	if (!last_action->mergeable)
+		return FALSE;
+
+	if ((!undo_action->mergeable) ||
+	    (undo_action->action_type != last_action->action_type))
+	{
+		last_action->mergeable = FALSE;
+		return FALSE;
+	}
+
+	if (undo_action->action_type == GEDIT_UNDO_ACTION_DELETE)
+	{
+		if ((last_action->action.delete.forward != undo_action->action.delete.forward) ||
+		    ((last_action->action.delete.start != undo_action->action.delete.start) &&
+		     (last_action->action.delete.start != undo_action->action.delete.end)))
+		{
+			last_action->mergeable = FALSE;
+			return FALSE;
+		}
+
+		if (last_action->action.delete.start == undo_action->action.delete.start)
+		{
+			gchar *str;
+
+#define L  (last_action->action.delete.end - last_action->action.delete.start - 1)
+#define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
+
+			/* Deleted with the delete key */
+			if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
+			    (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
+                            ((g_utf8_get_char_at (last_action->action.delete.text, L) == ' ') ||
+			     (g_utf8_get_char_at (last_action->action.delete.text, L)  == '\t')))
+			{
+				last_action->mergeable = FALSE;
+				return FALSE;
+			}
+
+			str = g_strdup_printf ("%s%s", last_action->action.delete.text,
+				undo_action->action.delete.text);
+
+			g_free (last_action->action.delete.text);
+			last_action->action.delete.end += (undo_action->action.delete.end -
+							   undo_action->action.delete.start);
+			last_action->action.delete.text = str;
+		}
+		else
+		{
+			gchar *str;
+
+			/* Deleted with the backspace key */
+			if ((g_utf8_get_char (undo_action->action.delete.text) != ' ') &&
+			    (g_utf8_get_char (undo_action->action.delete.text) != '\t') &&
+                            ((g_utf8_get_char (last_action->action.delete.text) == ' ') ||
+			     (g_utf8_get_char (last_action->action.delete.text) == '\t')))
+			{
+				last_action->mergeable = FALSE;
+				return FALSE;
+			}
+
+			str = g_strdup_printf ("%s%s", undo_action->action.delete.text,
+				last_action->action.delete.text);
+
+			g_free (last_action->action.delete.text);
+			last_action->action.delete.start = undo_action->action.delete.start;
+			last_action->action.delete.text = str;
+		}
+	}
+	else if (undo_action->action_type == GEDIT_UNDO_ACTION_INSERT)
+	{
+		gchar* str;
+
+#define I (last_action->action.insert.chars - 1)
+
+		if ((undo_action->action.insert.pos !=
+		     	(last_action->action.insert.pos + last_action->action.insert.chars)) ||
+		    ((g_utf8_get_char (undo_action->action.insert.text) != ' ') &&
+		      (g_utf8_get_char (undo_action->action.insert.text) != '\t') &&
+		     ((g_utf8_get_char_at (last_action->action.insert.text, I) == ' ') ||
+		      (g_utf8_get_char_at (last_action->action.insert.text, I) == '\t')))
+		   )
+		{
+			last_action->mergeable = FALSE;
+			return FALSE;
+		}
+
+		str = g_strdup_printf ("%s%s", last_action->action.insert.text,
+				undo_action->action.insert.text);
+
+		g_free (last_action->action.insert.text);
+		last_action->action.insert.length += undo_action->action.insert.length;
+		last_action->action.insert.text = str;
+		last_action->action.insert.chars += undo_action->action.insert.chars;
+
+	}
+	else
+		/* Unknown action inside undo merge encountered */
+		g_return_val_if_reached (TRUE);
+
+	return TRUE;
+}
+
+static void
+modified_changed_handler (GtkTextBuffer    *buffer,
+                          GeditUndoManager *manager)
+{
+	GeditUndoAction *action;
+	gint idx;
+
+	if (manager->priv->actions->len == 0)
+		return;
+
+	idx = manager->priv->next_redo + 1;
+	action = action_list_nth_data (manager->priv->actions, idx);
+
+	if (gtk_text_buffer_get_modified (buffer) == FALSE)
+	{
+		if (action != NULL)
+			action->mergeable = FALSE;
+
+		if (manager->priv->modified_action != NULL)
+		{
+			if (manager->priv->modified_action != INVALID)
+				manager->priv->modified_action->modified = FALSE;
+
+			manager->priv->modified_action = NULL;
+		}
+
+		return;
+	}
+
+	if (action == NULL)
+	{
+		g_return_if_fail (manager->priv->running_not_undoable_actions > 0);
+
+		return;
+	}
+
+	if (manager->priv->modified_action != NULL)
+	{
+		g_message ("%s: oops", G_STRLOC);
+		return;
+	}
+
+	if (action->order_in_group > 1)
+		manager->priv->modified_undoing_group  = TRUE;
+
+	while (action->order_in_group > 1)
+	{
+		action = action_list_nth_data (manager->priv->actions, ++idx);
+		g_return_if_fail (action != NULL);
+	}
+
+	action->modified = TRUE;
+	manager->priv->modified_action = action;
+}
+
+static void
+gedit_undo_manager_iface_init (GtkSourceUndoManagerIface *iface)
+{
+	iface->can_undo = gedit_undo_manager_can_undo_impl;
+	iface->can_redo = gedit_undo_manager_can_redo_impl;
+
+	iface->undo = gedit_undo_manager_undo_impl;
+	iface->redo = gedit_undo_manager_redo_impl;
+
+	iface->begin_not_undoable_action = gedit_undo_manager_begin_not_undoable_action_impl;
+	iface->end_not_undoable_action = gedit_undo_manager_end_not_undoable_action_impl;
+}
+
+GtkSourceUndoManager *
+gedit_undo_manager_new (GtkSourceBuffer *buffer)
+{
+	return GTK_SOURCE_UNDO_MANAGER (g_object_new (GEDIT_TYPE_UNDO_MANAGER,
+					"buffer", buffer,
+					NULL));
+}
+
+void
+gedit_undo_manager_set_max_undo_levels (GeditUndoManager *manager,
+                                        gint              max_undo_levels)
+{
+	g_return_if_fail (GTK_IS_SOURCE_UNDO_MANAGER (manager));
+
+	set_max_undo_levels (manager, max_undo_levels);
+	g_object_notify (G_OBJECT (manager), "max-undo-levels");
+}
diff --git a/gedit/gedit-undo-manager.h b/gedit/gedit-undo-manager.h
new file mode 100644
index 0000000..f84804c
--- /dev/null
+++ b/gedit/gedit-undo-manager.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gedit-undo-manager.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002, 2003 Paolo Maggi
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GEDIT_UNDO_MANAGER_H__
+#define __GEDIT_UNDO_MANAGER_H__
+
+#include <glib-object.h>
+#include <gtksourceview/gtksourcebuffer.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_UNDO_MANAGER			(gedit_undo_manager_get_type ())
+#define GEDIT_UNDO_MANAGER(obj)			(G_TYPE_CHECK_INSTANCE_CAST((obj), GEDIT_TYPE_UNDO_MANAGER, GeditUndoManager))
+#define GEDIT_UNDO_MANAGER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), GEDIT_TYPE_UNDO_MANAGER, GeditUndoManagerClass))
+#define GEDIT_IS_UNDO_MANAGER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_UNDO_MANAGER))
+#define GEDIT_IS_UNDO_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_UNDO_MANAGER))
+#define GEDIT_UNDO_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_UNDO_MANAGER, GeditUndoManagerClass))
+
+typedef struct _GeditUndoManager        	GeditUndoManager;
+typedef struct _GeditUndoManagerClass 		GeditUndoManagerClass;
+typedef struct _GeditUndoManagerPrivate 	GeditUndoManagerPrivate;
+
+struct _GeditUndoManager
+{
+	GObject parent;
+
+	GeditUndoManagerPrivate *priv;
+};
+
+struct _GeditUndoManagerClass
+{
+	GObjectClass parent_class;
+};
+
+GType gedit_undo_manager_get_type (void) G_GNUC_CONST;
+
+GtkSourceUndoManager * gedit_undo_manager_new (GtkSourceBuffer *buffer);
+
+void gedit_undo_manager_set_max_undo_levels (GeditUndoManager *manager,
+                                             gint              max_undo_levels);
+
+G_END_DECLS
+
+#endif /* __GEDIT_UNDO_MANAGER_H__ */
+
+
diff --git a/gedit/gedit-view-frame.c b/gedit/gedit-view-frame.c
new file mode 100644
index 0000000..16ca4bf
--- /dev/null
+++ b/gedit/gedit-view-frame.c
@@ -0,0 +1,123 @@
+/*
+ * gedit-view-frame.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "gedit-view-frame.h"
+
+
+#define GEDIT_VIEW_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_VIEW_FRAME, GeditViewFramePrivate))
+
+struct _GeditViewFramePrivate
+{
+	GtkWidget     *view;
+	GeditDocument *doc;
+};
+
+G_DEFINE_TYPE (GeditViewFrame, gedit_view_frame, GTK_TYPE_VBOX)
+
+static void
+gedit_view_frame_dispose (GObject *object)
+{
+	GeditViewFrame *holder = GEDIT_VIEW_FRAME (object);
+
+	if (holder->priv->doc != NULL)
+	{
+		g_object_unref (holder->priv->doc);
+		holder->priv->doc = NULL;
+	}
+
+	G_OBJECT_CLASS (gedit_view_frame_parent_class)->dispose (object);
+}
+
+static void
+gedit_view_frame_class_init (GeditViewFrameClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->dispose = gedit_view_frame_dispose;
+
+	g_type_class_add_private (object_class, sizeof (GeditViewFramePrivate));
+}
+
+static GMountOperation *
+view_frame_mount_operation_factory (GeditDocument   *doc,
+				    gpointer         user_data)
+{
+	GeditViewFrame *holder = GEDIT_VIEW_FRAME (user_data);
+	GtkWidget *window;
+
+	window = gtk_widget_get_toplevel (GTK_WIDGET (holder));
+
+	return gtk_mount_operation_new (GTK_WINDOW (window));
+}
+
+static void
+gedit_view_frame_init (GeditViewFrame *holder)
+{
+	GtkWidget *sw;
+
+	holder->priv = GEDIT_VIEW_FRAME_GET_PRIVATE (holder);
+
+	holder->priv->doc = gedit_document_new ();
+
+	_gedit_document_set_mount_operation_factory (holder->priv->doc,
+						     view_frame_mount_operation_factory,
+						     holder);
+
+	holder->priv->view = gedit_view_new (holder->priv->doc);
+	gtk_widget_show (holder->priv->view);
+
+	/* Create the scrolled window */
+	sw = gtk_scrolled_window_new (NULL, NULL);
+
+	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+					GTK_POLICY_AUTOMATIC,
+					GTK_POLICY_AUTOMATIC);
+
+	gtk_container_add (GTK_CONTAINER (sw), holder->priv->view);
+	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
+					     GTK_SHADOW_IN);
+	gtk_widget_show (sw);
+
+	gtk_box_pack_start (GTK_BOX (holder), sw, TRUE, TRUE, 0);
+}
+
+GeditViewFrame *
+gedit_view_frame_new ()
+{
+	return g_object_new (GEDIT_TYPE_VIEW_FRAME, NULL);
+}
+
+GeditDocument *
+gedit_view_frame_get_document (GeditViewFrame *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_FRAME (holder), NULL);
+
+	return holder->priv->doc;
+}
+
+GeditView *
+gedit_view_frame_get_view (GeditViewFrame *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_FRAME (holder), NULL);
+
+	return GEDIT_VIEW (holder->priv->view);
+}
diff --git a/gedit/gedit-view-frame.h b/gedit/gedit-view-frame.h
new file mode 100644
index 0000000..1357f8e
--- /dev/null
+++ b/gedit/gedit-view-frame.h
@@ -0,0 +1,66 @@
+/*
+ * gedit-view-frame.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GEDIT_VIEW_FRAME_H__
+#define __GEDIT_VIEW_FRAME_H__
+
+#include <gtk/gtk.h>
+#include "gedit-document.h"
+#include "gedit-view.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_VIEW_FRAME			(gedit_view_frame_get_type ())
+#define GEDIT_VIEW_FRAME(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_FRAME, GeditViewFrame))
+#define GEDIT_VIEW_FRAME_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_FRAME, GeditViewFrame const))
+#define GEDIT_VIEW_FRAME_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_VIEW_FRAME, GeditViewFrameClass))
+#define GEDIT_IS_VIEW_FRAME(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_VIEW_FRAME))
+#define GEDIT_IS_VIEW_FRAME_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_VIEW_FRAME))
+#define GEDIT_VIEW_FRAME_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_VIEW_FRAME, GeditViewFrameClass))
+
+typedef struct _GeditViewFrame		GeditViewFrame;
+typedef struct _GeditViewFrameClass	GeditViewFrameClass;
+typedef struct _GeditViewFramePrivate	GeditViewFramePrivate;
+
+struct _GeditViewFrame
+{
+	GtkVBox parent;
+	
+	GeditViewFramePrivate *priv;
+};
+
+struct _GeditViewFrameClass
+{
+	GtkVBoxClass parent_class;
+};
+
+GType		 gedit_view_frame_get_type	(void) G_GNUC_CONST;
+
+GeditViewFrame	*gedit_view_frame_new		(void);
+
+GeditDocument	*gedit_view_frame_get_document	(GeditViewFrame *holder);
+
+GeditView	*gedit_view_frame_get_view	(GeditViewFrame *holder);
+
+G_END_DECLS
+
+#endif /* __GEDIT_VIEW_FRAME_H__ */
diff --git a/gedit/gedit-view-holder.c b/gedit/gedit-view-holder.c
new file mode 100644
index 0000000..a8f49d1
--- /dev/null
+++ b/gedit/gedit-view-holder.c
@@ -0,0 +1,883 @@
+/*
+ * gedit-view-holder.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#include "gedit-view-holder.h"
+#include "gedit-undo-manager.h"
+#include "gedit-marshal.h"
+
+
+#define GEDIT_VIEW_HOLDER_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_VIEW_HOLDER, GeditViewHolderPrivate))
+
+/* Properties to bind between views and documents */
+enum
+{
+	AUTO_INDENT,
+	DRAW_SPACES,
+	HIGHLIGHT_CURRENT_LINE,
+	INDENT_ON_TAB,
+	INDENT_WIDTH,
+	INSERT_SPACES_INSTEAD_OF_TABS,
+	RIGHT_MARGIN_POSITION,
+	SHOW_LINE_MARKS,
+	SHOW_LINE_NUMBERS,
+	SHOW_RIGHT_MARGIN,
+	SMART_HOME_END,
+	TAB_WIDTH,
+	HIGHLIGHT_MATCHING_BRACKETS,
+	HIGHLIGHT_SYNTAX,
+	LANGUAGE,
+	MAX_UNDO_LEVELS,
+	STYLE_SCHEME,
+	LOCATION,
+	SHORTNAME,
+	CONTENT_TYPE,
+	LAST_PROPERTY
+};
+
+enum
+{
+	REAL,
+	VIRTUAL,
+	N_VIEW_TYPES
+};
+
+typedef struct _Binding
+{
+	GeditViewFrame *frames[N_VIEW_TYPES];
+
+	gulong          insert_text_id[N_VIEW_TYPES];
+	gulong          delete_range_id[N_VIEW_TYPES];
+
+	GBinding       *bindings[LAST_PROPERTY];
+} Binding;
+
+struct _GeditViewHolderPrivate
+{
+	GSList               *frames;
+	GeditViewFrame       *active_frame;
+	GSList               *bindings;
+	GtkSourceUndoManager *undo_manager;
+
+	guint                 dispose_has_run : 1;
+};
+
+/* Signals */
+enum
+{
+	FRAME_ADDED,
+	FRAME_REMOVED,
+	ACTIVE_FRAME_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GeditViewHolder, gedit_view_holder, GTK_TYPE_VBOX)
+
+static void
+unbind (Binding *binding)
+{
+	gint i;
+
+	for (i = 0; i < LAST_PROPERTY; i++)
+	{
+		g_object_unref (binding->bindings[i]);
+	}
+
+	g_signal_handler_disconnect (gedit_view_frame_get_document (binding->frames[REAL]),
+				     binding->insert_text_id[REAL]);
+	g_signal_handler_disconnect (gedit_view_frame_get_document (binding->frames[VIRTUAL]),
+				     binding->insert_text_id[VIRTUAL]);
+	g_signal_handler_disconnect (gedit_view_frame_get_document (binding->frames[REAL]),
+				     binding->delete_range_id[REAL]);
+	g_signal_handler_disconnect (gedit_view_frame_get_document (binding->frames[VIRTUAL]),
+				     binding->delete_range_id[VIRTUAL]);
+}
+
+static void
+insert_text_on_virtual_doc_cb (GtkTextBuffer *textbuffer,
+			       GtkTextIter   *location,
+			       gchar         *text,
+			       gint           len,
+			       Binding       *binding)
+{
+	GtkTextBuffer *doc;
+	GtkTextIter iter;
+	gint offset;
+	gulong id;
+
+	if (textbuffer == GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[REAL])))
+	{
+		doc = GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[VIRTUAL]));
+		id = binding->insert_text_id[VIRTUAL];
+	}
+	else
+	{
+		doc = GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[REAL]));
+		id = binding->insert_text_id[REAL];
+	}
+
+	offset = gtk_text_iter_get_offset (location);
+	gtk_text_buffer_get_iter_at_offset (doc, &iter, offset);
+
+	g_signal_handler_block (doc, id);
+	gtk_text_buffer_insert (doc, &iter, text, len);
+	g_signal_handler_unblock (doc, id);
+}
+
+static void
+delete_range_on_virtual_doc_cb (GtkTextBuffer *textbuffer,
+				GtkTextIter   *start,
+				GtkTextIter   *end,
+				gpointer       user_data)
+{
+	Binding *binding = (Binding *)user_data;
+	GtkTextBuffer *doc;
+	GtkTextIter start_iter, end_iter;
+	gint offset;
+	gulong id;
+
+	if (textbuffer == GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[REAL])))
+	{
+		doc = GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[VIRTUAL]));
+		id = binding->delete_range_id[VIRTUAL];
+	}
+	else
+	{
+		doc = GTK_TEXT_BUFFER (gedit_view_frame_get_document (binding->frames[REAL]));
+		id = binding->delete_range_id[REAL];
+	}
+
+	offset = gtk_text_iter_get_offset (start);
+	gtk_text_buffer_get_iter_at_offset (doc, &start_iter, offset);
+
+	offset = gtk_text_iter_get_offset (end);
+	gtk_text_buffer_get_iter_at_offset (doc, &end_iter, offset);
+
+	g_signal_handler_block (doc, id);
+	gtk_text_buffer_delete (doc, &start_iter, &end_iter);
+	g_signal_handler_unblock (doc, id);
+}
+
+static void
+bind (Binding *binding)
+{
+	GeditDocument *real_doc, *virtual_doc;
+	GeditView *real_view, *virtual_view;
+
+	real_doc = gedit_view_frame_get_document (binding->frames[REAL]);
+	virtual_doc = gedit_view_frame_get_document (binding->frames[VIRTUAL]);
+	real_view = gedit_view_frame_get_view (binding->frames[REAL]);
+	virtual_view = gedit_view_frame_get_view (binding->frames[VIRTUAL]);
+
+	/* Signals to sync the text inserted or deleted */
+	binding->insert_text_id[REAL] =
+		g_signal_connect (real_doc,
+				  "insert-text",
+				  G_CALLBACK (insert_text_on_virtual_doc_cb),
+				  binding);
+
+	binding->delete_range_id[REAL] =
+		g_signal_connect (real_doc,
+				  "delete-range",
+				  G_CALLBACK (delete_range_on_virtual_doc_cb),
+				  binding);
+
+	binding->insert_text_id[VIRTUAL] =
+		g_signal_connect (virtual_doc,
+				  "insert-text",
+				  G_CALLBACK (insert_text_on_virtual_doc_cb),
+				  binding);
+
+	binding->delete_range_id[VIRTUAL] =
+		g_signal_connect (virtual_doc,
+				  "delete-range",
+				  G_CALLBACK (delete_range_on_virtual_doc_cb),
+				  binding);
+
+	/* Bind all properties */
+	binding->bindings[AUTO_INDENT] =
+		g_object_bind_property (real_view,
+					"auto-indent",
+					virtual_view,
+					"auto-indent",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[DRAW_SPACES] =
+		g_object_bind_property (real_view,
+					"draw-spaces",
+					virtual_view,
+					"draw-spaces",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[HIGHLIGHT_CURRENT_LINE] =
+		g_object_bind_property (real_view,
+					"highlight-current-line",
+					virtual_view,
+					"highlight-current-line",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[INDENT_ON_TAB] =
+		g_object_bind_property (real_view,
+					"indent-on-tab",
+					virtual_view,
+					"indent-on-tab",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[INDENT_WIDTH] =
+		g_object_bind_property (real_view,
+					"indent-width",
+					virtual_view,
+					"indent-width",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[INSERT_SPACES_INSTEAD_OF_TABS] =
+		g_object_bind_property (real_view,
+					"insert-spaces-instead-of-tabs",
+					virtual_view,
+					"insert-spaces-instead-of-tabs",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[RIGHT_MARGIN_POSITION] =
+		g_object_bind_property (real_view,
+					"right-margin-position",
+					virtual_view,
+					"right-margin-position",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[SHOW_LINE_MARKS] =
+		g_object_bind_property (real_view,
+					"show-line-marks",
+					virtual_view,
+					"show-line-marks",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[SHOW_LINE_NUMBERS] =
+		g_object_bind_property (real_view,
+					"show-line-numbers",
+					virtual_view,
+					"show-line-numbers",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[SHOW_RIGHT_MARGIN] =
+		g_object_bind_property (real_view,
+					"show-right-margin",
+					virtual_view,
+					"show-right-margin",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[SMART_HOME_END] =
+		g_object_bind_property (real_view,
+					"smart-home-end",
+					virtual_view,
+					"smart-home-end",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[TAB_WIDTH] =
+		g_object_bind_property (real_view,
+					"tab-width",
+					virtual_view,
+					"tab-width",
+					G_BINDING_SYNC_CREATE);
+
+	binding->bindings[HIGHLIGHT_MATCHING_BRACKETS] =
+		g_object_bind_property (real_doc,
+					"highlight-matching-brackets",
+					virtual_doc,
+					"highlight-matching-brackets",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[HIGHLIGHT_SYNTAX] =
+		g_object_bind_property (real_doc,
+					"highlight-syntax",
+					virtual_doc,
+					"highlight-syntax",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[LANGUAGE] =
+		g_object_bind_property (real_doc,
+					"language",
+					virtual_doc,
+					"language",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[MAX_UNDO_LEVELS] =
+		g_object_bind_property (real_doc,
+					"max-undo-levels",
+					virtual_doc,
+					"max-undo-levels",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[STYLE_SCHEME] =
+		g_object_bind_property (real_doc,
+					"style-scheme",
+					virtual_doc,
+					"style-scheme",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[LOCATION] =
+		g_object_bind_property (real_doc,
+					"location",
+					virtual_doc,
+					"location",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[SHORTNAME] =
+		g_object_bind_property (real_doc,
+					"shortname",
+					virtual_doc,
+					"shortname",
+					G_BINDING_SYNC_CREATE);
+	binding->bindings[CONTENT_TYPE] =
+		g_object_bind_property (real_doc,
+					"content-type",
+					virtual_doc,
+					"content-type",
+					G_BINDING_SYNC_CREATE);
+}
+
+static void
+unbind_frame (GeditViewHolder *holder,
+              GeditViewFrame  *frame)
+{
+	GSList *l;
+	GSList *unbind_list = NULL;
+
+	for (l = holder->priv->bindings; l != NULL; l = g_slist_next (l))
+	{
+		Binding *binding = (Binding *)l->data;
+
+		if (frame == binding->frames[REAL] ||
+		    frame == binding->frames[VIRTUAL])
+		{
+			unbind_list = g_slist_prepend (unbind_list, binding);
+		}
+	}
+
+	for (l = unbind_list; l != NULL; l = g_slist_next (l))
+	{
+		Binding *b1 = (Binding *)l->data;
+
+		unbind (b1);
+
+		if (l->next != NULL)
+		{
+			Binding *b2 = (Binding *)l->next->data;
+			Binding *new_binding;
+			gint i, j;
+
+			i = (frame == b1->frames[REAL]) ? VIRTUAL : REAL;
+			j = (frame == b2->frames[REAL]) ? VIRTUAL : REAL;
+
+			new_binding = g_slice_new (Binding);
+			new_binding->frames[REAL] = b1->frames[i];
+			new_binding->frames[VIRTUAL] = b2->frames[j];
+
+			bind (new_binding);
+
+			holder->priv->bindings = g_slist_append (holder->priv->bindings,
+								 new_binding);
+		}
+
+		/* We remove the old binding */
+		holder->priv->bindings = g_slist_remove (holder->priv->bindings,
+							 b1);
+		g_slice_free (Binding, b1);
+	}
+
+	g_slist_free (unbind_list);
+}
+
+static void
+document_sync_documents (GeditDocument   *doc,
+			 GeditViewHolder *holder)
+{
+	GSList *l;
+
+	for (l = holder->priv->frames; l != NULL; l = g_slist_next (l))
+	{
+		GeditViewFrame *frame = GEDIT_VIEW_FRAME (l->data);
+
+		if (frame != holder->priv->active_frame)
+		{
+			GeditDocument *vdoc;
+
+			vdoc = gedit_view_frame_get_document (frame);
+
+			_gedit_document_sync_documents (doc, vdoc);
+		}
+	}
+}
+
+static void
+on_document_loaded (GeditDocument   *document,
+		    const GError    *error,
+		    GeditViewHolder *holder)
+{
+	if (error == NULL)
+	{
+		GeditView *view;
+
+		view = gedit_view_frame_get_view (holder->priv->active_frame);
+
+		/* Scroll to the cursor when the document is loaded */
+		gedit_view_scroll_to_cursor (view);
+	}
+}
+
+static void
+on_grab_focus (GtkWidget       *widget,
+	       GeditViewHolder *holder)
+{
+	GtkWidget *active_view;
+
+	active_view = GTK_WIDGET (gedit_view_frame_get_view (holder->priv->active_frame));
+
+	/* Update the active view */
+	if (active_view != widget)
+	{
+		GSList *l;
+
+		for (l = holder->priv->frames; l != NULL; l = g_slist_next (l))
+		{
+			GeditViewFrame *frame = GEDIT_VIEW_FRAME (l->data);
+			GtkWidget *view;
+
+			view = GTK_WIDGET (gedit_view_frame_get_view (frame));
+
+			if (view == widget)
+			{
+				GeditViewFrame *old_frame;
+
+				old_frame = holder->priv->active_frame;
+				holder->priv->active_frame = frame;
+
+				g_object_set (G_OBJECT (holder->priv->undo_manager),
+					      "buffer",
+					      gedit_view_frame_get_document (frame),
+					      NULL);
+
+				/* Mark the old view as non editable and the new
+				   one with the editability of the old one */
+				gtk_text_view_set_editable (GTK_TEXT_VIEW (view),
+							    gtk_text_view_get_editable (GTK_TEXT_VIEW (active_view)));
+				gtk_text_view_set_editable (GTK_TEXT_VIEW (active_view),
+							    FALSE);
+
+				g_signal_emit (G_OBJECT (holder), signals[ACTIVE_FRAME_CHANGED],
+				               0, old_frame, frame);
+				break;
+			}
+		}
+	}
+}
+
+static void
+add_view_frame (GeditViewHolder *holder,
+		GeditViewFrame  *frame,
+		gboolean         main_container,
+		GtkOrientation   orientation)
+{
+	if (main_container)
+	{
+		gtk_box_pack_start (GTK_BOX (holder), GTK_WIDGET (frame),
+				    TRUE, TRUE, 0);
+	}
+	else
+	{
+		GeditViewFrame *active_frame = holder->priv->active_frame;
+		GtkWidget *paned;
+		GtkWidget *parent;
+		GtkAllocation allocation;
+		gint pos;
+
+		gtk_widget_get_allocation (GTK_WIDGET (active_frame),
+					   &allocation);
+
+		if (orientation == GTK_ORIENTATION_HORIZONTAL)
+		{
+			paned = gtk_hpaned_new ();
+			pos = allocation.width / 2;
+		}
+		else
+		{
+			paned = gtk_vpaned_new ();
+			pos = allocation.height / 2;
+		}
+
+		gtk_widget_show (paned);
+
+		/* First we remove the active view from its parent, to do
+		   this we add a ref to it*/
+		g_object_ref (active_frame);
+		parent = gtk_widget_get_parent (GTK_WIDGET (active_frame));
+
+		gtk_container_remove (GTK_CONTAINER (parent),
+				      GTK_WIDGET (active_frame));
+
+		if (GTK_IS_VBOX (parent))
+		{
+			gtk_box_pack_end (GTK_BOX (parent), paned, TRUE, TRUE, 0);
+		}
+		else
+		{
+			gtk_container_add (GTK_CONTAINER (parent), paned);
+		}
+
+		gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (active_frame),
+				 FALSE, TRUE);
+		g_object_unref (active_frame);
+
+		gtk_paned_pack2 (GTK_PANED (paned), GTK_WIDGET (frame),
+				 FALSE, FALSE);
+
+		/* We need to set the new paned in the right place */
+		gtk_paned_set_position (GTK_PANED (paned), pos);
+	}
+
+	holder->priv->frames = g_slist_append (holder->priv->frames, frame);
+
+	g_signal_emit (G_OBJECT (holder), signals[FRAME_ADDED], 0, frame);
+}
+
+static void
+connect_frame_signals (GeditViewHolder *holder,
+		       GeditViewFrame  *frame)
+{
+	GeditDocument *doc;
+	GeditView *view;
+
+	doc = gedit_view_frame_get_document (frame);
+	view = gedit_view_frame_get_view (frame);
+
+	g_signal_connect (doc,
+			  "sync-documents",
+			  G_CALLBACK (document_sync_documents),
+			  holder);
+	g_signal_connect_after (doc,
+				"loaded",
+				G_CALLBACK (on_document_loaded),
+				holder);
+
+	g_signal_connect_after (view,
+				"grab-focus",
+				G_CALLBACK (on_grab_focus),
+				holder);
+}
+
+static void
+split_document (GeditViewHolder *holder,
+		GtkOrientation   orientation)
+{
+	GeditViewFrame *frame;
+	Binding *binding;
+	GtkTextIter start, end;
+	gchar *content;
+	GeditDocument *real_doc, *virtual_doc;
+
+	/* Create the holder */
+	frame = gedit_view_frame_new ();
+	connect_frame_signals (holder, frame);
+	gtk_widget_show (GTK_WIDGET (frame));
+
+	real_doc = gedit_view_frame_get_document (holder->priv->active_frame);
+	virtual_doc = gedit_view_frame_get_document (frame);
+
+	gtk_source_buffer_set_undo_manager (GTK_SOURCE_BUFFER (virtual_doc),
+					    holder->priv->undo_manager);
+
+	add_view_frame (holder, frame, FALSE, orientation);
+
+	/* Create the binding for the frames */
+	binding = g_slice_new (Binding);
+	binding->frames[REAL] = holder->priv->active_frame;
+	binding->frames[VIRTUAL] = frame;
+
+	holder->priv->bindings = g_slist_append (holder->priv->bindings, binding);
+
+	/* Copy the content from the real doc to the virtual doc */
+	gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (real_doc), &start, &end);
+
+	content = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (real_doc),
+					    &start, &end, FALSE);
+
+	gtk_text_buffer_set_text (GTK_TEXT_BUFFER (virtual_doc),
+				  content, -1);
+
+	g_free (content);
+
+	/* Bind the views */
+	bind (binding);
+	_gedit_document_sync_documents (real_doc, virtual_doc);
+
+	/* When grabbing the focus the active changes, so be careful here
+	   to grab the focus after creating the binding */
+	gtk_widget_grab_focus (GTK_WIDGET (gedit_view_frame_get_view (frame)));
+}
+
+static void
+remove_view_frame (GeditViewHolder *holder,
+		   GeditViewFrame  *frame)
+{
+	GtkWidget *parent;
+	GtkWidget *grandpa;
+	GList *children;
+	GSList *next_item;
+	GeditViewFrame *next_frame;
+	GeditView *next_view;
+
+	parent = gtk_widget_get_parent (GTK_WIDGET (frame));
+	if (GTK_IS_VBOX (parent))
+	{
+		g_warning ("We can't have an empty page");
+		return;
+	}
+
+	/* Get the next holder */
+	next_item = g_slist_find (holder->priv->frames, frame);
+	if (next_item->next != NULL)
+	{
+		next_item = next_item->next;
+	}
+	else
+	{
+		next_item = holder->priv->frames;
+	}
+
+	next_frame = GEDIT_VIEW_FRAME (next_item->data);
+
+	/* Now we destroy the widget, we get the children of parent and we destroy
+	   parent too as the parent is a useless paned. Finally we add the child
+	   into the grand parent */
+	g_object_ref (frame);
+	unbind_frame (holder, frame);
+
+	holder->priv->frames = g_slist_remove (holder->priv->frames,
+					       frame);
+
+	next_view = gedit_view_frame_get_view (next_frame);
+
+	/* It is important to grab the focus before destroying the view and
+	   after unbind the view, in this way we don't have to make weird
+	   checks in the grab focus handler */
+	gtk_widget_grab_focus (GTK_WIDGET (next_view));
+
+	gtk_widget_destroy (GTK_WIDGET (frame));
+
+	children = gtk_container_get_children (GTK_CONTAINER (parent));
+	if (g_list_length (children) > 1)
+	{
+		g_warning ("The parent is not a paned");
+		return;
+	}
+	grandpa = gtk_widget_get_parent (parent);
+
+	g_object_ref (children->data);
+	gtk_container_remove (GTK_CONTAINER (parent),
+			      GTK_WIDGET (children->data));
+	gtk_widget_destroy (parent);
+	gtk_container_add (GTK_CONTAINER (grandpa),
+			   GTK_WIDGET (children->data));
+	g_object_unref (children->data);
+
+	g_list_free (children);
+	g_object_unref (frame);
+
+	/* FIXME: this is a hack, the first grab focus is the one that emits
+	   the signal (ACTIVE_FRAME_CHANGED) and the second one makes the view
+	   get the focus as it is steal when destroying the active view */
+	gtk_widget_grab_focus (GTK_WIDGET (next_view));
+}
+
+static void
+gedit_view_holder_dispose (GObject *object)
+{
+	GeditViewHolder *holder = GEDIT_VIEW_HOLDER (object);
+
+	if (!holder->priv->dispose_has_run)
+	{
+		GSList *l;
+
+		for (l = holder->priv->bindings; l != NULL; l = g_slist_next (l))
+		{
+			Binding *b = (Binding *)l->data;
+
+			unbind (b);
+			g_slice_free (Binding, b);
+		}
+
+		holder->priv->dispose_has_run = TRUE;
+	}
+
+	G_OBJECT_CLASS (gedit_view_holder_parent_class)->dispose (object);
+}
+
+static void
+gedit_view_holder_finalize (GObject *object)
+{
+	GeditViewHolder *holder = GEDIT_VIEW_HOLDER (object);
+
+	g_slist_free (holder->priv->bindings);
+	g_slist_free (holder->priv->frames);
+
+	G_OBJECT_CLASS (gedit_view_holder_parent_class)->finalize (object);
+}
+
+static void
+gedit_view_holder_class_init (GeditViewHolderClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	
+	object_class->dispose = gedit_view_holder_dispose;
+	object_class->finalize = gedit_view_holder_finalize;
+
+	signals[FRAME_ADDED] =
+		g_signal_new ("frame-added",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (GeditViewHolderClass, frame_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      GEDIT_TYPE_VIEW_FRAME);
+
+	signals[FRAME_REMOVED] =
+		g_signal_new ("frame-removed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (GeditViewHolderClass, frame_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      GEDIT_TYPE_VIEW_FRAME);
+
+	signals[ACTIVE_FRAME_CHANGED] =
+		g_signal_new ("active-frame-changed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (GeditViewHolderClass, active_frame_changed),
+			      NULL, NULL,
+			      gedit_marshal_VOID__OBJECT_OBJECT,
+			      G_TYPE_NONE,
+			      2,
+			      GEDIT_TYPE_VIEW_FRAME,
+			      GEDIT_TYPE_VIEW_FRAME);
+
+	g_type_class_add_private (object_class, sizeof (GeditViewHolderPrivate));
+}
+
+static void
+gedit_view_holder_init (GeditViewHolder *holder)
+{
+	GeditDocument *doc;
+
+	holder->priv = GEDIT_VIEW_HOLDER_GET_PRIVATE (holder);
+
+	holder->priv->active_frame = gedit_view_frame_new ();
+	connect_frame_signals (holder, holder->priv->active_frame);
+	gtk_widget_show (GTK_WIDGET (holder->priv->active_frame));
+
+	add_view_frame (holder, holder->priv->active_frame, TRUE,
+			GTK_ORIENTATION_HORIZONTAL);
+
+	doc = gedit_view_frame_get_document (holder->priv->active_frame);
+
+	/* Create the default undo manager and assign it to the active view */
+	holder->priv->undo_manager = gedit_undo_manager_new (GTK_SOURCE_BUFFER (doc));
+
+	gtk_source_buffer_set_undo_manager (GTK_SOURCE_BUFFER (doc),
+					    holder->priv->undo_manager);
+}
+
+GeditViewHolder *
+gedit_view_holder_new ()
+{
+	return g_object_new (GEDIT_TYPE_VIEW_HOLDER, NULL);
+}
+
+GeditViewFrame *
+gedit_view_holder_get_active_frame (GeditViewHolder *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_HOLDER (holder), NULL);
+
+	return holder->priv->active_frame;
+}
+
+GSList *
+gedit_view_holder_get_frames (GeditViewHolder *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_HOLDER (holder), NULL);
+
+	return holder->priv->frames;
+}
+
+void
+gedit_view_holder_split (GeditViewHolder *holder,
+			 GtkOrientation   orientation)
+{
+	g_return_if_fail (GEDIT_IS_VIEW_HOLDER (holder));
+
+	split_document (holder, orientation);
+}
+
+void
+gedit_view_holder_unsplit (GeditViewHolder *holder)
+{
+	g_return_if_fail (GEDIT_VIEW_HOLDER (holder));
+
+	remove_view_frame (holder, holder->priv->active_frame);
+}
+
+gboolean
+gedit_view_holder_can_split (GeditViewHolder *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_HOLDER (holder), FALSE);
+
+	/*TODO: for future expansion */
+	return TRUE;
+}
+
+gboolean
+gedit_view_holder_can_unsplit (GeditViewHolder *holder)
+{
+	g_return_val_if_fail (GEDIT_IS_VIEW_HOLDER (holder), FALSE);
+
+	return (holder->priv->frames->next != NULL);
+}
+
+void
+gedit_view_holder_set_cursor (GeditViewHolder *holder,
+			      GdkCursorType    cursor_type)
+{
+	GSList *l;
+
+	g_return_if_fail (GEDIT_IS_VIEW_HOLDER (holder));
+
+	for (l = holder->priv->frames; l != NULL; l = g_slist_next (l))
+	{
+		GeditViewFrame *frame = GEDIT_VIEW_FRAME (l->data);
+		GtkTextView *view;
+		GdkCursor *cursor;
+		GdkWindow *text_window;
+		GdkWindow *left_window;
+
+		view = GTK_TEXT_VIEW (gedit_view_frame_get_view (frame));
+		text_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_TEXT);
+		left_window = gtk_text_view_get_window (view, GTK_TEXT_WINDOW_LEFT);
+
+		cursor = gdk_cursor_new_for_display (
+				gtk_widget_get_display (GTK_WIDGET (view)),
+				cursor_type);
+
+		if (text_window != NULL)
+			gdk_window_set_cursor (text_window, cursor);
+		if (left_window != NULL)
+			gdk_window_set_cursor (left_window, NULL);
+
+		gdk_cursor_unref (cursor);
+	}
+}
diff --git a/gedit/gedit-view-holder.h b/gedit/gedit-view-holder.h
new file mode 100644
index 0000000..520beff
--- /dev/null
+++ b/gedit/gedit-view-holder.h
@@ -0,0 +1,86 @@
+/*
+ * gedit-view-holder.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * gedit is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * gedit 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 General Public License
+ * along with gedit; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, 
+ * Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GEDIT_VIEW_HOLDER_H__
+#define __GEDIT_VIEW_HOLDER_H__
+
+#include <gtk/gtk.h>
+#include "gedit-view-frame.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_VIEW_HOLDER			(gedit_view_holder_get_type ())
+#define GEDIT_VIEW_HOLDER(obj)			(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_HOLDER, GeditViewHolder))
+#define GEDIT_VIEW_HOLDER_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_VIEW_HOLDER, GeditViewHolder const))
+#define GEDIT_VIEW_HOLDER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_VIEW_HOLDER, GeditViewHolderClass))
+#define GEDIT_IS_VIEW_HOLDER(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_VIEW_HOLDER))
+#define GEDIT_IS_VIEW_HOLDER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_VIEW_HOLDER))
+#define GEDIT_VIEW_HOLDER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_VIEW_HOLDER, GeditViewHolderClass))
+
+typedef struct _GeditViewHolder	GeditViewHolder;
+typedef struct _GeditViewHolderClass	GeditViewHolderClass;
+typedef struct _GeditViewHolderPrivate	GeditViewHolderPrivate;
+
+struct _GeditViewHolder
+{
+	GtkVBox parent;
+	
+	GeditViewHolderPrivate *priv;
+};
+
+struct _GeditViewHolderClass
+{
+	GtkVBoxClass parent_class;
+
+	void	(* frame_added)			(GeditViewHolder *holder,
+						 GeditViewFrame  *frame);
+	void	(* frame_removed)		(GeditViewHolder *holder,
+						 GeditViewFrame  *frame);
+	void	(* active_frame_changed)	(GeditViewHolder *holder,
+						 GeditViewFrame  *old_frame,
+						 GeditViewFrame  *new_frame);
+};
+
+GType			 gedit_view_holder_get_type	(void) G_GNUC_CONST;
+
+GeditViewHolder		*gedit_view_holder_new		(void);
+
+GeditViewFrame		*gedit_view_holder_get_active_frame
+							(GeditViewHolder *holder);
+
+GSList			*gedit_view_holder_get_frames	(GeditViewHolder *holder);
+
+void			 gedit_view_holder_split 	(GeditViewHolder *holder,
+							 GtkOrientation   orientation);
+
+void			 gedit_view_holder_unsplit	(GeditViewHolder *holder);
+
+gboolean		 gedit_view_holder_can_split	(GeditViewHolder *holder);
+
+gboolean		 gedit_view_holder_can_unsplit	(GeditViewHolder *holder);
+
+void			 gedit_view_holder_set_cursor	(GeditViewHolder *holder,
+							 GdkCursorType    cursor_type);
+
+G_END_DECLS
+
+#endif /* __GEDIT_VIEW_HOLDER_H__ */
diff --git a/gedit/gedit-window.c b/gedit/gedit-window.c
index 2dfa059..f4c108f 100644
--- a/gedit/gedit-window.c
+++ b/gedit/gedit-window.c
@@ -971,6 +971,27 @@ set_sensitivity_according_to_tab (GeditWindow *window,
 				  (state != GEDIT_TAB_STATE_CLOSING) &&
 				  enable_syntax_highlighting);
 
+	action = gtk_action_group_get_action (window->priv->action_group,
+					      "SplitHorizontal");
+
+	gtk_action_set_sensitive (action, 
+				  (state != GEDIT_TAB_STATE_CLOSING) &&
+				  _gedit_tab_can_split (tab));
+
+	action = gtk_action_group_get_action (window->priv->action_group,
+					      "SplitVertical");
+
+	gtk_action_set_sensitive (action, 
+				  (state != GEDIT_TAB_STATE_CLOSING) &&
+				  _gedit_tab_can_split (tab));
+
+	action = gtk_action_group_get_action (window->priv->action_group,
+					      "SplitUnsplit");
+
+	gtk_action_set_sensitive (action, 
+				  (state != GEDIT_TAB_STATE_CLOSING) &&
+				  _gedit_tab_can_unsplit (tab));
+
 	update_next_prev_doc_sensitivity (window, tab);
 
 	peas_extension_set_call (window->priv->extensions, "update_state", window);
@@ -3108,7 +3129,6 @@ drag_data_received_cb (GtkWidget        *widget,
 	}
 }
 
-/* Handle drops on the GeditView */
 static void
 drop_uris_cb (GtkWidget    *widget,
 	      gchar       **uri_list,
@@ -3495,44 +3515,12 @@ update_sensitivity_according_to_open_tabs (GeditWindow *window,
 }
 
 static void
-on_tab_added (GeditMultiNotebook *multi,
-	      GeditNotebook      *notebook,
-	      GeditTab           *tab,
-	      GeditWindow        *window)
+connect_per_view_signals (GeditWindow *window,
+			  GeditView   *view)
 {
-	GeditView *view;
 	GeditDocument *doc;
-	gint num_tabs;
-	gint num_notebooks;
-
-	gedit_debug (DEBUG_WINDOW);
-
-	g_return_if_fail ((window->priv->state & GEDIT_WINDOW_STATE_SAVING_SESSION) == 0);
-
-	num_notebooks = gedit_multi_notebook_get_n_notebooks (multi);
-	num_tabs = gedit_multi_notebook_get_n_tabs (multi);
-
-	update_sensitivity_according_to_open_tabs (window, num_notebooks,
-						   num_tabs);
-
-	view = gedit_tab_get_view (tab);
-	doc = gedit_tab_get_document (tab);
-
-	/* IMPORTANT: remember to disconnect the signal in notebook_tab_removed
-	 * if a new signal is connected here */
 
-	g_signal_connect (tab,
-			 "notify::name",
-			  G_CALLBACK (sync_name),
-			  window);
-	g_signal_connect (tab,
-			 "notify::state",
-			  G_CALLBACK (sync_state),
-			  window);
-	g_signal_connect (tab,
-			  "drop_uris",
-			  G_CALLBACK (drop_uris_cb),
-			  window);
+	doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
 
 	g_signal_connect (doc,
 			  "bracket-matched",
@@ -3574,6 +3562,109 @@ on_tab_added (GeditMultiNotebook *multi,
 			  "notify::editable",
 			  G_CALLBACK (editable_changed),
 			  window);
+}
+
+static void
+disconnect_per_view_signals (GeditWindow *window,
+			     GeditView   *view)
+{
+	GeditDocument *doc;
+
+	doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
+
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (update_cursor_position_statusbar),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (can_search_again),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (can_undo),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (can_redo),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (selection_changed),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (sync_languages_menu),
+					      window);
+	g_signal_handlers_disconnect_by_func (doc,
+					      G_CALLBACK (readonly_changed),
+					      window);
+	g_signal_handlers_disconnect_by_func (view,
+					      G_CALLBACK (update_overwrite_mode_statusbar),
+					      window);
+	g_signal_handlers_disconnect_by_func (view,
+					      G_CALLBACK (editable_changed),
+					      window);
+}
+
+static void
+on_active_view_changed (GeditTab    *tab,
+			GeditView   *old_view,
+			GeditView   *new_view,
+			GeditWindow *window)
+{
+	update_statusbar (window, old_view, new_view);
+
+	if (old_view)
+	{
+		disconnect_per_view_signals (window, old_view);
+	}
+
+	if (new_view)
+	{
+		connect_per_view_signals (window, new_view);
+	}
+
+	set_sensitivity_according_to_tab (window, tab);
+}
+
+static void
+on_tab_added (GeditMultiNotebook *multi,
+	      GeditNotebook      *notebook,
+	      GeditTab           *tab,
+	      GeditWindow        *window)
+{
+	GeditView *view;
+	gint num_tabs;
+	gint num_notebooks;
+
+	gedit_debug (DEBUG_WINDOW);
+
+	g_return_if_fail ((window->priv->state & GEDIT_WINDOW_STATE_SAVING_SESSION) == 0);
+
+	num_notebooks = gedit_multi_notebook_get_n_notebooks (multi);
+	num_tabs = gedit_multi_notebook_get_n_tabs (multi);
+
+	update_sensitivity_according_to_open_tabs (window, num_notebooks,
+						   num_tabs);
+
+	view = gedit_tab_get_view (tab);
+
+	/* IMPORTANT: remember to disconnect the signal in notebook_tab_removed
+	 * if a new signal is connected here */
+
+	g_signal_connect (tab,
+			  "active-view-changed",
+			  G_CALLBACK (on_active_view_changed),
+			  window);
+	g_signal_connect (tab,
+			 "notify::name",
+			  G_CALLBACK (sync_name),
+			  window);
+	g_signal_connect (tab,
+			 "notify::state",
+			  G_CALLBACK (sync_state),
+			  window);
+	g_signal_connect (tab,
+			  "drop-uris",
+			  G_CALLBACK (drop_uris_cb),
+			  window);
+
+	connect_per_view_signals (window, view);
 
 	update_documents_list_menu (window);
 
@@ -3604,6 +3695,9 @@ on_tab_removed (GeditMultiNotebook *multi,
 	doc = gedit_tab_get_document (tab);
 
 	g_signal_handlers_disconnect_by_func (tab,
+					      G_CALLBACK (on_active_view_changed),
+					      window);
+	g_signal_handlers_disconnect_by_func (tab,
 					      G_CALLBACK (sync_name), 
 					      window);
 	g_signal_handlers_disconnect_by_func (tab,
@@ -3612,33 +3706,8 @@ on_tab_removed (GeditMultiNotebook *multi,
 	g_signal_handlers_disconnect_by_func (tab,
 					      G_CALLBACK (drop_uris_cb),
 					      window);
-	g_signal_handlers_disconnect_by_func (doc,
-					      G_CALLBACK (update_cursor_position_statusbar), 
-					      window);
-	g_signal_handlers_disconnect_by_func (doc, 
-					      G_CALLBACK (can_search_again),
-					      window);
-	g_signal_handlers_disconnect_by_func (doc, 
-					      G_CALLBACK (can_undo),
-					      window);
-	g_signal_handlers_disconnect_by_func (doc, 
-					      G_CALLBACK (can_redo),
-					      window);
-	g_signal_handlers_disconnect_by_func (doc,
-					      G_CALLBACK (selection_changed),
-					      window);
-	g_signal_handlers_disconnect_by_func (doc,
-					      G_CALLBACK (sync_languages_menu),
-					      window);
-	g_signal_handlers_disconnect_by_func (doc,
-					      G_CALLBACK (readonly_changed),
-					      window);
-	g_signal_handlers_disconnect_by_func (view, 
-					      G_CALLBACK (update_overwrite_mode_statusbar),
-					      window);
-	g_signal_handlers_disconnect_by_func (view, 
-					      G_CALLBACK (editable_changed),
-					      window);
+
+	disconnect_per_view_signals (window, view);
 
 	if (window->priv->tab_width_id && tab == gedit_multi_notebook_get_active_tab (multi))
 	{
