[gedit] Add animation framework



commit 8cf1f421491555457d8e5046f8fabc82c23f42ba
Author: Ignacio Casal Quinteiro <icq gnome org>
Date:   Thu Jul 15 11:54:03 2010 +0200

    Add animation framework
    
    Now the interactive search uses the animation framework to provide
    a chrome like search dialog.

 configure.ac                                       |    1 +
 gedit/Makefile.am                                  |   21 +-
 gedit/gedit-commands-search.c                      |    8 +-
 gedit/gedit-overlay.c                              |  612 +++++++++
 gedit/gedit-overlay.h                              |   80 ++
 gedit/gedit-rounded-frame.c                        |  231 ++++
 gedit/gedit-rounded-frame.h                        |   61 +
 gedit/gedit-tab.c                                  |    6 +
 gedit/gedit-tab.h                                  |    1 +
 gedit/gedit-view-frame.c                           | 1249 +++++++++++++++++++-
 gedit/gedit-view.c                                 | 1307 +-------------------
 gedit/theatrics/Makefile.am                        |   52 +
 gedit/theatrics/gedit-theatrics-actor.c            |  279 +++++
 gedit/theatrics/gedit-theatrics-actor.h            |   90 ++
 gedit/theatrics/gedit-theatrics-animated-widget.c  |  643 ++++++++++
 gedit/theatrics/gedit-theatrics-animated-widget.h  |  108 ++
 gedit/theatrics/gedit-theatrics-choreographer.c    |   85 ++
 gedit/theatrics/gedit-theatrics-choreographer.h    |   74 ++
 .../gedit-theatrics-enum-types.c.template          |   39 +
 .../gedit-theatrics-enum-types.h.template          |   27 +
 gedit/theatrics/gedit-theatrics-marshal.list       |    1 +
 gedit/theatrics/gedit-theatrics-stage.c            |  313 +++++
 gedit/theatrics/gedit-theatrics-stage.h            |   87 ++
 gedit/theatrics/gedit-theatrics-utils.c            |  131 ++
 gedit/theatrics/gedit-theatrics-utils.h            |   48 +
 tests/Makefile.am                                  |    8 +
 tests/test-overlay.c                               |   62 +
 tests/test-rounded-frame.c                         |   29 +
 28 files changed, 4370 insertions(+), 1283 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index fd0deec..478c36e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -402,6 +402,7 @@ docs/Makefile
 docs/reference/Makefile
 gedit/dialogs/Makefile
 gedit/smclient/Makefile
+gedit/theatrics/Makefile
 gedit/Makefile
 help/Makefile
 pixmaps/Makefile
diff --git a/gedit/Makefile.am b/gedit/Makefile.am
index 3240cb1..4aca99b 100644
--- a/gedit/Makefile.am
+++ b/gedit/Makefile.am
@@ -1,5 +1,5 @@
 ## Process this file with automake to produce Makefile.in
-SUBDIRS = dialogs smclient
+SUBDIRS = dialogs smclient theatrics
 
 bin_PROGRAMS = gedit
 
@@ -40,7 +40,8 @@ libgedit_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_
 
 libgedit_la_LIBADD = \
 	dialogs/libdialogs.la		\
-	smclient/libeggsmclient.la
+	smclient/libeggsmclient.la	\
+	theatrics/libtheatrics.la
 
 # GEDIT_LIBS must be the last to ensure correct order on some platforms
 libgedit_la_LIBADD += $(GEDIT_LIBS)
@@ -114,9 +115,11 @@ NOINST_H_FILES =			\
 	gedit-language-manager.h	\
 	gedit-multi-notebook.h		\
 	gedit-notebook.h		\
+	gedit-overlay.h			\
 	gedit-plugins-engine.h		\
 	gedit-print-job.h		\
 	gedit-print-preview.h		\
+	gedit-rounded-frame.h		\
 	gedit-session.h			\
 	gedit-settings.h		\
 	gedit-smart-charset-converter.h	\
@@ -195,11 +198,13 @@ libgedit_c_files =			\
 	gedit-message.c			\
 	gedit-multi-notebook.c		\
 	gedit-notebook.c		\
+	gedit-overlay.c			\
 	gedit-panel.c			\
 	gedit-plugins-engine.c		\
 	gedit-print-job.c		\
 	gedit-print-preview.c		\
 	gedit-progress-info-bar.c	\
+	gedit-rounded-frame.c		\
 	gedit-session.c			\
 	gedit-settings.c		\
 	gedit-smart-charset-converter.c	\
@@ -260,6 +265,16 @@ EXTRA_DIST = 				\
 
 CLEANFILES = $(BUILT_SOURCES)
 
+theatrics_files =						\
+	./theatrics/gedit-theatrics-actor.h			\
+	./theatrics/gedit-theatrics-actor.c			\
+	./theatrics/gedit-theatrics-animated-widget.h		\
+	./theatrics/gedit-theatrics-animated-widget.c		\
+	./theatrics/gedit-theatrics-choreographer.h		\
+	./theatrics/gedit-theatrics-choreographer.c		\
+	./theatrics/gedit-theatrics-stage.h			\
+	./theatrics/gedit-theatrics-stage.c
+
 if HAVE_INTROSPECTION
 -include $(INTROSPECTION_MAKEFILE)
 INTROSPECTION_GIRS = Gedit-3.0.gir
@@ -269,7 +284,7 @@ INTROSPECTION_SCANNER_ARGS = -I$(top_srcdir) --warn-all
 Gedit_3_0_gir_NAMESPACE = Gedit
 Gedit_3_0_gir_VERSION = 3.0
 Gedit_3_0_gir_PROGRAM = $(builddir)/gedit
-Gedit_3_0_gir_FILES = $(INST_H_FILES) $(libgedit_c_files)
+Gedit_3_0_gir_FILES = $(theatrics_files) $(INST_H_FILES) $(libgedit_c_files)
 Gedit_3_0_gir_INCLUDES = Gtk-3.0 GtkSource-3.0
 
 girdir = $(datadir)/gedit/gir-1.0
diff --git a/gedit/gedit-commands-search.c b/gedit/gedit-commands-search.c
index 02d1bad..f267189 100644
--- a/gedit/gedit-commands-search.c
+++ b/gedit/gedit-commands-search.c
@@ -41,6 +41,7 @@
 #include "gedit-commands.h"
 #include "gedit-debug.h"
 #include "gedit-statusbar.h"
+#include "gedit-view-frame.h"
 #include "gedit-window.h"
 #include "gedit-window-private.h"
 #include "gedit-utils.h"
@@ -692,9 +693,8 @@ _gedit_cmd_search_goto_line (GtkAction   *action,
 	   activating the binding for goto line has no effect */
 	gtk_widget_grab_focus (GTK_WIDGET (active_view));
 
-
 	/* goto line is builtin in GeditView, just activate
-	 * the corrisponding binding.
+	 * the corresponding binding.
 	 */
 	gtk_bindings_activate (GTK_OBJECT (active_view),
 			       GDK_i,
@@ -714,11 +714,11 @@ _gedit_cmd_search_incremental_search (GtkAction   *action,
 		return;
 
 	/* Focus the view if needed: we need to focus the view otherwise 
-	   activating the binding for incremental search has no effect */
+	   activating the binding for goto line has no effect */
 	gtk_widget_grab_focus (GTK_WIDGET (active_view));
 	
 	/* incremental search is builtin in GeditView, just activate
-	 * the corrisponding binding.
+	 * the corresponding binding.
 	 */
 	gtk_bindings_activate (GTK_OBJECT (active_view),
 			       GDK_k,
diff --git a/gedit/gedit-overlay.c b/gedit/gedit-overlay.c
new file mode 100644
index 0000000..c716f3f
--- /dev/null
+++ b/gedit/gedit-overlay.c
@@ -0,0 +1,612 @@
+/*
+ * gedit-overlay.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * 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-overlay.h"
+#include "gedit-marshal.h"
+#include "theatrics/gedit-theatrics-animation.h"
+#include "theatrics/gedit-theatrics-animated-widget.h"
+#include "theatrics/gedit-theatrics-stage.h"
+
+#define GEDIT_OVERLAY_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_OVERLAY, GeditOverlayPrivate))
+
+typedef struct _ContainerChild
+{
+	GtkWidget *child;
+	gint x;
+	gint y;
+
+	guint fixed_position : 1;
+	guint is_animated : 1;
+} ContainerChild;
+
+struct _GeditOverlayPrivate
+{
+	GtkWidget *main_widget;
+	GSList *children;
+
+	GtkAdjustment *hadjustment;
+	GtkAdjustment *vadjustment;
+	glong          hadjustment_signal_id;
+	glong          vadjustment_signal_id;
+
+	GeditTheatricsStage *stage;
+};
+
+enum
+{
+	PROP_0,
+	PROP_MAIN_WIDGET
+};
+
+enum
+{
+	SET_SCROLL_ADJUSTMENTS,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GeditOverlay, gedit_overlay, GTK_TYPE_CONTAINER)
+
+static void
+free_container_child (ContainerChild *child)
+{
+	g_slice_free (ContainerChild, child);
+}
+
+static void
+add_toplevel_widget (GeditOverlay *overlay,
+                     GtkWidget    *widget,
+                     gboolean      fixed_position,
+                     gboolean      is_animated,
+                     gint          x,
+                     gint          y)
+{
+	ContainerChild *child = g_slice_new (ContainerChild);
+
+	gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
+	child->child = widget;
+	child->x = x;
+	child->y = y;
+	child->fixed_position = fixed_position;
+	child->is_animated = is_animated;
+
+	overlay->priv->children = g_slist_append (overlay->priv->children,
+	                                          child);
+}
+
+static void
+gedit_overlay_finalize (GObject *object)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+	g_slist_free (overlay->priv->children);
+
+	G_OBJECT_CLASS (gedit_overlay_parent_class)->finalize (object);
+}
+
+static void
+gedit_overlay_dispose (GObject *object)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+	if (overlay->priv->stage != NULL)
+	{
+		g_object_unref (overlay->priv->stage);
+		overlay->priv->stage = NULL;
+	}
+
+	G_OBJECT_CLASS (gedit_overlay_parent_class)->dispose (object);
+}
+
+static void
+gedit_overlay_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+	switch (prop_id)
+	{
+		case PROP_MAIN_WIDGET:
+			g_value_set_object (value, overlay->priv->main_widget);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_overlay_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+	switch (prop_id)
+	{
+		case PROP_MAIN_WIDGET:
+		{
+			overlay->priv->main_widget = g_value_get_object (value);
+			add_toplevel_widget (overlay,
+			                     overlay->priv->main_widget,
+			                     TRUE, FALSE, 0, 0);
+			break;
+		}
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_overlay_destroy (GtkObject *object)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (object);
+
+	if (overlay->priv->hadjustment != NULL)
+	{
+		g_signal_handler_disconnect (overlay->priv->hadjustment,
+		                             overlay->priv->hadjustment_signal_id);
+		overlay->priv->hadjustment = NULL;
+	}
+
+	if (overlay->priv->vadjustment != NULL)
+	{
+		g_signal_handler_disconnect (overlay->priv->vadjustment,
+		                             overlay->priv->vadjustment_signal_id);
+		overlay->priv->vadjustment = NULL;
+	}
+
+	GTK_OBJECT_CLASS (gedit_overlay_parent_class)->destroy (object);
+}
+
+static void
+gedit_overlay_realize (GtkWidget *widget)
+{
+	GdkWindowAttr attributes;
+	GtkAllocation allocation;
+	GdkWindowAttributesType mask;
+	GdkWindow *parent_window;
+	GdkWindow *window;
+	GtkStyle *style;
+
+	gtk_widget_set_realized (widget, TRUE);
+	gtk_widget_get_allocation (widget, &allocation);
+
+	parent_window = gtk_widget_get_parent_window (widget);
+	style = gtk_widget_get_style (widget);
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.x = allocation.x;
+	attributes.y = allocation.y;
+	attributes.width = allocation.width;
+	attributes.height = allocation.height;
+	attributes.wclass = GDK_INPUT_OUTPUT;
+	attributes.visual = gtk_widget_get_visual (widget);
+	attributes.colormap = gtk_widget_get_colormap (widget);
+	attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
+
+	mask = GDK_WA_X | GDK_WA_Y | GDK_WA_COLORMAP | GDK_WA_VISUAL;
+	window = gdk_window_new (parent_window, &attributes, mask);
+	gdk_window_set_user_data (window, widget);
+	gtk_widget_set_window (widget, window);
+
+	style = gtk_style_attach (style, window);
+	gtk_widget_set_style (widget, style);
+	gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+}
+
+static void
+set_children_positions (GeditOverlay *overlay)
+{
+	GSList *l;
+
+	for (l = overlay->priv->children; l != NULL; l = g_slist_next (l))
+	{
+		ContainerChild *child = (ContainerChild *)l->data;
+		GtkRequisition req;
+		GtkAllocation alloc;
+
+		if (child->child == overlay->priv->main_widget)
+			continue;
+
+		gtk_widget_size_request (child->child, &req);
+
+		alloc.x = child->fixed_position ? child->x :
+		          child->x * gtk_adjustment_get_value (overlay->priv->hadjustment);
+		alloc.y = child->fixed_position ? child->y :
+		          child->y * gtk_adjustment_get_value (overlay->priv->vadjustment);
+		alloc.width = req.width;
+		alloc.height = req.height;
+
+		gtk_widget_size_allocate (child->child, &alloc);
+	}
+}
+
+static void
+gedit_overlay_size_allocate (GtkWidget     *widget,
+                             GtkAllocation *allocation)
+{
+	GeditOverlay *overlay = GEDIT_OVERLAY (widget);
+	GtkAllocation alloc;
+
+	GTK_WIDGET_CLASS (gedit_overlay_parent_class)->size_allocate (widget, allocation);
+
+	alloc.x = 0;
+	alloc.y = 0;
+	alloc.width = allocation->width;
+	alloc.height = allocation->height;
+
+	gtk_widget_size_allocate (overlay->priv->main_widget,
+	                          &alloc);
+	set_children_positions (overlay);
+}
+
+static void
+gedit_overlay_add (GtkContainer *overlay,
+                   GtkWidget    *widget)
+{
+	add_toplevel_widget (GEDIT_OVERLAY (overlay), widget,
+	                     FALSE, FALSE, 0, 0);
+}
+
+static void
+gedit_overlay_remove (GtkContainer *overlay,
+                      GtkWidget    *widget)
+{
+	GeditOverlay *goverlay = GEDIT_OVERLAY (overlay);
+	GSList *l;
+
+	for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l))
+	{
+		ContainerChild *child = (ContainerChild *)l->data;
+
+		if (child->child == widget)
+		{
+			gtk_widget_unparent (widget);
+			goverlay->priv->children = g_slist_remove (goverlay->priv->children,
+			                                           child);
+			free_container_child (child);
+		}
+	}
+}
+
+static void
+gedit_overlay_forall (GtkContainer *overlay,
+                      gboolean      include_internals,
+                      GtkCallback   callback,
+                      gpointer      callback_data)
+{
+	GeditOverlay *goverlay = GEDIT_OVERLAY (overlay);
+	GSList *l;
+
+	for (l = goverlay->priv->children; l != NULL; l = g_slist_next (l))
+	{
+		ContainerChild *child = (ContainerChild *)l->data;
+
+		callback (child->child, callback_data);
+	}
+}
+
+static GType
+gedit_overlay_child_type (GtkContainer *overlay)
+{
+	return GTK_TYPE_WIDGET;
+}
+
+static void
+adjustment_value_changed (GtkAdjustment *adjustment,
+                          GeditOverlay  *overlay)
+{
+	set_children_positions (overlay);
+}
+
+static void
+gedit_overlay_set_scroll_adjustments (GeditOverlay  *overlay,
+                                      GtkAdjustment *hadjustment,
+                                      GtkAdjustment *vadjustment)
+{
+	if (overlay->priv->hadjustment != NULL)
+	{
+		g_signal_handler_disconnect (overlay->priv->hadjustment,
+		                             overlay->priv->hadjustment_signal_id);
+	}
+
+	if (overlay->priv->vadjustment != NULL)
+	{
+		g_signal_handler_disconnect (overlay->priv->vadjustment,
+		                             overlay->priv->vadjustment_signal_id);
+	}
+
+	if (hadjustment != NULL)
+	{
+		overlay->priv->hadjustment_signal_id =
+			g_signal_connect (hadjustment,
+			                  "value-changed",
+			                  G_CALLBACK (adjustment_value_changed),
+			                  overlay);
+	}
+
+	if (vadjustment != NULL)
+	{
+		overlay->priv->vadjustment_signal_id =
+			g_signal_connect (vadjustment,
+			                  "value-changed",
+			                  G_CALLBACK (adjustment_value_changed),
+			                  overlay);
+	}
+
+	overlay->priv->hadjustment = hadjustment;
+	overlay->priv->vadjustment = vadjustment;
+
+	gtk_widget_set_scroll_adjustments (overlay->priv->main_widget,
+	                                   hadjustment,
+	                                   vadjustment);
+}
+
+static void
+gedit_overlay_class_init (GeditOverlayClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkObjectClass *gtkobject_class = GTK_OBJECT_CLASS (klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+	object_class->finalize = gedit_overlay_finalize;
+	object_class->dispose = gedit_overlay_dispose;
+	object_class->get_property = gedit_overlay_get_property;
+	object_class->set_property = gedit_overlay_set_property;
+
+	gtkobject_class->destroy = gedit_overlay_destroy;
+
+	widget_class->realize = gedit_overlay_realize;
+	widget_class->size_allocate = gedit_overlay_size_allocate;
+
+	container_class->add = gedit_overlay_add;
+	container_class->remove = gedit_overlay_remove;
+	container_class->forall = gedit_overlay_forall;
+	container_class->child_type = gedit_overlay_child_type;
+
+	klass->set_scroll_adjustments = gedit_overlay_set_scroll_adjustments;
+
+	g_object_class_install_property (object_class, PROP_MAIN_WIDGET,
+	                                 g_param_spec_object ("main-widget",
+	                                                      "Main Widget",
+	                                                      "The Main Widget",
+	                                                      GTK_TYPE_WIDGET,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT_ONLY |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	signals[SET_SCROLL_ADJUSTMENTS] =
+		g_signal_new ("set-scroll-adjustments",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		              G_STRUCT_OFFSET (GeditOverlayClass, set_scroll_adjustments),
+		              NULL, NULL,
+		              gedit_marshal_VOID__OBJECT_OBJECT,
+		              G_TYPE_NONE, 2,
+		              GTK_TYPE_ADJUSTMENT,
+		              GTK_TYPE_ADJUSTMENT);
+	widget_class->set_scroll_adjustments_signal = signals[SET_SCROLL_ADJUSTMENTS];
+
+	g_type_class_add_private (object_class, sizeof (GeditOverlayPrivate));
+}
+
+static void
+on_actor_step (GeditTheatricsStage *stage,
+               GeditTheatricsActor *actor,
+               GeditOverlay        *overlay)
+{
+	GeditTheatricsAnimationState animation_state;
+	GeditTheatricsAnimatedWidget *anim_widget;
+
+	anim_widget = GEDIT_THEATRICS_ANIMATED_WIDGET (gedit_theatrics_actor_get_target (actor));
+	animation_state = gedit_theatrics_animated_widget_get_animation_state (anim_widget);
+
+	switch (animation_state)
+	{
+		case GEDIT_THEATRICS_ANIMATION_STATE_COMING:
+		{
+			gtk_widget_queue_draw (GTK_WIDGET (anim_widget));
+			gedit_theatrics_animated_widget_set_percent (anim_widget,
+			                                             gedit_theatrics_actor_get_percent (actor));
+			if (gedit_theatrics_actor_get_expired (actor))
+			{
+				gedit_theatrics_animated_widget_set_animation_state (anim_widget,
+				                                                     GEDIT_THEATRICS_ANIMATION_STATE_IDLE);
+			}
+			break;
+		}
+		case GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO:
+		{
+			gedit_theatrics_animated_widget_set_animation_state (anim_widget,
+			                                                     GEDIT_THEATRICS_ANIMATION_STATE_GOING);
+			gedit_theatrics_animated_widget_set_bias (anim_widget,
+			                                          gedit_theatrics_actor_get_percent (actor));
+			gedit_theatrics_actor_reset (actor, gedit_theatrics_animated_widget_get_duration (anim_widget) *
+			                                    gedit_theatrics_actor_get_percent (actor));
+			break;
+		}
+		case GEDIT_THEATRICS_ANIMATION_STATE_GOING:
+		{
+			if (gedit_theatrics_actor_get_expired (actor))
+			{
+				gtk_container_remove (GTK_CONTAINER (overlay),
+				                      GTK_WIDGET (anim_widget));
+				return;
+			}
+			gedit_theatrics_animated_widget_set_percent (anim_widget, 1.0 - gedit_theatrics_actor_get_percent (actor));
+			break;
+		}
+		default:
+			break;
+	}
+}
+
+static void
+remove_core (GeditOverlay                 *overlay,
+             GeditTheatricsAnimatedWidget *aw)
+{
+	GeditTheatricsAnimationState animation_state;
+
+	animation_state = gedit_theatrics_animated_widget_get_animation_state (aw);
+
+	if (animation_state == GEDIT_THEATRICS_ANIMATION_STATE_COMING)
+	{
+		gedit_theatrics_animated_widget_set_animation_state (aw, GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO);
+	}
+	else
+	{
+		GeditTheatricsChoreographerEasing easing;
+
+		easing = gedit_theatrics_animated_widget_get_easing (aw);
+
+		switch (easing)
+		{
+			case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN:
+				gedit_theatrics_animated_widget_set_easing (
+					aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT);
+				break;
+			case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT:
+				gedit_theatrics_animated_widget_set_easing (
+					aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN);
+				break;
+			case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN:
+				gedit_theatrics_animated_widget_set_easing (
+					aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT);
+				break;
+			case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT:
+				gedit_theatrics_animated_widget_set_easing (
+					aw, GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN);
+				break;
+			default:
+				break;
+		}
+
+		gedit_theatrics_animated_widget_set_animation_state (aw, GEDIT_THEATRICS_ANIMATION_STATE_GOING);
+		gedit_theatrics_stage_add_with_duration (overlay->priv->stage,
+		                                         G_OBJECT (aw),
+		                                         gedit_theatrics_animated_widget_get_duration (aw));
+	}
+}
+
+static void
+on_remove_core (GeditTheatricsAnimatedWidget *aw,
+                GeditOverlay                 *overlay)
+{
+	remove_core (overlay, aw);
+}
+
+static void
+gedit_overlay_init (GeditOverlay *overlay)
+{
+	overlay->priv = GEDIT_OVERLAY_GET_PRIVATE (overlay);
+
+	overlay->priv->stage = gedit_theatrics_stage_new ();
+
+	g_signal_connect (overlay->priv->stage,
+	                  "actor-step",
+	                  G_CALLBACK (on_actor_step),
+	                  overlay);
+}
+
+GtkWidget *
+gedit_overlay_new (GtkWidget *main_widget)
+{
+	return GTK_WIDGET (g_object_new (GEDIT_TYPE_OVERLAY,
+	                                 "main-widget", main_widget,
+	                                 NULL));
+}
+
+void
+gedit_overlay_add_animated_widget (GeditOverlay                       *overlay,
+                                   GtkWidget                          *widget,
+                                   guint                               duration,
+                                   GeditTheatricsChoreographerEasing   easing,
+                                   GeditTheatricsChoreographerBlocking blocking,
+                                   GtkOrientation                      orientation,
+                                   gint                                x,
+                                   gint                                y)
+{
+	GeditTheatricsAnimatedWidget *anim_widget;
+	GeditTheatricsActor *actor;
+	GtkAllocation widget_alloc;
+
+	anim_widget = gedit_theatrics_animated_widget_new (widget, duration,
+	                                                   easing,
+	                                                   blocking,
+	                                                   orientation);
+	gtk_widget_show (GTK_WIDGET (anim_widget));
+
+	g_signal_connect (anim_widget,
+	                  "remove-core",
+	                  G_CALLBACK (on_remove_core),
+	                  overlay);
+
+	gtk_widget_get_allocation (widget, &widget_alloc);
+	gedit_theatrics_animated_widget_set_end_padding (anim_widget,
+	                                                 widget_alloc.height);
+
+	actor = gedit_theatrics_stage_add_with_duration (overlay->priv->stage,
+	                                                 G_OBJECT (anim_widget),
+	                                                 duration);
+
+	add_toplevel_widget (overlay, GTK_WIDGET (anim_widget), TRUE,
+	                     TRUE, x, y);
+}
+
+void
+gedit_overlay_move_widget (GeditOverlay *overlay,
+                           GtkWidget    *widget,
+                           gint          x,
+                           gint          y)
+{
+	GSList *l;
+
+	for (l = overlay->priv->children; l != NULL; l = g_slist_next (l))
+	{
+		ContainerChild *child = (ContainerChild *)l->data;
+		GtkWidget *w;
+
+		if (child->is_animated)
+		{
+			w = gedit_theatrics_animated_widget_get_widget (GEDIT_THEATRICS_ANIMATED_WIDGET (child->child));
+		}
+		else
+		{
+			w = child->child;
+		}
+
+		if (w == widget)
+		{
+			child->x = x;
+			child->y = y;
+		}
+	}
+}
diff --git a/gedit/gedit-overlay.h b/gedit/gedit-overlay.h
new file mode 100644
index 0000000..bf9be4e
--- /dev/null
+++ b/gedit/gedit-overlay.h
@@ -0,0 +1,80 @@
+/*
+ * gedit-overlay.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_OVERLAY_H__
+#define __GEDIT_OVERLAY_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "theatrics/gedit-theatrics-choreographer.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_OVERLAY		(gedit_overlay_get_type ())
+#define GEDIT_OVERLAY(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay))
+#define GEDIT_OVERLAY_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_OVERLAY, GeditOverlay const))
+#define GEDIT_OVERLAY_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_OVERLAY, GeditOverlayClass))
+#define GEDIT_IS_OVERLAY(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_OVERLAY))
+#define GEDIT_IS_OVERLAY_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_OVERLAY))
+#define GEDIT_OVERLAY_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_OVERLAY, GeditOverlayClass))
+
+typedef struct _GeditOverlay		GeditOverlay;
+typedef struct _GeditOverlayClass	GeditOverlayClass;
+typedef struct _GeditOverlayPrivate	GeditOverlayPrivate;
+
+struct _GeditOverlay
+{
+	GtkContainer parent;
+
+	GeditOverlayPrivate *priv;
+};
+
+struct _GeditOverlayClass
+{
+	GtkContainerClass parent_class;
+
+	void (* set_scroll_adjustments)   (GeditOverlay  *overlay,
+	                                   GtkAdjustment *hadjustment,
+	                                   GtkAdjustment *vadjustment);
+};
+
+GType		 gedit_overlay_get_type			(void) G_GNUC_CONST;
+
+GtkWidget	*gedit_overlay_new			(GtkWidget *main_widget);
+
+void		 gedit_overlay_add_animated_widget	(GeditOverlay                       *overlay,
+							 GtkWidget                          *widget,
+							 guint                               duration,
+							 GeditTheatricsChoreographerEasing   easing,
+							 GeditTheatricsChoreographerBlocking blocking,
+							 GtkOrientation                      orientation,
+							 gint                                x,
+							 gint                                y);
+
+void		 gedit_overlay_move_widget		(GeditOverlay *container,
+							 GtkWidget    *widget,
+							 gint          x,
+							 gint          y);
+
+G_END_DECLS
+
+#endif /* __GEDIT_OVERLAY_H__ */
diff --git a/gedit/gedit-rounded-frame.c b/gedit/gedit-rounded-frame.c
new file mode 100644
index 0000000..c762021
--- /dev/null
+++ b/gedit/gedit-rounded-frame.c
@@ -0,0 +1,231 @@
+/*
+ * gedit-rounded-frame.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Work based on Aaron Bockover <abockover novell com>
+ *               Gabriel Burt <gburt novell com>
+ *
+ * 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-rounded-frame.h"
+#include "theatrics/gedit-theatrics-utils.h"
+
+
+#define GEDIT_ROUNDED_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFramePrivate))
+
+struct _GeditRoundedFramePrivate
+{
+	GtkWidget *child;
+
+	GtkAllocation child_allocation;
+	guint frame_width;
+};
+
+G_DEFINE_TYPE (GeditRoundedFrame, gedit_rounded_frame, GTK_TYPE_BIN)
+
+static void
+gedit_rounded_frame_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gedit_rounded_frame_parent_class)->finalize (object);
+}
+
+static void
+gedit_rounded_frame_size_request (GtkWidget      *widget,
+                                  GtkRequisition *requisition)
+{
+	GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+	gint border_width;
+
+	if (frame->priv->child != NULL &&
+	    gtk_widget_get_visible (frame->priv->child))
+	{
+		GtkRequisition child_requisition;
+
+		/* Add the child's width/height */
+		gtk_widget_size_request (frame->priv->child, &child_requisition);
+
+		requisition->width = MAX (0, child_requisition.width);
+		requisition->height = child_requisition.height;
+	}
+	else
+	{
+		requisition->width = 0;
+		requisition->height = 0;
+	}
+
+	/* Add the border */
+	border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+	requisition->width += (border_width + frame->priv->frame_width) * 2;
+	requisition->height += (border_width + frame->priv->frame_width) * 2;
+}
+
+static void
+gedit_rounded_frame_size_allocate (GtkWidget     *widget,
+                                   GtkAllocation *allocation)
+{
+	GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+	GtkAllocation *child_allocation;
+	int border;
+
+	child_allocation = &frame->priv->child_allocation;
+
+	GTK_WIDGET_CLASS (gedit_rounded_frame_parent_class)->size_allocate (widget, allocation);
+
+	if (frame->priv->child == NULL ||
+	    !gtk_widget_get_visible (frame->priv->child))
+	{
+		return;
+	}
+
+	border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 
+	         frame->priv->frame_width;
+	child_allocation->x = allocation->x + border;
+	child_allocation->y = allocation->y + border;
+	child_allocation->width = MAX (1, allocation->width - border * 2);
+	child_allocation->height = MAX (1, allocation->height - border * 2);
+
+	gtk_widget_size_allocate (frame->priv->child, child_allocation);
+}
+
+static void
+draw_frame (GeditRoundedFrame *frame,
+            cairo_t           *cr,
+            GdkRectangle      *area)
+{
+	GtkStyle *style;
+	GdkColor bg_color;
+	GdkColor border_color;
+
+	gedit_theatrics_utils_draw_round_rectangle (cr,
+	                                            FALSE,
+	                                            FALSE,
+	                                            TRUE,
+	                                            TRUE,
+	                                            area->x,
+	                                            area->y,
+	                                            MIN (0.30 * area->width, 0.30 * area->height),
+	                                            area->width,
+	                                            area->height);
+
+	style = gtk_widget_get_style (GTK_WIDGET (frame));
+	bg_color = style->bg[GTK_STATE_NORMAL];
+	border_color = style->dark[GTK_STATE_ACTIVE];
+
+	gdk_cairo_set_source_color (cr, &bg_color);
+	cairo_fill_preserve (cr);
+
+	gdk_cairo_set_source_color (cr, &border_color);
+	cairo_set_line_width (cr, frame->priv->frame_width / 2);
+	cairo_stroke (cr);
+}
+
+static gboolean
+gedit_rounded_frame_expose_event (GtkWidget      *widget,
+                                  GdkEventExpose *event)
+{
+	GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (widget);
+	GdkRectangle area;
+	cairo_t *cr;
+
+	if (!gtk_widget_is_drawable (widget))
+	{
+		return FALSE;
+	}
+
+	cr = gdk_cairo_create (event->window);
+
+	area.x = frame->priv->child_allocation.x - frame->priv->frame_width;
+	area.y = frame->priv->child_allocation.y - 2 * frame->priv->frame_width - 1;
+	area.width = frame->priv->child_allocation.width + 2 * frame->priv->frame_width;
+	area.height = frame->priv->child_allocation.height + 3 * frame->priv->frame_width;
+
+	draw_frame (frame, cr, &area);
+
+	if (frame->priv->child != NULL)
+	{
+		gtk_container_propagate_expose (GTK_CONTAINER (frame),
+		                                frame->priv->child,
+		                                event);
+	}
+
+	cairo_destroy (cr);
+
+	return FALSE;
+}
+
+static void
+gedit_rounded_frame_add (GtkContainer *container,
+                         GtkWidget    *widget)
+{
+	GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (container);
+
+	frame->priv->child = widget;
+
+	GTK_CONTAINER_CLASS (gedit_rounded_frame_parent_class)->add (container, widget);
+}
+
+static void
+gedit_rounded_frame_remove (GtkContainer *container,
+                            GtkWidget    *widget)
+{
+	GeditRoundedFrame *frame = GEDIT_ROUNDED_FRAME (container);
+
+	if (frame->priv->child == widget)
+	{
+		frame->priv->child = NULL;
+	}
+
+	GTK_CONTAINER_CLASS (gedit_rounded_frame_parent_class)->remove (container, widget);
+}
+
+static void
+gedit_rounded_frame_class_init (GeditRoundedFrameClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+	object_class->finalize = gedit_rounded_frame_finalize;
+
+	widget_class->size_request = gedit_rounded_frame_size_request;
+	widget_class->size_allocate = gedit_rounded_frame_size_allocate;
+	widget_class->expose_event = gedit_rounded_frame_expose_event;
+
+	container_class->add = gedit_rounded_frame_add;
+	container_class->remove = gedit_rounded_frame_remove;
+
+	g_type_class_add_private (object_class, sizeof (GeditRoundedFramePrivate));
+}
+
+static void
+gedit_rounded_frame_init (GeditRoundedFrame *frame)
+{
+	frame->priv = GEDIT_ROUNDED_FRAME_GET_PRIVATE (frame);
+
+	frame->priv->frame_width = 3; /* Make it a prop */
+
+	gtk_widget_set_has_window (GTK_WIDGET (frame), FALSE);
+	gtk_widget_set_app_paintable (GTK_WIDGET (frame), FALSE);
+}
+
+GtkWidget *
+gedit_rounded_frame_new ()
+{
+	return GTK_WIDGET (g_object_new (GEDIT_TYPE_ROUNDED_FRAME, NULL));
+}
diff --git a/gedit/gedit-rounded-frame.h b/gedit/gedit-rounded-frame.h
new file mode 100644
index 0000000..9fce152
--- /dev/null
+++ b/gedit/gedit-rounded-frame.h
@@ -0,0 +1,61 @@
+/*
+ * gedit-rounded-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_ROUNDED_FRAME_H__
+#define __GEDIT_ROUNDED_FRAME_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_ROUNDED_FRAME		(gedit_rounded_frame_get_type ())
+#define GEDIT_ROUNDED_FRAME(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrame))
+#define GEDIT_ROUNDED_FRAME_CONST(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrame const))
+#define GEDIT_ROUNDED_FRAME_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrameClass))
+#define GEDIT_IS_ROUNDED_FRAME(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_ROUNDED_FRAME))
+#define GEDIT_IS_ROUNDED_FRAME_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_ROUNDED_FRAME))
+#define GEDIT_ROUNDED_FRAME_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_ROUNDED_FRAME, GeditRoundedFrameClass))
+
+typedef struct _GeditRoundedFrame		GeditRoundedFrame;
+typedef struct _GeditRoundedFrameClass		GeditRoundedFrameClass;
+typedef struct _GeditRoundedFramePrivate	GeditRoundedFramePrivate;
+
+struct _GeditRoundedFrame
+{
+	GtkBin parent;
+
+	GeditRoundedFramePrivate *priv;
+};
+
+struct _GeditRoundedFrameClass
+{
+	GtkBinClass parent_class;
+};
+
+GType		 gedit_rounded_frame_get_type		(void) G_GNUC_CONST;
+
+GtkWidget	*gedit_rounded_frame_new		(void);
+
+G_END_DECLS
+
+#endif /* __GEDIT_ROUNDED_FRAME_H__ */
diff --git a/gedit/gedit-tab.c b/gedit/gedit-tab.c
index c6a5db2..245110e 100644
--- a/gedit/gedit-tab.c
+++ b/gedit/gedit-tab.c
@@ -2923,4 +2923,10 @@ gedit_tab_set_info_bar (GeditTab  *tab,
 	set_info_bar (tab, info_bar);
 }
 
+GtkWidget *
+_gedit_tab_get_view_frame (GeditTab *tab)
+{
+	return GTK_WIDGET (tab->priv->frame);
+}
+
 /* ex:ts=8:noet: */
diff --git a/gedit/gedit-tab.h b/gedit/gedit-tab.h
index 1b45989..0f25d79 100644
--- a/gedit/gedit-tab.h
+++ b/gedit/gedit-tab.h
@@ -175,6 +175,7 @@ void		 _gedit_tab_mark_for_closing	(GeditTab	     *tab);
 
 gboolean	 _gedit_tab_can_close		(GeditTab	     *tab);
 
+GtkWidget	*_gedit_tab_get_view_frame	(GeditTab            *tab);
 
 G_END_DECLS
 
diff --git a/gedit/gedit-view-frame.c b/gedit/gedit-view-frame.c
index 1c8ee7e..faa6f58 100644
--- a/gedit/gedit-view-frame.c
+++ b/gedit/gedit-view-frame.c
@@ -21,13 +21,59 @@
  */
 
 #include "gedit-view-frame.h"
+#include "gedit-marshal.h"
+#include "gedit-debug.h"
+#include "gedit-utils.h"
+#include "gedit-overlay.h"
+#include "gedit-rounded-frame.h"
 
+#include <gdk/gdkkeysyms.h>
+#include <glib/gi18n.h>
+#include <stdlib.h>
+
+#define GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */
+
+#define MIN_SEARCH_COMPLETION_KEY_LEN	3
 
 #define GEDIT_VIEW_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_VIEW_FRAME, GeditViewFramePrivate))
 
+typedef enum
+{
+	GOTO_LINE,
+	SEARCH
+} SearchMode;
+
 struct _GeditViewFramePrivate
 {
-	GtkWidget     *view;
+	GtkWidget   *view;
+	GtkWidget   *overlay;
+
+	SearchMode   search_mode;
+	SearchMode   request_search_mode;
+
+	GtkTextMark *start_mark;
+
+	/* used to restore the search state if an
+	 * incremental search is cancelled
+	 */
+	gchar       *old_search_text;
+	guint        old_search_flags;
+
+	/* used to remeber the state of the last
+	 * incremental search (the document search
+	 * state may be changed by the search dialog)
+	 */
+	guint        search_flags;
+
+	GtkWidget   *search_widget;
+	GtkWidget   *search_entry;
+
+	guint        typeselect_flush_timeout;
+	glong        view_scroll_event_id;
+	glong        search_entry_focus_out_id;
+
+	guint        disable_popdown : 1;
+	guint        wrap_around : 1;
 };
 
 enum
@@ -37,15 +83,42 @@ enum
 	PROP_VIEW
 };
 
+typedef enum
+{
+	GEDIT_SEARCH_ENTRY_NORMAL,
+	GEDIT_SEARCH_ENTRY_NOT_FOUND
+} GeditSearchEntryBgColor;
+
+/* The search entry completion is shared among all the views */
+GtkListStore *search_completion_model = NULL;
+
 G_DEFINE_TYPE (GeditViewFrame, gedit_view_frame, GTK_TYPE_VBOX)
 
 static void
 gedit_view_frame_finalize (GObject *object)
 {
+	GeditViewFrame *frame = GEDIT_VIEW_FRAME (object);
+
+	g_free (frame->priv->old_search_text);
+
 	G_OBJECT_CLASS (gedit_view_frame_parent_class)->finalize (object);
 }
 
 static void
+gedit_view_frame_dispose (GObject *object)
+{
+	GeditViewFrame *frame = GEDIT_VIEW_FRAME (object);
+
+	if (frame->priv->typeselect_flush_timeout != 0)
+	{
+		g_source_remove (frame->priv->typeselect_flush_timeout);
+		frame->priv->typeselect_flush_timeout = 0;
+	}
+
+	G_OBJECT_CLASS (gedit_view_frame_parent_class)->dispose (object);
+}
+
+static void
 gedit_view_frame_get_property (GObject    *object,
                                guint       prop_id,
                                GValue     *value,
@@ -70,11 +143,1124 @@ gedit_view_frame_get_property (GObject    *object,
 }
 
 static void
+hide_search_widget (GeditViewFrame *frame,
+                    gboolean        cancel)
+{
+	GtkTextBuffer *buffer;
+
+	if (frame->priv->disable_popdown)
+	{
+		return;
+	}
+
+	if (frame->priv->view_scroll_event_id != 0)
+	{
+		g_signal_handler_disconnect (frame->priv->view,
+		                             frame->priv->view_scroll_event_id);
+		frame->priv->view_scroll_event_id = 0;
+	}
+
+	if (frame->priv->search_entry_focus_out_id != 0)
+	{
+		g_signal_handler_disconnect (frame->priv->search_entry,
+		                             frame->priv->search_entry_focus_out_id);
+		frame->priv->search_entry_focus_out_id = 0;
+	}
+
+	if (frame->priv->typeselect_flush_timeout != 0)
+	{
+		g_source_remove (frame->priv->typeselect_flush_timeout);
+		frame->priv->typeselect_flush_timeout = 0;
+	}
+
+	gtk_widget_destroy (frame->priv->search_widget);
+	frame->priv->search_widget = NULL;
+
+	if (cancel)
+	{
+		GtkTextBuffer *buffer;
+		GtkTextIter iter;
+
+		buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view)));
+		gtk_text_buffer_get_iter_at_mark (buffer, &iter,
+		                                  frame->priv->start_mark);
+		gtk_text_buffer_place_cursor (buffer, &iter);
+
+		gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+	}
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+	gtk_text_buffer_delete_mark (buffer, frame->priv->start_mark);
+
+	/* Make sure the view is the one who has the focus when we destroy
+	   the search widget */
+	gtk_widget_grab_focus (frame->priv->view);
+}
+
+static void
+add_search_completion_entry (const gchar *str)
+{
+	gchar        *text;
+	gboolean      valid;
+	GtkTreeModel *model;
+	GtkTreeIter   iter;
+
+	if (str == NULL)
+		return;
+
+	text = gedit_utils_unescape_search_text (str);
+
+	if (g_utf8_strlen (text, -1) < MIN_SEARCH_COMPLETION_KEY_LEN)
+	{
+		g_free (text);
+		return;
+	}
+
+	g_return_if_fail (GTK_IS_TREE_MODEL (search_completion_model));
+
+	model = GTK_TREE_MODEL (search_completion_model);
+
+	/* Get the first iter in the list */
+	valid = gtk_tree_model_get_iter_first (model, &iter);
+
+	while (valid)
+	{
+		/* Walk through the list, reading each row */
+		gchar *str_data;
+
+		gtk_tree_model_get (model,
+		                    &iter,
+		                    0,
+		                    &str_data,
+		                    -1);
+
+		if (strcmp (text, str_data) == 0)
+		{
+			g_free (text);
+			g_free (str_data);
+			gtk_list_store_move_after (GTK_LIST_STORE (model),
+			                           &iter,
+			                           NULL);
+
+			return;
+		}
+
+		g_free (str_data);
+
+		valid = gtk_tree_model_iter_next (model, &iter);
+	}
+
+	gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
+	gtk_list_store_set (GTK_LIST_STORE (model),
+	                    &iter,
+	                    0,
+	                    text,
+	                    -1);
+
+	g_free (text);
+}
+
+static gboolean
+search_entry_flush_timeout (GeditViewFrame *frame)
+{
+	GDK_THREADS_ENTER ();
+
+	frame->priv->typeselect_flush_timeout = 0;
+	hide_search_widget (frame, FALSE);
+
+	GDK_THREADS_LEAVE ();
+
+	return FALSE;
+}
+
+static void
+set_entry_background (GtkWidget               *entry,
+                      GeditSearchEntryBgColor  col)
+{
+	if (col == GEDIT_SEARCH_ENTRY_NOT_FOUND)
+	{
+		GdkColor red;
+		GdkColor white;
+
+		/* FIXME: a11y and theme */
+
+		gdk_color_parse ("#FF6666", &red);
+		gdk_color_parse ("white", &white);
+
+		gtk_widget_modify_base (entry,
+		                        GTK_STATE_NORMAL,
+		                        &red);
+		gtk_widget_modify_text (entry,
+		                        GTK_STATE_NORMAL,
+		                        &white);
+	}
+	else /* reset */
+	{
+		gtk_widget_modify_base (entry,
+		                        GTK_STATE_NORMAL,
+		                        NULL);
+		gtk_widget_modify_text (entry,
+		                        GTK_STATE_NORMAL,
+		                        NULL);
+	}
+}
+
+static gboolean
+run_search (GeditViewFrame   *frame,
+            const gchar      *entry_text,
+            gboolean          search_backward,
+            gboolean          wrap_around,
+            gboolean          typing)
+{
+	GtkTextIter    start_iter;
+	GtkTextIter    match_start;
+	GtkTextIter    match_end;
+	gboolean       found = FALSE;
+	GeditDocument *doc;
+
+	g_return_val_if_fail (frame->priv->search_mode == SEARCH, FALSE);
+
+	doc = gedit_view_frame_get_document (frame);
+
+	gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+	                                  &start_iter,
+	                                  frame->priv->start_mark);
+
+	if (*entry_text != '\0')
+	{
+		if (!search_backward)
+		{
+			if (!typing)
+			{
+				/* forward and _NOT_ typing */
+				gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+				                                      &start_iter,
+				                                      &match_end);
+
+				gtk_text_iter_order (&match_end, &start_iter);
+			}
+
+			/* run search */
+			found = gedit_document_search_forward (doc,
+			                                       &start_iter,
+			                                       NULL,
+			                                       &match_start,
+			                                       &match_end);
+		}
+		else if (!typing)
+		{
+			/* backward and not typing */
+			gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+			                                      &start_iter,
+			                                      &match_end);
+
+			/* run search */
+			found = gedit_document_search_backward (doc,
+			                                        NULL,
+			                                        &start_iter,
+			                                        &match_start,
+			                                        &match_end);
+		}
+		else
+		{
+			/* backward (while typing) */
+			g_return_val_if_reached (FALSE);
+		}
+
+		if (!found && wrap_around)
+		{
+			if (!search_backward)
+			{
+				found = gedit_document_search_forward (doc,
+				                                       NULL,
+				                                       NULL, /* FIXME: set the end_inter */
+				                                       &match_start,
+				                                       &match_end);
+			}
+			else
+			{
+				found = gedit_document_search_backward (doc,
+				                                        NULL, /* FIXME: set the start_inter */
+				                                        NULL,
+				                                        &match_start,
+				                                        &match_end);
+			}
+		}
+	}
+	else
+	{
+		gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
+		                                      &start_iter,
+		                                      NULL);
+	}
+	
+	if (found)
+	{
+		gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+		                              &match_start);
+
+		gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
+		                                   "selection_bound", &match_end);
+	}
+	else if (typing)
+	{
+		gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+		                                  &start_iter,
+		                                  frame->priv->start_mark);
+		gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
+		                              &start_iter);
+	}
+
+	if (found || (*entry_text == '\0'))
+	{
+		gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+
+		set_entry_background (frame->priv->search_entry,
+		                      GEDIT_SEARCH_ENTRY_NORMAL);
+	}
+	else
+	{
+		set_entry_background (frame->priv->search_entry,
+		                      GEDIT_SEARCH_ENTRY_NOT_FOUND);
+	}
+
+	return found;
+}
+
+static void
+search_again (GeditViewFrame *frame,
+              gboolean        search_backward)
+{
+	const gchar *entry_text;
+
+	g_return_if_fail (frame->priv->search_mode == SEARCH);
+
+	/* SEARCH mode */
+	/* renew the flush timeout */
+	if (frame->priv->typeselect_flush_timeout != 0)
+	{
+		g_source_remove (frame->priv->typeselect_flush_timeout);
+		frame->priv->typeselect_flush_timeout =
+			g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+			               (GSourceFunc)search_entry_flush_timeout,
+			               frame);
+	}
+
+	entry_text = gtk_entry_get_text (GTK_ENTRY (frame->priv->search_entry));
+
+	add_search_completion_entry (entry_text);
+
+	run_search (frame,
+	            entry_text,
+	            search_backward,
+	            frame->priv->wrap_around,
+	            FALSE);
+}
+
+static gboolean
+search_widget_scroll_event (GtkWidget      *widget,
+                            GdkEventScroll *event,
+                            GeditViewFrame *frame)
+{
+	gboolean retval = FALSE;
+
+	if (frame->priv->search_mode == GOTO_LINE)
+		return retval;
+
+	/* SEARCH mode */
+	if (event->direction == GDK_SCROLL_UP)
+	{
+		search_again (frame, TRUE);
+		retval = TRUE;
+	}
+	else if (event->direction == GDK_SCROLL_DOWN)
+	{
+		search_again (frame, FALSE);
+		retval = TRUE;
+	}
+
+	return retval;
+}
+
+static gboolean
+search_widget_key_press_event (GtkWidget      *widget,
+                               GdkEventKey    *event,
+                               GeditViewFrame *frame)
+{
+	gboolean retval = FALSE;
+	guint modifiers;
+
+	modifiers = gtk_accelerator_get_default_mod_mask ();
+
+	/* Close window */
+	if (event->keyval == GDK_Tab)
+	{
+		hide_search_widget (frame, FALSE);
+		retval = TRUE;
+	}
+
+	/* Close window and cancel the search */
+	if (event->keyval == GDK_Escape)
+	{
+		if (frame->priv->search_mode == SEARCH)
+		{
+			GeditDocument *doc;
+
+			/* restore document search so that Find Next does the right thing */
+			doc = gedit_view_frame_get_document (frame);
+			gedit_document_set_search_text (doc,
+			                                frame->priv->old_search_text,
+			                                frame->priv->old_search_flags);
+		}
+
+		hide_search_widget (frame, TRUE);
+		retval = TRUE;
+	}
+
+	if (frame->priv->search_mode == GOTO_LINE)
+		return retval;
+
+	/* SEARCH mode */
+
+	/* select previous matching iter */
+	if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
+	{
+		search_again (frame, TRUE);
+		retval = TRUE;
+	}
+
+	if (((event->state & modifiers) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) && 
+	    (event->keyval == GDK_g || event->keyval == GDK_G))
+	{
+		search_again (frame, TRUE);
+		retval = TRUE;
+	}
+
+	/* select next matching iter */
+	if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
+	{
+		search_again (frame, FALSE);
+		retval = TRUE;
+	}
+
+	if (((event->state & modifiers) == GDK_CONTROL_MASK) && 
+	    (event->keyval == GDK_g || event->keyval == GDK_G))
+	{
+		search_again (frame, FALSE);
+		retval = TRUE;
+	}
+
+	return retval;
+}
+
+static void
+wrap_around_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+                               GeditViewFrame   *frame)
+{	
+	frame->priv->wrap_around = gtk_check_menu_item_get_active (checkmenuitem);
+}
+
+static void
+match_entire_word_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+                                     GeditViewFrame   *frame)
+{
+	GEDIT_SEARCH_SET_ENTIRE_WORD (frame->priv->search_flags,
+	                              gtk_check_menu_item_get_active (checkmenuitem));
+}
+
+static void
+match_case_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
+                              GeditViewFrame   *frame)
+{
+	GEDIT_SEARCH_SET_CASE_SENSITIVE (frame->priv->search_flags,
+	                                 gtk_check_menu_item_get_active (checkmenuitem));
+}
+
+static void
+add_popup_menu_items (GtkWidget      *menu,
+                      GeditViewFrame *frame)
+{
+	GtkWidget *menu_item;
+
+	/* create "Wrap Around" menu item. */
+	menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Wrap Around"));
+	g_signal_connect (G_OBJECT (menu_item), "toggled",
+			  G_CALLBACK (wrap_around_menu_item_toggled),
+			  frame);
+	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+					frame->priv->wrap_around);
+	gtk_widget_show (menu_item);
+
+	/* create "Match Entire Word Only" menu item. */
+	menu_item = gtk_check_menu_item_new_with_mnemonic (_("Match _Entire Word Only"));
+	g_signal_connect (G_OBJECT (menu_item), "toggled",
+			  G_CALLBACK (match_entire_word_menu_item_toggled),
+			  frame);
+	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+					GEDIT_SEARCH_IS_ENTIRE_WORD (frame->priv->search_flags));
+	gtk_widget_show (menu_item);
+
+	/* create "Match Case" menu item. */
+	menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Match Case"));
+	g_signal_connect (G_OBJECT (menu_item), "toggled",
+			  G_CALLBACK (match_case_menu_item_toggled),
+			  frame);
+	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
+					GEDIT_SEARCH_IS_CASE_SENSITIVE (frame->priv->search_flags));
+	gtk_widget_show (menu_item);
+}
+
+static gboolean
+real_search_enable_popdown (gpointer data)
+{
+	GeditViewFrame *frame = GEDIT_VIEW_FRAME (data);
+
+	GDK_THREADS_ENTER ();
+
+	frame->priv->disable_popdown = FALSE;
+
+	GDK_THREADS_LEAVE ();
+
+	return FALSE;
+}
+
+static void
+search_enable_popdown (GtkWidget      *widget,
+                       GeditViewFrame *frame)
+{
+	g_timeout_add (200, real_search_enable_popdown, frame);
+
+	/* renew the flush timeout */
+	if (frame->priv->typeselect_flush_timeout != 0)
+		g_source_remove (frame->priv->typeselect_flush_timeout);
+
+	frame->priv->typeselect_flush_timeout =
+		g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+		               (GSourceFunc)search_entry_flush_timeout,
+		               frame);
+}
+
+static void
+search_entry_populate_popup (GtkEntry       *entry,
+                             GtkMenu        *menu,
+                             GeditViewFrame *frame)
+{
+	GtkWidget *menu_item;
+
+	frame->priv->disable_popdown = TRUE;
+	g_signal_connect (menu, "hide",
+			  G_CALLBACK (search_enable_popdown), frame);
+
+	if (frame->priv->search_mode == GOTO_LINE)
+		return;
+
+	/* separator */
+	menu_item = gtk_menu_item_new ();
+	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+	gtk_widget_show (menu_item);
+
+	add_popup_menu_items (GTK_WIDGET (menu), frame);
+}
+
+static void
+search_entry_icon_release (GtkEntry            *entry,
+                           GtkEntryIconPosition icon_pos,
+                           GdkEventButton      *event,
+                           GeditViewFrame      *frame)
+{
+	GtkWidget *menu;
+
+	if (frame->priv->search_mode == GOTO_LINE ||
+	    icon_pos != GTK_ENTRY_ICON_PRIMARY)
+		return;
+
+	menu = gtk_menu_new ();
+	gtk_widget_show (menu);
+
+	frame->priv->disable_popdown = TRUE;
+	g_signal_connect (menu, "hide",
+	                  G_CALLBACK (search_enable_popdown), frame);
+
+	add_popup_menu_items (menu, frame);
+
+	gtk_menu_popup (GTK_MENU (menu),
+	                NULL, NULL,
+	                NULL, NULL,
+	                event->button, event->time);
+}
+
+static void
+search_entry_activate (GtkEntry       *entry,
+                       GeditViewFrame *frame)
+{
+	hide_search_widget (frame, FALSE);
+}
+
+static void
+search_entry_insert_text (GtkEditable    *editable,
+                          const gchar    *text,
+                          gint            length,
+                          gint           *position,
+                          GeditViewFrame *frame)
+{
+	if (frame->priv->search_mode == GOTO_LINE)
+	{
+		gunichar c;
+		const gchar *p;
+		const gchar *end;
+		const gchar *next;
+
+		p = text;
+		end = text + length;
+
+		if (p == end)
+			return;
+
+		c = g_utf8_get_char (p);
+		
+		if (((c == '-' || c == '+') && *position == 0) ||
+		    (c == ':' && *position != 0))
+		{
+			gchar *s = NULL;
+		
+			if (c == ':')
+			{
+				s = gtk_editable_get_chars (editable, 0, -1);
+				s = g_utf8_strchr (s, -1, ':');
+			}
+			
+			if (s == NULL || s == p)
+			{
+				next = g_utf8_next_char (p);
+				p = next;
+			}
+			
+			g_free (s);
+		}
+
+		while (p != end)
+		{
+			next = g_utf8_next_char (p);
+
+			c = g_utf8_get_char (p);
+
+			if (!g_unichar_isdigit (c))
+			{
+				g_signal_stop_emission_by_name (editable, "insert_text");
+				gtk_widget_error_bell (frame->priv->search_entry);
+				break;
+			}
+
+			p = next;
+		}
+	}
+	else
+	{
+		/* SEARCH mode */
+		static gboolean  insert_text = FALSE;
+		gchar           *escaped_text;
+		gint             new_len;
+
+		gedit_debug_message (DEBUG_SEARCH, "Text: %s", text);
+
+		/* To avoid recursive behavior */
+		if (insert_text)
+			return;
+
+		escaped_text = gedit_utils_escape_search_text (text);
+
+		gedit_debug_message (DEBUG_SEARCH, "Escaped Text: %s", escaped_text);
+
+		new_len = strlen (escaped_text);
+
+		if (new_len == length)
+		{
+			g_free (escaped_text);
+			return;
+		}
+
+		insert_text = TRUE;
+
+		g_signal_stop_emission_by_name (editable, "insert_text");
+		
+		gtk_editable_insert_text (editable, escaped_text, new_len, position);
+
+		insert_text = FALSE;
+
+		g_free (escaped_text);
+	}
+}
+
+static gboolean
+completion_func (GtkEntryCompletion *completion,
+                 const gchar        *key,
+		 GtkTreeIter        *iter,
+		 gpointer            data)
+{
+	gchar *item = NULL;
+	gboolean ret = FALSE;
+	GtkTreeModel *model;
+	GeditViewFramePrivate *priv = GEDIT_VIEW_FRAME (data)->priv;
+	const gchar *real_key;
+
+	if (priv->search_mode == GOTO_LINE)
+		return FALSE;
+
+	real_key = gtk_entry_get_text (GTK_ENTRY (gtk_entry_completion_get_entry (completion)));
+
+	if (g_utf8_strlen (real_key, -1) <= MIN_SEARCH_COMPLETION_KEY_LEN)
+		return FALSE;
+
+	model = gtk_entry_completion_get_model (completion);
+	g_return_val_if_fail (gtk_tree_model_get_column_type (model, 0) == G_TYPE_STRING,
+	                      FALSE);
+
+	gtk_tree_model_get (model,
+	                    iter,
+	                    0,
+	                    &item,
+	                    -1);
+
+	if (item == NULL)
+		return FALSE;
+
+	if (GEDIT_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
+	{
+		if (!strncmp (real_key, item, strlen (real_key)))
+			ret = TRUE;
+	}
+	else
+	{
+		gchar *normalized_string;
+		gchar *case_normalized_string;
+		
+		normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
+		case_normalized_string = g_utf8_casefold (normalized_string, -1);
+
+		if (!strncmp (key, case_normalized_string, strlen (key)))
+			ret = TRUE;
+
+		g_free (normalized_string);
+		g_free (case_normalized_string);
+	}
+
+	g_free (item);
+
+	return ret;
+}
+
+static void
+customize_for_search_mode (GeditViewFrame *frame)
+{
+	if (frame->priv->search_mode == SEARCH)
+	{
+		gtk_entry_set_icon_from_stock (GTK_ENTRY (frame->priv->search_entry),
+		                               GTK_ENTRY_ICON_PRIMARY,
+		                               GTK_STOCK_FIND);
+
+		gtk_widget_set_tooltip_text (frame->priv->search_entry,
+		                             _("String you want to search for"));
+	}
+	else
+	{
+		gtk_entry_set_icon_from_stock (GTK_ENTRY (frame->priv->search_entry),
+		                               GTK_ENTRY_ICON_PRIMARY,
+		                               GTK_STOCK_JUMP_TO);
+
+		gtk_widget_set_tooltip_text (frame->priv->search_entry,
+		                             _("Line you want to move the cursor to"));
+	}
+}
+
+static void
+search_init (GtkWidget      *entry,
+             GeditViewFrame *frame)
+{
+	GeditDocument *doc;
+	const gchar *entry_text;
+
+	/* renew the flush timeout */
+	if (frame->priv->typeselect_flush_timeout != 0)
+	{
+		g_source_remove (frame->priv->typeselect_flush_timeout);
+		frame->priv->typeselect_flush_timeout =
+			g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+			               (GSourceFunc)search_entry_flush_timeout,
+			               frame);
+	}
+
+	doc = gedit_view_frame_get_document (frame);
+
+	entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
+
+	if (frame->priv->search_mode == SEARCH)
+	{
+		gchar *search_text;
+		guint  search_flags;
+
+		search_text = gedit_document_get_search_text (doc, &search_flags);
+
+		if ((search_text == NULL) ||
+		    (strcmp (search_text, entry_text) != 0) ||
+		     search_flags != frame->priv->search_flags)
+		{
+			gedit_document_set_search_text (doc,
+			                                entry_text,
+			                                frame->priv->search_flags);
+		}
+
+		g_free (search_text);
+
+		run_search (frame,
+		            entry_text,
+		            FALSE,
+		            frame->priv->wrap_around,
+		            TRUE);
+	}
+	else
+	{
+		if (*entry_text != '\0')
+		{
+			gboolean moved, moved_offset;
+			gint line;
+			gint offset_line = 0;
+			gint line_offset = 0;
+			gchar **split_text = NULL;
+			const gchar *text;
+			GtkTextIter iter;
+
+			gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc),
+			                                  &iter,
+			                                  frame->priv->start_mark);
+
+			split_text = g_strsplit (entry_text, ":", -1);
+
+			if (g_strv_length (split_text) > 1)
+			{
+				text = split_text[0];
+			}
+			else
+			{
+				text = entry_text;
+			}
+
+			if (*text == '-')
+			{
+				gint cur_line = gtk_text_iter_get_line (&iter);
+
+				if (*(text + 1) != '\0')
+					offset_line = MAX (atoi (text + 1), 0);
+
+				line = MAX (cur_line - offset_line, 0);
+			}
+			else if (*entry_text == '+')
+			{
+				gint cur_line = gtk_text_iter_get_line (&iter);
+
+				if (*(text + 1) != '\0')
+					offset_line = MAX (atoi (text + 1), 0);
+
+				line = cur_line + offset_line;
+			}
+			else
+			{
+				line = MAX (atoi (text) - 1, 0);
+			}
+
+			if (split_text[1] != NULL)
+			{
+				line_offset = atoi (split_text[1]);
+			}
+
+			g_strfreev (split_text);
+
+			moved = gedit_document_goto_line (doc, line);
+			moved_offset = gedit_document_goto_line_offset (doc, line,
+			                                                line_offset);
+
+			gedit_view_scroll_to_cursor (GEDIT_VIEW (frame->priv->view));
+
+			if (!moved || !moved_offset)
+			{
+				set_entry_background (frame->priv->search_entry,
+				                      GEDIT_SEARCH_ENTRY_NOT_FOUND);
+			}
+			else
+			{
+				set_entry_background (frame->priv->search_entry,
+				                      GEDIT_SEARCH_ENTRY_NORMAL);
+			}
+		}
+	}
+}
+
+static gboolean
+search_entry_focus_out_event (GtkWidget      *widget,
+                              GdkEventFocus  *event,
+                              GeditViewFrame *frame)
+{
+	/* hide interactive search dialog */
+	hide_search_widget (frame, FALSE);
+
+	return FALSE;
+}
+
+static GtkWidget *
+create_search_widget (GeditViewFrame *frame)
+{
+	GtkWidget          *search_widget;
+	GtkWidget          *vbox;
+	GtkEntryCompletion *completion;
+
+	search_widget = gedit_rounded_frame_new ();
+	gtk_widget_show (search_widget);
+
+	g_signal_connect (search_widget, "key-press-event",
+	                  G_CALLBACK (search_widget_key_press_event),
+	                  frame);
+	g_signal_connect (search_widget, "scroll-event",
+	                  G_CALLBACK (search_widget_scroll_event),
+	                  frame);
+	/* Manage the scroll also for the view */
+	frame->priv->view_scroll_event_id =
+		g_signal_connect (frame->priv->view, "scroll-event",
+			          G_CALLBACK (search_widget_scroll_event),
+			          frame);
+
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_widget_show (vbox);
+	gtk_container_add (GTK_CONTAINER (search_widget), vbox);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
+
+	/* add entry */
+	frame->priv->search_entry = gtk_entry_new ();
+	gtk_widget_show (frame->priv->search_entry);
+
+	g_signal_connect (frame->priv->search_entry, "populate-popup",
+	                  G_CALLBACK (search_entry_populate_popup),
+	                  frame);
+	g_signal_connect (frame->priv->search_entry, "icon-release",
+	                  G_CALLBACK (search_entry_icon_release),
+	                  frame);
+	g_signal_connect (frame->priv->search_entry, "activate",
+	                  G_CALLBACK (search_entry_activate),
+	                  frame);
+	g_signal_connect (frame->priv->search_entry, "insert_text",
+	                  G_CALLBACK (search_entry_insert_text),
+	                  frame);
+	g_signal_connect (frame->priv->search_entry, "changed",
+	                  G_CALLBACK (search_init),
+	                  frame);
+	frame->priv->search_entry_focus_out_id =
+		g_signal_connect (frame->priv->search_entry, "focus-out-event",
+			          G_CALLBACK (search_entry_focus_out_event),
+			          frame);
+
+	gtk_container_add (GTK_CONTAINER (vbox),
+	                   frame->priv->search_entry);
+
+	if (search_completion_model == NULL)
+	{
+		/* Create a tree model and use it as the completion model */
+		search_completion_model = gtk_list_store_new (1, G_TYPE_STRING);
+	}
+
+	/* Create the completion object for the search entry */
+	completion = gtk_entry_completion_new ();
+	gtk_entry_completion_set_model (completion,
+	                                GTK_TREE_MODEL (search_completion_model));
+
+	/* Use model column 0 as the text column */
+	gtk_entry_completion_set_text_column (completion, 0);
+
+	gtk_entry_completion_set_minimum_key_length (completion,
+	                                             MIN_SEARCH_COMPLETION_KEY_LEN);
+
+	gtk_entry_completion_set_popup_completion (completion, FALSE);
+	gtk_entry_completion_set_inline_completion (completion, TRUE);
+
+	gtk_entry_completion_set_match_func (completion,
+	                                     completion_func,
+	                                     frame,
+	                                     NULL);
+
+	/* Assign the completion to the entry */
+	gtk_entry_set_completion (GTK_ENTRY (frame->priv->search_entry),
+	                          completion);
+	g_object_unref (completion);
+
+	customize_for_search_mode (frame);
+
+	return search_widget;
+}
+
+static gboolean
+get_selected_text (GtkTextBuffer *doc, gchar **selected_text, gint *len)
+{
+	GtkTextIter start, end;
+
+	g_return_val_if_fail (selected_text != NULL, FALSE);
+	g_return_val_if_fail (*selected_text == NULL, FALSE);
+
+	if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
+	{
+		if (len != NULL)
+			len = 0;
+
+		return FALSE;
+	}
+
+	*selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
+
+	if (len != NULL)
+		*len = g_utf8_strlen (*selected_text, -1);
+
+	return TRUE;
+}
+
+static void
+init_search_entry (GeditViewFrame *frame)
+{
+	GtkTextBuffer *buffer;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+
+	if (frame->priv->search_mode == GOTO_LINE)
+	{
+		gint   line;
+		gchar *line_str;
+		GtkTextIter iter;
+
+		gtk_text_buffer_get_iter_at_mark (buffer,
+		                                  &iter,
+		                                  frame->priv->start_mark);
+
+		line = gtk_text_iter_get_line (&iter);
+
+		line_str = g_strdup_printf ("%d", line + 1);
+
+		gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+		                    line_str);
+
+		g_free (line_str);
+
+		return;
+	}
+	else
+	{
+		/* SEARCH mode */
+		gboolean  selection_exists;
+		gchar    *find_text = NULL;
+		gchar    *old_find_text;
+		guint     old_find_flags = 0;
+		gint      sel_len = 0;
+
+		g_free (frame->priv->old_search_text);
+
+		old_find_text = gedit_document_get_search_text (GEDIT_DOCUMENT (buffer),
+		                                                &old_find_flags);
+		if (old_find_text != NULL)
+		{
+			frame->priv->old_search_text = old_find_text;
+			add_search_completion_entry (old_find_text);
+		}
+
+		if (old_find_flags != 0)
+		{
+			frame->priv->old_search_flags = old_find_flags;
+		}
+
+		selection_exists = get_selected_text (buffer,
+		                                      &find_text,
+		                                      &sel_len);
+
+		if (selection_exists  && (find_text != NULL) && (sel_len <= 160))
+		{
+			gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+			                    find_text);
+		}
+		else
+		{
+			gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry),
+			                    "");
+		}
+
+		g_free (find_text);
+	}
+}
+
+static gboolean
+start_interactive_search_real (GeditViewFrame *frame)
+{
+	GtkTextBuffer *buffer;
+	GtkTextMark *mark;
+	GtkTextIter iter;
+
+	/* FIXME: it enters here twice, why? */
+
+	if ((frame->priv->search_widget != NULL) &&
+	    gtk_widget_get_visible (frame->priv->search_widget))
+	{
+		if (frame->priv->search_mode != frame->priv->request_search_mode)
+		{
+			hide_search_widget (frame, TRUE);
+		}
+		else
+		{
+			return TRUE;
+		}
+	}
+
+	frame->priv->search_mode = frame->priv->request_search_mode;
+
+	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view));
+
+	if (frame->priv->search_mode == SEARCH)
+	{
+		mark = gtk_text_buffer_get_selection_bound (buffer);
+	}
+	else
+	{
+		mark = gtk_text_buffer_get_insert (buffer);
+	}
+
+	gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+	frame->priv->start_mark = gtk_text_buffer_create_mark (buffer, NULL,
+	                                                       &iter, FALSE);
+
+	frame->priv->search_widget = create_search_widget (frame);
+
+	gedit_overlay_add_animated_widget (GEDIT_OVERLAY (frame->priv->overlay),
+	                                   frame->priv->search_widget,
+	                                   300,
+	                                   GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+	                                   GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+	                                   GTK_ORIENTATION_VERTICAL,
+	                                   0, 0);
+
+	init_search_entry (frame);
+
+	frame->priv->typeselect_flush_timeout =
+		g_timeout_add (GEDIT_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT,
+		               (GSourceFunc) search_entry_flush_timeout,
+		               frame);
+
+	/* We need to grab the focus after the widget has been added */
+	gtk_widget_grab_focus (frame->priv->search_entry);
+
+	return TRUE;
+}
+
+static void
 gedit_view_frame_class_init (GeditViewFrameClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
 	object_class->finalize = gedit_view_frame_finalize;
+	object_class->dispose = gedit_view_frame_dispose;
 	object_class->get_property = gedit_view_frame_get_property;
 
 	g_object_class_install_property (object_class, PROP_DOCUMENT,
@@ -109,6 +1295,42 @@ view_frame_mount_operation_factory (GeditDocument   *doc,
 }
 
 static void
+on_view_size_allocate (GeditView      *view,
+                       GtkAllocation  *allocation,
+                       GeditViewFrame *frame)
+{
+	if (frame->priv->search_widget != NULL)
+	{
+		GtkAllocation widget_alloc;
+
+		gtk_widget_get_allocation (frame->priv->search_widget,
+		                           &widget_alloc);
+		gedit_overlay_move_widget (GEDIT_OVERLAY (frame->priv->overlay),
+		                           frame->priv->search_widget,
+		                           allocation->width - widget_alloc.width - 8,
+		                           0);
+	}
+}
+
+static gboolean
+on_start_interactive_search (GeditView      *view,
+                             GeditViewFrame *frame)
+{
+	frame->priv->request_search_mode = SEARCH;
+
+	return start_interactive_search_real (frame);
+}
+
+static gboolean
+on_start_interactive_goto_line (GeditView      *view,
+                                GeditViewFrame *frame)
+{
+	frame->priv->request_search_mode = GOTO_LINE;
+
+	return start_interactive_search_real (frame);
+}
+
+static void
 gedit_view_frame_init (GeditViewFrame *frame)
 {
 	GeditDocument *doc;
@@ -116,6 +1338,9 @@ gedit_view_frame_init (GeditViewFrame *frame)
 
 	frame->priv = GEDIT_VIEW_FRAME_GET_PRIVATE (frame);
 
+	frame->priv->typeselect_flush_timeout = 0;
+	frame->priv->wrap_around = TRUE;
+
 	doc = gedit_document_new ();
 
 	_gedit_document_set_mount_operation_factory (doc,
@@ -127,14 +1352,34 @@ gedit_view_frame_init (GeditViewFrame *frame)
 
 	g_object_unref (doc);
 
+	/* TODO: connect it when the search widget exists */
+	g_signal_connect_after (frame->priv->view,
+	                        "size-allocate",
+	                        G_CALLBACK (on_view_size_allocate),
+	                        frame);
+
+	g_signal_connect (frame->priv->view,
+	                  "start-interactive-search",
+	                  G_CALLBACK (on_start_interactive_search),
+	                  frame);
+
+	g_signal_connect (frame->priv->view,
+	                  "start-interactive-goto-line",
+	                  G_CALLBACK (on_start_interactive_goto_line),
+	                  frame);
+
+	frame->priv->overlay = gedit_overlay_new (frame->priv->view);
+	gtk_widget_show (frame->priv->overlay);
+
 	/* Create the scrolled window */
 	sw = gtk_scrolled_window_new (NULL, NULL);
 
+	gtk_container_add (GTK_CONTAINER (sw), frame->priv->overlay);
+
 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
 					GTK_POLICY_AUTOMATIC,
 					GTK_POLICY_AUTOMATIC);
 
-	gtk_container_add (GTK_CONTAINER (sw), frame->priv->view);
 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
 					     GTK_SHADOW_IN);
 	gtk_widget_show (sw);
diff --git a/gedit/gedit-view.c b/gedit/gedit-view.c
index 65a3354..a8610f0 100644
--- a/gedit/gedit-view.c
+++ b/gedit/gedit-view.c
@@ -52,9 +52,6 @@
 #include "gedit-app.h"
 
 #define GEDIT_VIEW_SCROLL_MARGIN 0.02
-#define GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */
-
-#define MIN_SEARCH_COMPLETION_KEY_LEN	3
 
 #define GEDIT_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), GEDIT_TYPE_VIEW, GeditViewPrivate))
 
@@ -72,40 +69,12 @@ enum
 struct _GeditViewPrivate
 {
 	GSettings   *editor_settings;
-
-	SearchMode   search_mode;
-	
-	GtkTextIter  start_search_iter;
-
-	/* used to restore the search state if an
-	 * incremental search is cancelled
-	 */
- 	gchar       *old_search_text;
-	guint        old_search_flags;
-
-	/* used to remeber the state of the last
-	 * incremental search (the document search
-	 * state may be changed by the search dialog)
-	 */
-	guint        search_flags;
-	gboolean     wrap_around;
-
-	GtkWidget   *search_window;
-	GtkWidget   *search_entry;
-
-	guint        typeselect_flush_timeout;
-	guint        search_entry_changed_id;
-	
-	gboolean     disable_popdown;
 	
 	GtkTextBuffer *current_buffer;
 
 	PeasExtensionSet *extensions;
 };
 
-/* The search entry completion is shared among all the views */
-GtkListStore *search_completion_model = NULL;
-
 static void	gedit_view_destroy		(GtkObject        *object);
 static void	gedit_view_finalize		(GObject          *object);
 static gint     gedit_view_focus_out		(GtkWidget        *widget,
@@ -131,13 +100,8 @@ static gboolean	gedit_view_button_press_event	(GtkWidget        *widget,
 						 GdkEventButton   *event);
 static void	gedit_view_realize		(GtkWidget        *widget);
 
-static gboolean start_interactive_search	(GeditView        *view);
-static gboolean start_interactive_goto_line	(GeditView        *view);
 static gboolean reset_searched_text		(GeditView        *view);
 
-static void	hide_search_window 		(GeditView        *view,
-						 gboolean          cancel);
-
 
 static gint	gedit_view_expose	 	(GtkWidget        *widget,
 						 GdkEventExpose   *event);
@@ -164,12 +128,6 @@ enum
 
 static guint view_signals [LAST_SIGNAL] = { 0 };
 
-typedef enum
-{
-	GEDIT_SEARCH_ENTRY_NORMAL,
-	GEDIT_SEARCH_ENTRY_NOT_FOUND
-} GeditSearchEntryBgColor;
-
 static void
 document_read_only_notify_handler (GeditDocument *document, 
 			           GParamSpec    *pspec,
@@ -216,38 +174,36 @@ gedit_view_class_init (GeditViewClass *klass)
 	widget_class->drag_drop = gedit_view_drag_drop;
 	widget_class->button_press_event = gedit_view_button_press_event;
 	widget_class->realize = gedit_view_realize;
-	klass->start_interactive_search = start_interactive_search;
-	klass->start_interactive_goto_line = start_interactive_goto_line;
-	klass->reset_searched_text = reset_searched_text;	
+	klass->reset_searched_text = reset_searched_text;
 
 	text_view_class->delete_from_cursor = gedit_view_delete_from_cursor;
-	
+
 	view_signals[START_INTERACTIVE_SEARCH] =
-    		g_signal_new ("start_interactive_search",
-		  	      G_TYPE_FROM_CLASS (object_class),
-		  	      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		  	      G_STRUCT_OFFSET (GeditViewClass, start_interactive_search),
-			      NULL, NULL,
-			      gedit_marshal_BOOLEAN__NONE,
-			      G_TYPE_BOOLEAN, 0);	
+		g_signal_new ("start-interactive-search",
+		              G_TYPE_FROM_CLASS (object_class),
+		              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		              G_STRUCT_OFFSET (GeditViewClass, start_interactive_search),
+		              NULL, NULL,
+		              gedit_marshal_BOOLEAN__NONE,
+		              G_TYPE_BOOLEAN, 0);
 
 	view_signals[START_INTERACTIVE_GOTO_LINE] =
-    		g_signal_new ("start_interactive_goto_line",
-		  	      G_TYPE_FROM_CLASS (object_class),
-		  	      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		  	      G_STRUCT_OFFSET (GeditViewClass, start_interactive_goto_line),
-			      NULL, NULL,
-			      gedit_marshal_BOOLEAN__NONE,
-			      G_TYPE_BOOLEAN, 0);
+		g_signal_new ("start-interactive-goto-line",
+		              G_TYPE_FROM_CLASS (object_class),
+		              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		              G_STRUCT_OFFSET (GeditViewClass, start_interactive_goto_line),
+		              NULL, NULL,
+		              gedit_marshal_BOOLEAN__NONE,
+		              G_TYPE_BOOLEAN, 0);
 
 	view_signals[RESET_SEARCHED_TEXT] =
-    		g_signal_new ("reset_searched_text",
-		  	      G_TYPE_FROM_CLASS (object_class),
-		  	      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-		  	      G_STRUCT_OFFSET (GeditViewClass, reset_searched_text),
+		g_signal_new ("reset-searched-text",
+			      G_TYPE_FROM_CLASS (object_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+			      G_STRUCT_OFFSET (GeditViewClass, reset_searched_text),
 			      NULL, NULL,
 			      gedit_marshal_BOOLEAN__NONE,
-			      G_TYPE_BOOLEAN, 0);		
+			      G_TYPE_BOOLEAN, 0);
 
 	/* A new signal DROP_URIS has been added to allow plugins to intercept
 	 * the default dnd behaviour of 'text/uri-list'. GeditView now handles
@@ -270,17 +226,17 @@ gedit_view_class_init (GeditViewClass *klass)
 	g_type_class_add_private (klass, sizeof (GeditViewPrivate));
 	
 	binding_set = gtk_binding_set_by_class (klass);
-	
+
 	gtk_binding_entry_add_signal (binding_set,
-				      GDK_k,
-				      GDK_CONTROL_MASK,
-				      "start_interactive_search", 0);
-		
+	                              GDK_k,
+	                              GDK_CONTROL_MASK,
+	                              "start-interactive-search", 0);
+
 	gtk_binding_entry_add_signal (binding_set,
-				      GDK_i,
-				      GDK_CONTROL_MASK,
-				      "start_interactive_goto_line", 0);
-	
+	                              GDK_i,
+	                              GDK_CONTROL_MASK,
+	                              "start-interactive-goto-line", 0);
+
 	gtk_binding_entry_add_signal (binding_set,
 				      GDK_k,
 				      GDK_CONTROL_MASK | GDK_SHIFT_MASK,
@@ -438,9 +394,6 @@ gedit_view_init (GeditView *view)
 		      "indent_on_tab", TRUE,
 		      NULL);
 
-	view->priv->typeselect_flush_timeout = 0;
-	view->priv->wrap_around = TRUE;
-
 	/* Drag and drop support */	
 	tl = gtk_drag_dest_get_target_list (GTK_WIDGET (view));
 
@@ -481,19 +434,6 @@ gedit_view_destroy (GtkObject *object)
 		view->priv->extensions = NULL;
 	}
 
-	if (view->priv->search_window != NULL)
-	{
-		gtk_widget_destroy (view->priv->search_window);
-		view->priv->search_window = NULL;
-		view->priv->search_entry = NULL;
-		
-		if (view->priv->typeselect_flush_timeout != 0)
-		{
-			g_source_remove (view->priv->typeselect_flush_timeout);
-			view->priv->typeselect_flush_timeout = 0;
-		}
-	}
-	
 	/* Disconnect notify buffer because the destroy of the textview will
 	   set the buffer to NULL, and we call get_buffer in the notify which
 	   would reinstate a GtkTextBuffer which we don't want */
@@ -505,7 +445,7 @@ gedit_view_destroy (GtkObject *object)
 		g_object_unref (view->priv->editor_settings);
 		view->priv->editor_settings = NULL;
 	}
-	
+
 	(* GTK_OBJECT_CLASS (gedit_view_parent_class)->destroy) (object);
 }
 
@@ -518,24 +458,16 @@ gedit_view_finalize (GObject *object)
 
 	current_buffer_removed (view);
 
-	g_free (view->priv->old_search_text);
-
 	(* G_OBJECT_CLASS (gedit_view_parent_class)->finalize) (object);
 }
 
 static gint
 gedit_view_focus_out (GtkWidget *widget, GdkEventFocus *event)
 {
-	GeditView *view = GEDIT_VIEW (widget);
-	
 	gtk_widget_queue_draw (widget);
-	
-	/* hide interactive search dialog */
-	if (view->priv->search_window != NULL)
-		hide_search_window (view, FALSE);
-	
+
 	(* GTK_WIDGET_CLASS (gedit_view_parent_class)->focus_out_event) (widget, event);
-	
+
 	return FALSE;
 }
 
@@ -776,1163 +708,6 @@ gedit_view_set_font (GeditView   *view,
 	pango_font_description_free (font_desc);
 }
 
-static void
-add_search_completion_entry (const gchar *str)
-{
-	gchar        *text;
-	gboolean      valid;
-	GtkTreeModel *model;
-	GtkTreeIter   iter;
-
-	if (str == NULL)
-		return;
-
-	text = gedit_utils_unescape_search_text (str);
-
-	if (g_utf8_strlen (text, -1) < MIN_SEARCH_COMPLETION_KEY_LEN)
-	{
-		g_free (text);
-		return;
-	}
-
-	g_return_if_fail (GTK_IS_TREE_MODEL (search_completion_model));
-
-	model = GTK_TREE_MODEL (search_completion_model);	
-
-	/* Get the first iter in the list */
-	valid = gtk_tree_model_get_iter_first (model, &iter);
-
-	while (valid)
-	{
-		/* Walk through the list, reading each row */
-     		gchar *str_data;
-
-		gtk_tree_model_get (model, 
-				    &iter, 
-                          	    0, 
-                          	    &str_data,
-                          	    -1);
-
-		if (strcmp (text, str_data) == 0)
-		{
-			g_free (text);
-			g_free (str_data);
-			gtk_list_store_move_after (GTK_LIST_STORE (model),
-						   &iter,
-						   NULL);
-
-			return;
-		}
-
-		g_free (str_data);
-
-		valid = gtk_tree_model_iter_next (model, &iter);
-    	}
-
-	gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
-	gtk_list_store_set (GTK_LIST_STORE (model),
-			    &iter,
-			    0,
-			    text,
-			    -1);
-
-	g_free (text);
-}
-
-static void
-set_entry_background (GtkWidget               *entry,
-		      GeditSearchEntryBgColor  col)
-{
-	if (col == GEDIT_SEARCH_ENTRY_NOT_FOUND)
-	{
-		GdkColor red;
-		GdkColor white;
-
-		/* FIXME: a11y and theme */
-
-		gdk_color_parse ("#FF6666", &red);
-		gdk_color_parse ("white", &white);
-
-		gtk_widget_modify_base (entry,
-				        GTK_STATE_NORMAL,
-				        &red);
-		gtk_widget_modify_text (entry,
-				        GTK_STATE_NORMAL,
-				        &white);
-	}
-	else /* reset */
-	{
-		gtk_widget_modify_base (entry,
-				        GTK_STATE_NORMAL,
-				        NULL);
-		gtk_widget_modify_text (entry,
-				        GTK_STATE_NORMAL,
-				        NULL);
-	}
-}
-
-static gboolean
-run_search (GeditView        *view,
-            const gchar      *entry_text,
-	    gboolean          search_backward,
-	    gboolean          wrap_around,
-            gboolean          typing)
-{
-	GtkTextIter    start_iter;
-	GtkTextIter    match_start;
-	GtkTextIter    match_end;	
-	gboolean       found = FALSE;
-	GeditDocument *doc;
-
-	g_return_val_if_fail (view->priv->search_mode == SEARCH, FALSE);
-
-	doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-	
-	start_iter = view->priv->start_search_iter;
-	
-	if (*entry_text != '\0')
-	{	
-		if (!search_backward)
-		{
-			if (!typing)
-			{
-				/* forward and _NOT_ typing */
-				gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
-							      &start_iter,
-							      &match_end);
-		
-				gtk_text_iter_order (&match_end, &start_iter);
-			}
-		
-			/* run search */
-			found = gedit_document_search_forward (doc,
-							       &start_iter,
-							       NULL,
-							       &match_start,
-							       &match_end);
-		}						       
-		else if (!typing)
-		{
-			/* backward and not typing */
-			gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
-							      &start_iter,
-							      &match_end);
-			
-			/* run search */
-			found = gedit_document_search_backward (doc,
-							        NULL,
-							        &start_iter,
-							        &match_start,
-							        &match_end);
-		} 
-		else
-		{
-			/* backward (while typing) */
-			g_return_val_if_reached (FALSE);
-
-		}
-		
-		if (!found && wrap_around)
-		{
-			if (!search_backward)
-			{
-				found = gedit_document_search_forward (doc,
-								       NULL,
-								       NULL, /* FIXME: set the end_inter */
-								       &match_start,
-								       &match_end);
-			}
-			else
-			{
-				found = gedit_document_search_backward (doc,
-								        NULL, /* FIXME: set the start_inter */
-								        NULL, 
-								        &match_start,
-								        &match_end);
-			}
-		}
-	}
-	else
-	{
-		gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc),
-						      &start_iter, 
-						      NULL);	
-	}	
-	
-	if (found)
-	{
-		gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
-					&match_start);
-
-		gtk_text_buffer_move_mark_by_name (GTK_TEXT_BUFFER (doc),
-					"selection_bound", &match_end);
-	}
-	else if (typing)
-	{
-		gtk_text_buffer_place_cursor (GTK_TEXT_BUFFER (doc),
-					      &view->priv->start_search_iter);
-	}
-						      
-	if (found || (*entry_text == '\0'))
-	{				   
-		gedit_view_scroll_to_cursor (view);
-
-		set_entry_background (view->priv->search_entry,
-				      GEDIT_SEARCH_ENTRY_NORMAL);	
-	}
-	else
-	{
-		set_entry_background (view->priv->search_entry,
-				      GEDIT_SEARCH_ENTRY_NOT_FOUND);
-	}
-
-	return found;
-}
-
-/* Cut and paste from gtkwindow.c */
-static void
-send_focus_change (GtkWidget *widget,
-		   gboolean   in)
-{
-	GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
-
-	g_object_ref (widget);
-
-	fevent->focus_change.type = GDK_FOCUS_CHANGE;
-	fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget));
-	fevent->focus_change.in = in;
-
-	gtk_widget_send_focus_change (widget, fevent);
-
-	gdk_event_free (fevent);
-}
-
-static void
-hide_search_window (GeditView *view, gboolean cancel)
-{
-	if (view->priv->disable_popdown)
-		return;
-
-	if (view->priv->search_entry_changed_id != 0)
-	{
-		g_signal_handler_disconnect (view->priv->search_entry,
-					     view->priv->search_entry_changed_id);
-		view->priv->search_entry_changed_id = 0;
-    	}
-
-	if (view->priv->typeselect_flush_timeout != 0)
-	{
-		g_source_remove (view->priv->typeselect_flush_timeout);
-		view->priv->typeselect_flush_timeout = 0;
-	}
-
-	/* send focus-in event */
-	send_focus_change (GTK_WIDGET (view->priv->search_entry), FALSE);
-	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), TRUE);
-	gtk_widget_hide (view->priv->search_window);
-	
-	if (cancel)
-	{
-		GtkTextBuffer *buffer;
-		
-		buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-		gtk_text_buffer_place_cursor (buffer, &view->priv->start_search_iter);
-		
-		gedit_view_scroll_to_cursor (view);
-	}
-
-	/* make sure a focus event is sent for the edit area */
-	send_focus_change (GTK_WIDGET (view), TRUE);
-}
-
-static gboolean
-search_entry_flush_timeout (GeditView *view)
-{
-	GDK_THREADS_ENTER ();
-
-  	view->priv->typeselect_flush_timeout = 0;
-	hide_search_window (view, FALSE);
-
-	GDK_THREADS_LEAVE ();
-
-	return FALSE;
-}
-
-static void
-update_search_window_position (GeditView *view)
-{
-	gint x, y;
-	gint view_x, view_y;
-	GdkWindow *view_window = gtk_widget_get_window (GTK_WIDGET (view));
-
-	gtk_widget_realize (view->priv->search_window);
-
-	gdk_window_get_origin (view_window, &view_x, &view_y);
-  
-	x = MAX (12, view_x + 12);
-	y = MAX (12, view_y - 12);
-	
-	gtk_window_move (GTK_WINDOW (view->priv->search_window), x, y);
-}
-
-static gboolean
-search_window_delete_event (GtkWidget   *widget,
-			    GdkEventAny *event,
-			    GeditView   *view)
-{
-	hide_search_window (view, FALSE);
-
-	return TRUE;
-}
-
-static gboolean
-search_window_button_press_event (GtkWidget      *widget,
-				  GdkEventButton *event,
-				  GeditView      *view)
-{
-	hide_search_window (view, FALSE);
-	
-	gtk_propagate_event (GTK_WIDGET (view), (GdkEvent *)event);
-
-	return FALSE;
-}
-
-static void
-search_again (GeditView *view,
-	      gboolean   search_backward)
-{
-	const gchar *entry_text;
-
-	g_return_if_fail (view->priv->search_mode == SEARCH);
-		
-	/* SEARCH mode */	
-	/* renew the flush timeout */
-	if (view->priv->typeselect_flush_timeout != 0)
-	{
-		g_source_remove (view->priv->typeselect_flush_timeout);
-		view->priv->typeselect_flush_timeout =
-			g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
-		       		       (GSourceFunc)search_entry_flush_timeout,
-		       		       view);
-	}
-	
-	entry_text = gtk_entry_get_text (GTK_ENTRY (view->priv->search_entry));
-	
-	add_search_completion_entry (entry_text);
-		
-	run_search (view,
-		    entry_text,
-		    search_backward,
-		    view->priv->wrap_around,
-		    FALSE);
-}
-
-static gboolean
-search_window_scroll_event (GtkWidget      *widget,
-			    GdkEventScroll *event,
-			    GeditView      *view)
-{
-	gboolean retval = FALSE;
-
-	if (view->priv->search_mode == GOTO_LINE)
-		return retval;
-		
-	/* SEARCH mode */	
-	if (event->direction == GDK_SCROLL_UP)
-	{
-		search_again (view, TRUE);
-		retval = TRUE;
-	}
-	else if (event->direction == GDK_SCROLL_DOWN)
-	{
-      		search_again (view, FALSE);
-      		retval = TRUE;
-	}
-
-	return retval;
-}
-
-static gboolean
-search_window_key_press_event (GtkWidget   *widget,
-			       GdkEventKey *event,
-			       GeditView   *view)
-{
-	gboolean retval = FALSE;
-	guint modifiers;
-
-	modifiers = gtk_accelerator_get_default_mod_mask ();
-
-	/* Close window */
-	if (event->keyval == GDK_Tab)
-	{
-		hide_search_window (view, FALSE);
-		retval = TRUE;
-	}
-
-	/* Close window and cancel the search */
-	if (event->keyval == GDK_Escape)
-	{
-		if (view->priv->search_mode == SEARCH)
-		{
-			GeditDocument *doc;
-
-			/* restore document search so that Find Next does the right thing */
-			doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-			gedit_document_set_search_text (doc, 
-							view->priv->old_search_text,
-							view->priv->old_search_flags);
-						
-		}
-		
-		hide_search_window (view, TRUE);
-		retval = TRUE;
-	}
-	
-	if (view->priv->search_mode == GOTO_LINE)
-		return retval;
-		
-	/* SEARCH mode */
-
-	/* select previous matching iter */
-	if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
-	{
-		search_again (view, TRUE);
-		retval = TRUE;
-	}
-
-	if (((event->state & modifiers) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) && 
-	    (event->keyval == GDK_g || event->keyval == GDK_G))
-	{
-		search_again (view, TRUE);
-		retval = TRUE;
-	}
-
-	/* select next matching iter */
-	if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
-	{
-		search_again (view, FALSE);
-		retval = TRUE;
-	}
-
-	if (((event->state & modifiers) == GDK_CONTROL_MASK) && 
-	    (event->keyval == GDK_g || event->keyval == GDK_G))
-	{
-		search_again (view, FALSE);
-		retval = TRUE;
-	}
-
-	return retval;
-}
-
-static void
-search_entry_activate (GtkEntry  *entry,
-		       GeditView *view)
-{
-	hide_search_window (view, FALSE);
-}
-
-static void
-wrap_around_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
-			       GeditView        *view)
-{	
-	view->priv->wrap_around = gtk_check_menu_item_get_active (checkmenuitem);
-}
-
-static void
-match_entire_word_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
-				     GeditView        *view)
-{
-	GEDIT_SEARCH_SET_ENTIRE_WORD (view->priv->search_flags,
-				      gtk_check_menu_item_get_active (checkmenuitem));
-}
-
-static void
-match_case_menu_item_toggled (GtkCheckMenuItem *checkmenuitem,
-			      GeditView        *view)
-{
-	GEDIT_SEARCH_SET_CASE_SENSITIVE (view->priv->search_flags,
-					 gtk_check_menu_item_get_active (checkmenuitem));
-}
-
-static gboolean
-real_search_enable_popdown (gpointer data)
-{
-	GeditView *view = (GeditView *)data;
-
-	GDK_THREADS_ENTER ();
-
-	view->priv->disable_popdown = FALSE;
-
-	GDK_THREADS_LEAVE ();
-
-	return FALSE;
-}
-
-static void
-search_enable_popdown (GtkWidget *widget,
-		       GeditView *view)
-{
-	g_timeout_add (200, real_search_enable_popdown, view);
-	
-	/* renew the flush timeout */
-	if (view->priv->typeselect_flush_timeout != 0)
-		g_source_remove (view->priv->typeselect_flush_timeout);
-
-	view->priv->typeselect_flush_timeout =
-		g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
-	       		       (GSourceFunc)search_entry_flush_timeout,
-	       		       view);
-}
-
-static void
-add_popup_menu_items (GtkWidget *menu,
-		      GeditView *view)
-{
-	GtkWidget *menu_item;
-
-	/* create "Wrap Around" menu item. */
-	menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Wrap Around"));
-	g_signal_connect (G_OBJECT (menu_item), "toggled",
-			  G_CALLBACK (wrap_around_menu_item_toggled), 
-			  view);
-	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
-	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
-					view->priv->wrap_around);
-	gtk_widget_show (menu_item);
-
-	/* create "Match Entire Word Only" menu item. */
-	menu_item = gtk_check_menu_item_new_with_mnemonic (_("Match _Entire Word Only"));
-	g_signal_connect (G_OBJECT (menu_item), "toggled",
-			  G_CALLBACK (match_entire_word_menu_item_toggled), 
-			  view);
-	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
-	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
-					GEDIT_SEARCH_IS_ENTIRE_WORD (view->priv->search_flags));
-	gtk_widget_show (menu_item);
-
-	/* create "Match Case" menu item. */
-	menu_item = gtk_check_menu_item_new_with_mnemonic (_("_Match Case"));
-	g_signal_connect (G_OBJECT (menu_item), "toggled",
-			  G_CALLBACK (match_case_menu_item_toggled), 
-			  view);
-	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
-	gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item),
-					GEDIT_SEARCH_IS_CASE_SENSITIVE (view->priv->search_flags));
-	gtk_widget_show (menu_item);
-}
-
-static void
-search_entry_populate_popup (GtkEntry  *entry,
-			     GtkMenu   *menu,
-			     GeditView *view)
-{
-	GtkWidget *menu_item;
-
-	view->priv->disable_popdown = TRUE;
-	g_signal_connect (menu, "hide",
-			  G_CALLBACK (search_enable_popdown), view);
-
-	if (view->priv->search_mode == GOTO_LINE)
-		return;
-
-	/* separator */
-	menu_item = gtk_menu_item_new ();
-	gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
-	gtk_widget_show (menu_item);
-
-	add_popup_menu_items (GTK_WIDGET (menu), view);
-}
-
-static void
-search_entry_icon_release (GtkEntry            *entry,
-			   GtkEntryIconPosition icon_pos,
-			   GdkEventButton      *event,
-			   GeditView           *view)
-{
-	GtkWidget *menu;
-
-	if (view->priv->search_mode == GOTO_LINE ||
-	    icon_pos != GTK_ENTRY_ICON_PRIMARY)
-		return;
-
-	menu = gtk_menu_new ();
-	gtk_widget_show (menu);
-
-	view->priv->disable_popdown = TRUE;
-	g_signal_connect (menu, "hide",
-			  G_CALLBACK (search_enable_popdown), view);
-
-	add_popup_menu_items (menu, view);
-
-	gtk_menu_popup (GTK_MENU (menu),
-			NULL, NULL,
-			NULL, NULL,
-			event->button, event->time);
-}
-
-static void
-search_entry_insert_text (GtkEditable *editable, 
-			  const gchar *text, 
-			  gint         length, 
-			  gint        *position,
-			  GeditView   *view)
-{
-	if (view->priv->search_mode == GOTO_LINE)
-	{
-		gunichar c;
-		const gchar *p;
-	 	const gchar *end;
-	 	const gchar *next;
-
-		p = text;
-		end = text + length;
-
-		if (p == end)
-			return;
-
-		c = g_utf8_get_char (p);
-		
-		if (((c == '-' || c == '+') && *position == 0) ||
-		    (c == ':' && *position != 0))
-		{
-			gchar *s = NULL;
-		
-			if (c == ':')
-			{
-				s = gtk_editable_get_chars (editable, 0, -1);
-				s = g_utf8_strchr (s, -1, ':');
-			}
-			
-			if (s == NULL || s == p)
-			{
-				next = g_utf8_next_char (p);
-				p = next;
-			}
-			
-			g_free (s);
-		}
-
-		while (p != end)
-		{
-			next = g_utf8_next_char (p);
-
-			c = g_utf8_get_char (p);
-
-			if (!g_unichar_isdigit (c))
-			{
-				g_signal_stop_emission_by_name (editable, "insert_text");
-				gtk_widget_error_bell (view->priv->search_entry);
-				break;
-			}
-
-			p = next;
-		}
-	}
-	else
-	{
-		/* SEARCH mode */
-		static gboolean  insert_text = FALSE;
-		gchar           *escaped_text;
-		gint             new_len;
-
-		gedit_debug_message (DEBUG_SEARCH, "Text: %s", text);
-
-		/* To avoid recursive behavior */
-		if (insert_text)
-			return;
-
-		escaped_text = gedit_utils_escape_search_text (text);
-
-		gedit_debug_message (DEBUG_SEARCH, "Escaped Text: %s", escaped_text);
-
-		new_len = strlen (escaped_text);
-
-		if (new_len == length)
-		{
-			g_free (escaped_text);
-			return;
-		}
-
-		insert_text = TRUE;
-
-		g_signal_stop_emission_by_name (editable, "insert_text");
-		
-		gtk_editable_insert_text (editable, escaped_text, new_len, position);
-
-		insert_text = FALSE;
-
-		g_free (escaped_text);
-	}
-}
-
-static void
-customize_for_search_mode (GeditView *view)
-{
-	if (view->priv->search_mode == SEARCH)
-	{
-		gtk_entry_set_icon_from_stock (GTK_ENTRY (view->priv->search_entry),
-					       GTK_ENTRY_ICON_PRIMARY,
-					       GTK_STOCK_FIND);
-		
-		gtk_widget_set_tooltip_text (view->priv->search_entry,
-					     _("String you want to search for"));
-	}
-	else
-	{
-		gtk_entry_set_icon_from_stock (GTK_ENTRY (view->priv->search_entry),
-					       GTK_ENTRY_ICON_PRIMARY,
-					       GTK_STOCK_JUMP_TO);
-		
-		gtk_widget_set_tooltip_text (view->priv->search_entry,
-					     _("Line you want to move the cursor to"));
-	}
-}
-
-static gboolean
-completion_func (GtkEntryCompletion *completion,
-                 const char         *key,
-		 GtkTreeIter        *iter,
-		 gpointer            data)
-{
-	gchar *item = NULL;
-	gboolean ret = FALSE;
-	GtkTreeModel *model;
-	GeditViewPrivate *priv = (GeditViewPrivate *)data;
-	const gchar *real_key;
-		
-	if (priv->search_mode == GOTO_LINE)
-		return FALSE;
-		
-	real_key = gtk_entry_get_text (GTK_ENTRY (gtk_entry_completion_get_entry (completion)));
-	
-	if (g_utf8_strlen (real_key, -1) <= MIN_SEARCH_COMPLETION_KEY_LEN)
-		return FALSE;
-		
-	model = gtk_entry_completion_get_model (completion);
-	g_return_val_if_fail (gtk_tree_model_get_column_type (model, 0) == G_TYPE_STRING, 
-			      FALSE);
-			      
-	gtk_tree_model_get (model, 
-			    iter,
-			    0, 
-			    &item,
-			    -1);
-	
-	if (item == NULL)
-		return FALSE;
-		
-	if (GEDIT_SEARCH_IS_CASE_SENSITIVE (priv->search_flags))
-	{		
-		if (!strncmp (real_key, item, strlen (real_key)))
-			ret = TRUE;
-	}
-	else
-	{
-		gchar *normalized_string;
-		gchar *case_normalized_string;
-		
-		normalized_string = g_utf8_normalize (item, -1, G_NORMALIZE_ALL);
-		case_normalized_string = g_utf8_casefold (normalized_string, -1);
-      
-      		if (!strncmp (key, case_normalized_string, strlen (key)))
-			ret = TRUE;
- 		
-		g_free (normalized_string);
-		g_free (case_normalized_string);
-		
-	}
-	
-	g_free (item);
-	
-	return ret;	
-}
-
-static void
-ensure_search_window (GeditView *view)
-{  
-	GtkWidget          *frame;
-	GtkWidget          *vbox;
-	GtkWidget          *toplevel;
-	GtkEntryCompletion *completion;
-	
-	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (view));
-
-	if (view->priv->search_window != NULL)
-	{
-		if (gtk_window_has_group (GTK_WINDOW (toplevel)))
-		{
-			gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-						     GTK_WINDOW (view->priv->search_window));
-		}
-		else if (gtk_window_has_group (GTK_WINDOW (view->priv->search_window)))
-		{
-			gtk_window_group_remove_window (gtk_window_get_group (GTK_WINDOW (view->priv->search_window)),
-							GTK_WINDOW (view->priv->search_window));
-		}
-
-		customize_for_search_mode (view);
-		
-		return;
-	}
-   
-	view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
-
-	if (gtk_window_has_group (GTK_WINDOW (toplevel)))
-	{
-		gtk_window_group_add_window (gtk_window_get_group (GTK_WINDOW (toplevel)),
-					     GTK_WINDOW (view->priv->search_window));
-	}
-					     
-	gtk_window_set_modal (GTK_WINDOW (view->priv->search_window), TRUE);
-	
-	g_signal_connect (view->priv->search_window, "delete_event",
-			  G_CALLBACK (search_window_delete_event),
-			  view);
-	g_signal_connect (view->priv->search_window, "key_press_event",
-			  G_CALLBACK (search_window_key_press_event),
-			  view);
-	g_signal_connect (view->priv->search_window, "button_press_event",
-			  G_CALLBACK (search_window_button_press_event),
-			  view);
-	g_signal_connect (view->priv->search_window, "scroll_event",
-			  G_CALLBACK (search_window_scroll_event),
-			  view);
-
-	frame = gtk_frame_new (NULL);
-	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-	gtk_widget_show (frame);
-	gtk_container_add (GTK_CONTAINER (view->priv->search_window), frame);
-
-	vbox = gtk_vbox_new (FALSE, 0);
-	gtk_widget_show (vbox);
-	gtk_container_add (GTK_CONTAINER (frame), vbox);
-	gtk_container_set_border_width (GTK_CONTAINER (vbox), 3);
-
-	/* add entry */
-	view->priv->search_entry = gtk_entry_new ();
-	gtk_widget_show (view->priv->search_entry);
-
-	g_signal_connect (view->priv->search_entry, "populate-popup",
-			  G_CALLBACK (search_entry_populate_popup),
-			  view);
-	g_signal_connect (view->priv->search_entry, "icon-release",
-			  G_CALLBACK (search_entry_icon_release),
-			  view);
-	g_signal_connect (view->priv->search_entry, "activate", 
-			  G_CALLBACK (search_entry_activate),
-			  view);
-	/* CHECK: do we really need to connect to preedit too? -- Paolo
-	g_signal_connect (GTK_ENTRY (view->priv->search_entry)->im_context, "preedit-changed",
-			  G_CALLBACK (gtk_view_search_preedit_changed),
-			  view);
-	*/		
-	g_signal_connect (view->priv->search_entry, 
-			  "insert_text",
-			  G_CALLBACK (search_entry_insert_text), 
-			  view);	  
-			  
-	gtk_container_add (GTK_CONTAINER (vbox),
-			   view->priv->search_entry);
-
-	if (search_completion_model == NULL)
-	{
-		/* Create a tree model and use it as the completion model */
-		search_completion_model = gtk_list_store_new (1, G_TYPE_STRING);
-	}
-	
-	/* Create the completion object for the search entry */
-	completion = gtk_entry_completion_new ();
-	gtk_entry_completion_set_model (completion, 
-					GTK_TREE_MODEL (search_completion_model));
-		
-	/* Use model column 0 as the text column */
-	gtk_entry_completion_set_text_column (completion, 0);
-
-	gtk_entry_completion_set_minimum_key_length (completion,
-						     MIN_SEARCH_COMPLETION_KEY_LEN);
-
-	gtk_entry_completion_set_popup_completion (completion, FALSE);
-	gtk_entry_completion_set_inline_completion (completion, TRUE);
-	
-	gtk_entry_completion_set_match_func (completion, 
-					     completion_func,
-					     view->priv,
-					     NULL);
-
-	/* Assign the completion to the entry */
-	gtk_entry_set_completion (GTK_ENTRY (view->priv->search_entry), 
-				  completion);
-	g_object_unref (completion);
-
-	gtk_widget_realize (view->priv->search_entry);
-
-	customize_for_search_mode (view);	
-}
-
-static gboolean
-get_selected_text (GtkTextBuffer *doc, gchar **selected_text, gint *len)
-{
-	GtkTextIter start, end;
-
-	g_return_val_if_fail (selected_text != NULL, FALSE);
-	g_return_val_if_fail (*selected_text == NULL, FALSE);
-
-	if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end))
-	{
-		if (len != NULL)
-			len = 0;
-
-		return FALSE;
-	}
-
-	*selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE);
-
-	if (len != NULL)
-		*len = g_utf8_strlen (*selected_text, -1);
-
-	return TRUE;
-}
-
-static void
-init_search_entry (GeditView *view)
-{
-	GtkTextBuffer *buffer;
-				
-	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-	
-	if (view->priv->search_mode == GOTO_LINE)
-	{	
-		gint   line;
-		gchar *line_str;
-		
-		line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-		
-		line_str = g_strdup_printf ("%d", line + 1);
-		
-		gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry), 
-				    line_str);
-				    
-		g_free (line_str);
-		
-		return;
-	}
-	else
-	{
-		/* SEARCH mode */
-		gboolean  selection_exists;
-		gchar    *find_text = NULL;
-		gchar    *old_find_text;
-		guint     old_find_flags = 0;
-		gint      sel_len = 0;
-
-		g_free (view->priv->old_search_text);
-		
-		old_find_text = gedit_document_get_search_text (GEDIT_DOCUMENT (buffer), 
-								&old_find_flags);
-		if (old_find_text != NULL)
-		{
-			view->priv->old_search_text = old_find_text;
-			add_search_completion_entry (old_find_text);
-		}
-
-		if (old_find_flags != 0)
-		{
-			view->priv->old_search_flags = old_find_flags;
-		}
-
-		selection_exists = get_selected_text (buffer, 
-						      &find_text, 
-						      &sel_len);
-							      				
-		if (selection_exists  && (find_text != NULL) && (sel_len <= 160))
-		{
-			gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry), 
-					    find_text);	
-		}
-		else
-		{
-			gtk_entry_set_text (GTK_ENTRY (view->priv->search_entry), 
-					    "");
-		}
-		
-		g_free (find_text);
-	}
-}
-
-static void
-search_init (GtkWidget *entry,
-	     GeditView *view)
-{
-	GeditDocument *doc;
-	const gchar *entry_text;
-
-	/* renew the flush timeout */
-	if (view->priv->typeselect_flush_timeout != 0)
-	{
-		g_source_remove (view->priv->typeselect_flush_timeout);
-		view->priv->typeselect_flush_timeout =
-			g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
-		       		       (GSourceFunc)search_entry_flush_timeout,
-		       		       view);
-	}
-	
-	doc = GEDIT_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)));
-			
-	entry_text = gtk_entry_get_text (GTK_ENTRY (entry));
-	
-	if (view->priv->search_mode == SEARCH)
-	{
-		gchar *search_text;
-		guint  search_flags;
-
-		search_text = gedit_document_get_search_text (doc, &search_flags);
-
-		if ((search_text == NULL) ||
-		    (strcmp (search_text, entry_text) != 0) ||
-		     search_flags != view->priv->search_flags)
-		{
-			gedit_document_set_search_text (doc, 
-							entry_text,
-							view->priv->search_flags);
-		}
-
-		g_free (search_text);
-
-		run_search (view,
-			    entry_text,
-			    FALSE,
-			    view->priv->wrap_around,
-			    TRUE);
-	}
-	else
-	{
-		if (*entry_text != '\0')
-		{
-			gboolean moved, moved_offset;
-			gint line;
-			gint offset_line = 0;
-			gint line_offset = 0;
-			gchar **split_text = NULL;
-			const gchar *text;
-			
-			split_text = g_strsplit (entry_text, ":", -1);
-			
-			if (g_strv_length (split_text) > 1)
-			{
-				text = split_text[0];
-			}
-			else
-			{
-				text = entry_text;
-			}
-			
-			if (*text == '-')
-			{
-				gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-			
-				if (*(text + 1) != '\0')
-					offset_line = MAX (atoi (text + 1), 0);
-				
-				line = MAX (cur_line - offset_line, 0);
-			}
-			else if (*entry_text == '+')
-			{
-				gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter);
-			
-				if (*(text + 1) != '\0')
-					offset_line = MAX (atoi (text + 1), 0);
-				
-				line = cur_line + offset_line;
-			}
-			else
-			{
-				line = MAX (atoi (text) - 1, 0);
-			}
-			
-			if (split_text[1] != NULL)
-			{
-				line_offset = atoi (split_text[1]);
-			}
-			
-			g_strfreev (split_text);
-			
-			moved = gedit_document_goto_line (doc, line);
-			moved_offset = gedit_document_goto_line_offset (doc, line,
-									line_offset);
-			
-			gedit_view_scroll_to_cursor (view);
-
-			if (!moved || !moved_offset)
-			{
-				set_entry_background (view->priv->search_entry,
-						      GEDIT_SEARCH_ENTRY_NOT_FOUND);
-			}
-			else
-			{
-				set_entry_background (view->priv->search_entry,
-						      GEDIT_SEARCH_ENTRY_NORMAL);
-			}
-		}
-	}
-}
-
-static gboolean
-start_interactive_search_real (GeditView *view)
-{	
-	GtkTextBuffer *buffer;
-	
-	if ((view->priv->search_window != NULL) &&
-	    gtk_widget_get_visible (view->priv->search_window))
-	{
-		return TRUE;
-	}
-
-	if (!gtk_widget_has_focus (GTK_WIDGET (view)))
-		return FALSE;
-
-	buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
-
-	if (view->priv->search_mode == SEARCH)
-	{
-		gtk_text_buffer_get_selection_bounds (buffer, &view->priv->start_search_iter, NULL);
-	}
-	else
-	{
-		gtk_text_buffer_get_iter_at_mark (buffer,
-						  &view->priv->start_search_iter,
-						  gtk_text_buffer_get_insert (buffer));
-	}
-
-	ensure_search_window (view);
-
-	/* done, show it */
-	update_search_window_position (view);
-	gtk_widget_show (view->priv->search_window);
-
-	if (view->priv->search_entry_changed_id == 0)
-	{
-      		view->priv->search_entry_changed_id =
-			g_signal_connect (view->priv->search_entry,
-					  "changed",
-					  G_CALLBACK (search_init),
-					  view);
-	}
-
-	init_search_entry (view);
-
-	view->priv->typeselect_flush_timeout =  
-		g_timeout_add (GEDIT_VIEW_SEARCH_DIALOG_TIMEOUT,
-		   	       (GSourceFunc) search_entry_flush_timeout,
-		   	       view);
-
-	gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE);
-	gtk_widget_grab_focus (view->priv->search_entry);
-	
-	send_focus_change (view->priv->search_entry, TRUE);
-	
-	return TRUE;
-}
-
 static gboolean
 reset_searched_text (GeditView *view)
 {		
@@ -1945,22 +720,6 @@ reset_searched_text (GeditView *view)
 	return TRUE;
 }
 
-static gboolean
-start_interactive_search (GeditView *view)
-{		
-	view->priv->search_mode = SEARCH;
-	
-	return start_interactive_search_real (view);
-}
-
-static gboolean 
-start_interactive_goto_line (GeditView *view)
-{
-	view->priv->search_mode = GOTO_LINE;
-	
-	return start_interactive_search_real (view);
-}
-
 static gint
 gedit_view_expose (GtkWidget      *widget,
                    GdkEventExpose *event)
diff --git a/gedit/theatrics/Makefile.am b/gedit/theatrics/Makefile.am
new file mode 100644
index 0000000..d79fe42
--- /dev/null
+++ b/gedit/theatrics/Makefile.am
@@ -0,0 +1,52 @@
+INCLUDES = 							\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-I$(top_srcdir)/gedit					\
+	-I$(top_builddir)/gedit					\
+	$(GEDIT_CFLAGS)						\
+	$(WARN_CFLAGS)						\
+	$(DISABLE_DEPRECATED_CFLAGS)
+
+noinst_LTLIBRARIES = libtheatrics.la
+
+BUILT_SOURCES =					\
+	gedit-theatrics-enum-types.h		\
+	gedit-theatrics-enum-types.c		\
+	gedit-theatrics-marshal.h		\
+	gedit-theatrics-marshal.c
+
+libtheatrics_la_SOURCES =				\
+	gedit-theatrics-actor.h				\
+	gedit-theatrics-actor.c				\
+	gedit-theatrics-animated-widget.h		\
+	gedit-theatrics-animated-widget.c		\
+	gedit-theatrics-choreographer.h			\
+	gedit-theatrics-choreographer.c			\
+	gedit-theatrics-stage.h				\
+	gedit-theatrics-stage.c				\
+	gedit-theatrics-utils.h				\
+	gedit-theatrics-utils.c				\
+	$(BUILT_SOURCES)
+
+ENUM_TYPES =					\
+	gedit-theatrics-choreographer.h
+
+gedit-theatrics-enum-types.h: gedit-theatrics-enum-types.h.template $(ENUM_TYPES) $(GLIB_MKENUMS)
+	$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-theatrics-enum-types.h.template $(ENUM_TYPES)) > $@
+
+gedit-theatrics-enum-types.c: gedit-theatrics-enum-types.c.template $(ENUM_TYPES) $(GLIB_MKENUMS)
+	$(AM_V_GEN) (cd $(srcdir) && $(GLIB_MKENUMS) --template gedit-theatrics-enum-types.c.template $(ENUM_TYPES)) > $@
+
+gedit-theatrics-marshal.h: gedit-theatrics-marshal.list $(GLIB_GENMARSHAL)
+	$(AM_V_GEN) $(GLIB_GENMARSHAL) $< --header --prefix=gedit_theatrics_marshal > $@
+
+gedit-theatrics-marshal.c: gedit-theatrics-marshal.list $(GLIB_GENMARSHAL)
+	$(AM_V_GEN) echo "#include \"gedit-theatrics-marshal.h\"" > $@ && \
+	$(GLIB_GENMARSHAL) $< --body --prefix=gedit_theatrics_marshal >> $@
+
+EXTRA_DIST =				\
+	gedit-theatrics-marshal.list
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/gedit/theatrics/gedit-theatrics-actor.c b/gedit/theatrics/gedit-theatrics-actor.c
new file mode 100644
index 0000000..772acaa
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-actor.c
@@ -0,0 +1,279 @@
+/*
+ * gedit-theatrics-actor.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * 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-theatrics-actor.h"
+
+
+#define GEDIT_THEATRICS_ACTOR_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorPrivate))
+
+struct _GeditTheatricsActorPrivate
+{
+	GObject *target;
+
+	guint duration;
+	gdouble frames;
+	gdouble percent;
+
+	GTimeVal start_time;
+
+	guint can_expire : 1;
+};
+
+enum
+{
+	PROP_0,
+	PROP_TARGET,
+	PROP_DURATION
+};
+
+G_DEFINE_TYPE (GeditTheatricsActor, gedit_theatrics_actor, G_TYPE_OBJECT)
+
+static void
+gedit_theatrics_actor_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gedit_theatrics_actor_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_actor_get_property (GObject    *object,
+				    guint       prop_id,
+				    GValue     *value,
+				    GParamSpec *pspec)
+{
+	GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (object);
+
+	switch (prop_id)
+	{
+		case PROP_TARGET:
+			g_value_set_object (value, actor->priv->target);
+			break;
+		case PROP_DURATION:
+			g_value_set_uint (value, actor->priv->duration);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_actor_set_property (GObject      *object,
+				    guint         prop_id,
+				    const GValue *value,
+				    GParamSpec   *pspec)
+{
+	GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (object);
+
+	switch (prop_id)
+	{
+		case PROP_TARGET:
+		{
+			GObject *target;
+
+			target = g_value_get_object (value);
+
+			if (target != NULL)
+			{
+				actor->priv->target = target;
+			}
+
+			break;
+		}
+		case PROP_DURATION:
+			actor->priv->duration = g_value_get_uint (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_actor_class_init (GeditTheatricsActorClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	
+	object_class->finalize = gedit_theatrics_actor_finalize;
+	object_class->get_property = gedit_theatrics_actor_get_property;
+	object_class->set_property = gedit_theatrics_actor_set_property;
+
+	g_object_class_install_property (object_class, PROP_TARGET,
+	                                 g_param_spec_object ("target",
+	                                                      "Target",
+	                                                      "The Target",
+	                                                      G_TYPE_OBJECT,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_DURATION,
+	                                 g_param_spec_uint ("duration",
+	                                                    "Duration",
+	                                                    "The duration",
+	                                                    0,
+	                                                    G_MAXUINT,
+	                                                    0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_type_class_add_private (object_class, sizeof (GeditTheatricsActorPrivate));
+}
+
+static void
+gedit_theatrics_actor_init (GeditTheatricsActor *actor)
+{
+	actor->priv = GEDIT_THEATRICS_ACTOR_GET_PRIVATE (actor);
+
+	actor->priv->can_expire = TRUE;
+
+	gedit_theatrics_actor_reset (actor, actor->priv->duration);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_actor_new (GObject *target,
+			   guint    duration)
+{
+	return g_object_new (GEDIT_TYPE_THEATRICS_ACTOR,
+			     "target", target,
+			     "duration", duration,
+			     NULL);
+}
+
+/* Use duration = -1 to not set a new duration */
+void
+gedit_theatrics_actor_reset (GeditTheatricsActor *actor,
+			     guint                duration)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+	g_get_current_time (&actor->priv->start_time);
+	actor->priv->frames = 0.0;
+	actor->priv->percent = 0.0;
+
+	if (duration > -1)
+	{
+		actor->priv->duration = duration;
+	}
+}
+
+void
+gedit_theatrics_actor_step (GeditTheatricsActor *actor)
+{
+	GTimeVal now;
+	gdouble now_num, start_time;
+
+	g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+	if (!actor->priv->can_expire && actor->priv->percent >= 1.0)
+	{
+		gedit_theatrics_actor_reset (actor, actor->priv->duration);
+	}
+
+	g_get_current_time (&now);
+
+	now_num = now.tv_sec * 1000 + now.tv_usec / 1000;
+	start_time = actor->priv->start_time.tv_sec * 1000 + actor->priv->start_time.tv_usec / 1000;
+
+	actor->priv->percent = ((now_num - start_time) / actor->priv->duration);
+
+	actor->priv->frames++;
+}
+
+GObject *
+gedit_theatrics_actor_get_target (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), NULL);
+
+	return actor->priv->target;
+}
+
+gboolean
+gedit_theatrics_actor_get_expired (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), FALSE);
+
+	return (actor->priv->can_expire && actor->priv->percent >= 1.0);
+}
+
+gboolean
+gedit_theatrics_actor_get_can_expire (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), FALSE);
+
+	return actor->priv->can_expire;
+}
+
+void
+gedit_theatrics_actor_set_can_expire (GeditTheatricsActor *actor,
+				      gboolean             can_expire)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor));
+
+	actor->priv->can_expire = can_expire;
+}
+
+guint
+gedit_theatrics_actor_get_duration (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+	return actor->priv->duration;
+}
+
+GTimeVal
+gedit_theatrics_actor_get_start_time (GeditTheatricsActor *actor)
+{
+	GTimeVal r = {0, };
+
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), r);
+
+	return actor->priv->start_time;
+}
+
+gdouble
+gedit_theatrics_actor_get_frames (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+	return actor->priv->frames;
+}
+
+gdouble
+gedit_theatrics_actor_get_frames_per_second (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+	return (actor->priv->frames / (actor->priv->duration / 1000.0));
+}
+
+gdouble
+gedit_theatrics_actor_get_percent (GeditTheatricsActor *actor)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ACTOR (actor), 0.0);
+
+	return MAX (0.0, MIN (1.0, actor->priv->percent));
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-actor.h b/gedit/theatrics/gedit-theatrics-actor.h
new file mode 100644
index 0000000..8f81fcb
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-actor.h
@@ -0,0 +1,90 @@
+/*
+ * gedit-theatrics-actor.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * 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_THEATRICS_ACTOR_H__
+#define __GEDIT_THEATRICS_ACTOR_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_ACTOR		(gedit_theatrics_actor_get_type ())
+#define GEDIT_THEATRICS_ACTOR(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActor))
+#define GEDIT_THEATRICS_ACTOR_CONST(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActor const))
+#define GEDIT_THEATRICS_ACTOR_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorClass))
+#define GEDIT_IS_THEATRICS_ACTOR(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_ACTOR))
+#define GEDIT_IS_THEATRICS_ACTOR_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_ACTOR))
+#define GEDIT_THEATRICS_ACTOR_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_ACTOR, GeditTheatricsActorClass))
+
+typedef struct _GeditTheatricsActor		GeditTheatricsActor;
+typedef struct _GeditTheatricsActorClass	GeditTheatricsActorClass;
+typedef struct _GeditTheatricsActorPrivate	GeditTheatricsActorPrivate;
+
+struct _GeditTheatricsActor
+{
+	GObject parent;
+	
+	GeditTheatricsActorPrivate *priv;
+};
+
+struct _GeditTheatricsActorClass
+{
+	GObjectClass parent_class;
+};
+
+GType			 gedit_theatrics_actor_get_type		(void) G_GNUC_CONST;
+
+GeditTheatricsActor	*gedit_theatrics_actor_new		(GObject *target,
+								 guint    duration);
+
+void			 gedit_theatrics_actor_reset		(GeditTheatricsActor *actor,
+								 guint                duration);
+
+void			 gedit_theatrics_actor_step		(GeditTheatricsActor *actor);
+
+GObject			*gedit_theatrics_actor_get_target	(GeditTheatricsActor *actor);
+
+gboolean		 gedit_theatrics_actor_get_expired	(GeditTheatricsActor *actor);
+
+gboolean		 gedit_theatrics_actor_get_can_expire	(GeditTheatricsActor *actor);
+
+void			 gedit_theatrics_actor_set_can_expire	(GeditTheatricsActor *actor,
+								 gboolean             can_expire);
+
+guint			 gedit_theatrics_actor_get_duration	(GeditTheatricsActor *actor);
+
+GTimeVal		 gedit_theatrics_actor_get_start_time	(GeditTheatricsActor *actor);
+
+gdouble			 gedit_theatrics_actor_get_frames	(GeditTheatricsActor *actor);
+
+gdouble			 gedit_theatrics_actor_get_frames_per_second
+								(GeditTheatricsActor *actor);
+
+gdouble			 gedit_theatrics_actor_get_percent	(GeditTheatricsActor *actor);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_ACTOR_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-animated-widget.c b/gedit/theatrics/gedit-theatrics-animated-widget.c
new file mode 100644
index 0000000..826aec1
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-animated-widget.c
@@ -0,0 +1,643 @@
+/*
+ * gedit-theatrics-animated-widget.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * 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-theatrics-animated-widget.h"
+#include "gedit-theatrics-enum-types.h"
+
+
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetPrivate))
+
+struct _GeditTheatricsAnimatedWidgetPrivate
+{
+	GtkWidget *widget;
+	GeditTheatricsChoreographerEasing easing;
+	GeditTheatricsChoreographerBlocking blocking;
+	GeditTheatricsAnimationState animation_state;
+	GtkOrientation orientation;
+	guint duration;
+	gdouble bias;
+	gdouble percent;
+	GtkAllocation widget_alloc;
+
+	cairo_surface_t *surface;
+
+	gint width;
+	gint height;
+	gint start_padding;
+	gint end_padding;
+};
+
+enum
+{
+	PROP_0,
+	PROP_WIDGET,
+	PROP_EASING,
+	PROP_BLOCKING,
+	PROP_ANIMATION_STATE,
+	PROP_DURATION,
+	PROP_PERCENT,
+	PROP_ORIENTATION
+};
+
+enum
+{
+	REMOVE_CORE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE_EXTENDED (GeditTheatricsAnimatedWidget,
+			gedit_theatrics_animated_widget,
+			GTK_TYPE_BIN,
+			0,
+			G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
+					       NULL))
+
+static void
+on_widget_destroyed (GtkWidget                    *widget,
+		     GeditTheatricsAnimatedWidget *aw)
+{
+	GdkWindow *window;
+	cairo_t *img_cr;
+	cairo_t *cr;
+	cairo_surface_t *surface;
+
+	if (!gtk_widget_get_realized (GTK_WIDGET (aw)))
+		return;
+
+	aw->priv->width = aw->priv->widget_alloc.width;
+	aw->priv->height = aw->priv->widget_alloc.height;
+
+	aw->priv->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+							aw->priv->width,
+							aw->priv->height);
+
+	img_cr = cairo_create (aw->priv->surface);
+
+	window = gtk_widget_get_window (GTK_WIDGET (aw));
+
+	cr = gdk_cairo_create (GDK_DRAWABLE (window));
+	surface = cairo_get_target (cr);
+
+	cairo_set_source_surface (img_cr, surface,
+	                          aw->priv->widget_alloc.x,
+	                          aw->priv->widget_alloc.y);
+
+	cairo_paint (img_cr);
+
+	cairo_destroy (img_cr);
+	cairo_destroy (cr);
+
+	if (aw->priv->animation_state != GEDIT_THEATRICS_ANIMATION_STATE_GOING)
+	{
+		g_signal_emit (G_OBJECT (aw), signals[REMOVE_CORE], 0);
+	}
+}
+
+static void
+set_widget (GeditTheatricsAnimatedWidget *aw,
+	    GtkWidget                    *widget)
+{
+	if (widget == NULL)
+		return;
+
+	aw->priv->widget = widget;
+	gtk_widget_set_parent (widget, GTK_WIDGET (aw));
+
+	g_signal_connect (widget, "destroy",
+			  G_CALLBACK (on_widget_destroyed),
+			  aw);
+}
+
+static void
+gedit_theatrics_animated_widget_finalize (GObject *object)
+{
+	G_OBJECT_CLASS (gedit_theatrics_animated_widget_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_animated_widget_get_property (GObject    *object,
+					      guint       prop_id,
+					      GValue     *value,
+					      GParamSpec *pspec)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object);
+
+	switch (prop_id)
+	{
+		case PROP_WIDGET:
+			g_value_set_object (value, aw->priv->widget);
+			break;
+		case PROP_EASING:
+			g_value_set_enum (value, aw->priv->easing);
+			break;
+		case PROP_BLOCKING:
+			g_value_set_enum (value, aw->priv->blocking);
+			break;
+		case PROP_ANIMATION_STATE:
+			g_value_set_enum (value, aw->priv->animation_state);
+			break;
+		case PROP_DURATION:
+			g_value_set_uint (value, aw->priv->duration);
+			break;
+		case PROP_PERCENT:
+			g_value_set_double (value, aw->priv->percent);
+			break;
+		case PROP_ORIENTATION:
+			g_value_set_enum (value, aw->priv->orientation);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_animated_widget_set_property (GObject      *object,
+					      guint         prop_id,
+					      const GValue *value,
+					      GParamSpec   *pspec)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (object);
+
+	switch (prop_id)
+	{
+		case PROP_WIDGET:
+		{
+			set_widget (aw, g_value_get_object (value));
+			break;
+		}
+		case PROP_EASING:
+			gedit_theatrics_animated_widget_set_easing (aw,
+			                                            g_value_get_enum (value));
+			break;
+		case PROP_BLOCKING:
+			gedit_theatrics_animated_widget_set_blocking (aw,
+			                                              g_value_get_enum (value));
+			break;
+		case PROP_ANIMATION_STATE:
+			gedit_theatrics_animated_widget_set_animation_state (aw,
+			                                                     g_value_get_enum (value));
+			break;
+		case PROP_DURATION:
+			gedit_theatrics_animated_widget_set_duration (aw,
+			                                              g_value_get_uint (value));
+			break;
+		case PROP_PERCENT:
+			gedit_theatrics_animated_widget_set_percent (aw,
+			                                             g_value_get_double (value));
+			break;
+		case PROP_ORIENTATION:
+			aw->priv->orientation = g_value_get_enum (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_animated_widget_realize (GtkWidget *widget)
+{
+	GdkWindowAttr attributes;
+	GdkWindow *parent_window;
+	GdkWindow *window;
+	GtkStyle *style;
+
+	gtk_widget_set_realized (widget, TRUE);
+
+	parent_window = gtk_widget_get_parent_window (widget);
+	style = gtk_widget_get_style (widget);
+
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.wclass = GDK_INPUT_OUTPUT;
+	attributes.event_mask = GDK_EXPOSURE_MASK;
+
+	window = gdk_window_new (parent_window, &attributes, 0);
+	gdk_window_set_user_data (window, widget);
+	gtk_widget_set_window (widget, window);
+	gdk_window_set_back_pixmap (window, NULL, FALSE);
+	style = gtk_style_attach (style, window);
+	gtk_widget_set_style (widget, style);
+	gtk_style_set_background (style, window, GTK_STATE_NORMAL);
+}
+
+static void
+gedit_theatrics_animated_widget_size_request (GtkWidget      *widget,
+					      GtkRequisition *requisition)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+	gint width;
+	gint height;
+
+	if (aw->priv->widget != NULL)
+	{
+		GtkRequisition req;
+
+		gtk_widget_size_request (aw->priv->widget, &req);
+		aw->priv->widget_alloc.width = req.width;
+		aw->priv->widget_alloc.height = req.height;
+	}
+
+	if (aw->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+	{
+		width = gedit_theatrics_choreographer_pixel_compose (aw->priv->percent,
+								     aw->priv->widget_alloc.width +
+								     aw->priv->start_padding +
+								     aw->priv->end_padding,
+								     aw->priv->easing);
+		height = aw->priv->widget_alloc.height;
+	}
+	else
+	{
+		width = aw->priv->widget_alloc.width;
+		height = gedit_theatrics_choreographer_pixel_compose (aw->priv->percent,
+								      aw->priv->widget_alloc.height +
+								      aw->priv->start_padding +
+								      aw->priv->end_padding,
+								      aw->priv->easing);
+	}
+
+	requisition->width = width;
+	requisition->height = height;
+}
+
+static void
+gedit_theatrics_animated_widget_size_allocate (GtkWidget     *widget,
+					       GtkAllocation *allocation)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+
+	GTK_WIDGET_CLASS (gedit_theatrics_animated_widget_parent_class)->size_allocate (widget, allocation);
+
+	if (aw->priv->widget != NULL)
+	{
+		if (aw->priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+		{
+			aw->priv->widget_alloc.height = allocation->height;
+			aw->priv->widget_alloc.x = aw->priv->start_padding;
+
+			if (aw->priv->blocking == GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE)
+			{
+				aw->priv->widget_alloc.x += allocation->width - aw->priv->widget_alloc.width;
+			}
+		}
+		else
+		{
+			aw->priv->widget_alloc.width = allocation->width;
+			aw->priv->widget_alloc.y = aw->priv->start_padding;
+
+			if (aw->priv->blocking == GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE)
+			{
+				aw->priv->widget_alloc.y = allocation->height - aw->priv->widget_alloc.height;
+			}
+		}
+
+		if (aw->priv->widget_alloc.height > 0 && aw->priv->widget_alloc.width > 0)
+		{
+			gtk_widget_size_allocate (aw->priv->widget,
+						  &aw->priv->widget_alloc);
+		}
+	}
+}
+
+static gboolean
+gedit_theatrics_animated_widget_expose_event (GtkWidget      *widget,
+					      GdkEventExpose *event)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (widget);
+
+	if (aw->priv->surface != NULL)
+	{
+		/* Do not scale if the size is 0 */
+		if (aw->priv->width > 0 && aw->priv->height > 0)
+		{
+			cairo_t *cr;
+			cr = gdk_cairo_create (event->window);
+
+			cairo_scale (cr,
+				     aw->priv->widget_alloc.width / aw->priv->width,
+				     aw->priv->widget_alloc.height / aw->priv->height);
+			cairo_set_source_surface (cr, aw->priv->surface, 0, 0);
+
+			cairo_paint (cr);
+			cairo_destroy (cr);
+		}
+
+		return TRUE;
+	}
+	else
+	{
+		return GTK_WIDGET_CLASS (gedit_theatrics_animated_widget_parent_class)->expose_event (widget, event);
+	}
+}
+
+static void
+gedit_theatrics_animated_widget_remove (GtkContainer *container,
+					GtkWidget    *widget)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container);
+
+	gtk_widget_unparent (widget);
+	aw->priv->widget = NULL;
+}
+
+static void
+gedit_theatrics_animated_widget_forall (GtkContainer *container,
+					gboolean      include_internals,
+					GtkCallback   callback,
+					gpointer      callback_data)
+{
+	GeditTheatricsAnimatedWidget *aw = GEDIT_THEATRICS_ANIMATED_WIDGET (container);
+
+	if (aw->priv->widget != NULL)
+	{
+		callback (aw->priv->widget, callback_data);
+	}
+}
+
+static void
+gedit_theatrics_animated_widget_class_init (GeditTheatricsAnimatedWidgetClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+	
+	object_class->finalize = gedit_theatrics_animated_widget_finalize;
+	object_class->get_property = gedit_theatrics_animated_widget_get_property;
+	object_class->set_property = gedit_theatrics_animated_widget_set_property;
+
+	widget_class->realize = gedit_theatrics_animated_widget_realize;
+	widget_class->size_request = gedit_theatrics_animated_widget_size_request;
+	widget_class->size_allocate = gedit_theatrics_animated_widget_size_allocate;
+	widget_class->expose_event = gedit_theatrics_animated_widget_expose_event;
+
+	container_class->remove = gedit_theatrics_animated_widget_remove;
+	container_class->forall = gedit_theatrics_animated_widget_forall;
+
+	g_object_class_install_property (object_class, PROP_WIDGET,
+	                                 g_param_spec_object ("widget",
+	                                                      "Widget",
+	                                                      "The Widget",
+	                                                      GTK_TYPE_WIDGET,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT_ONLY |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_EASING,
+	                                 g_param_spec_enum ("easing",
+	                                                    "Easing",
+	                                                    "The Easing",
+	                                                    GEDIT_TYPE_THEATRICS_CHOREOGRAPHER_EASING,
+	                                                    GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_BLOCKING,
+	                                 g_param_spec_enum ("blocking",
+	                                                    "Blocking",
+	                                                    "The Blocking",
+	                                                    GEDIT_TYPE_THEATRICS_CHOREOGRAPHER_BLOCKING,
+	                                                    GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_ANIMATION_STATE,
+	                                 g_param_spec_enum ("animation-state",
+	                                                    "Animation State",
+	                                                    "The Animation State",
+	                                                    GEDIT_TYPE_THEATRICS_ANIMATION_STATE,
+	                                                    GEDIT_THEATRICS_ANIMATION_STATE_COMING,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_DURATION,
+	                                 g_param_spec_uint ("duration",
+	                                                    "Duration",
+	                                                    "The duration",
+	                                                    0,
+	                                                    G_MAXUINT,
+	                                                    0,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property (object_class, PROP_PERCENT,
+	                                 g_param_spec_double ("percent",
+	                                                      "Percent",
+	                                                      "The percent",
+	                                                      0,
+	                                                      G_MAXDOUBLE,
+	                                                      0.0,
+	                                                      G_PARAM_READWRITE |
+	                                                      G_PARAM_CONSTRUCT |
+	                                                      G_PARAM_STATIC_STRINGS));
+
+	g_object_class_override_property (object_class,
+	                                  PROP_ORIENTATION,
+	                                  "orientation");
+
+	signals[REMOVE_CORE] =
+		g_signal_new ("remove-core",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (GeditTheatricsAnimatedWidgetClass, remove_core),
+		              NULL, NULL,
+		              g_cclosure_marshal_VOID__VOID,
+		              G_TYPE_NONE,
+		              0);
+
+	g_type_class_add_private (object_class, sizeof (GeditTheatricsAnimatedWidgetPrivate));
+}
+
+static void
+gedit_theatrics_animated_widget_init (GeditTheatricsAnimatedWidget *aw)
+{
+	aw->priv = GEDIT_THEATRICS_ANIMATED_WIDGET_GET_PRIVATE (aw);
+
+	gtk_widget_set_has_window (GTK_WIDGET (aw), TRUE);
+
+	aw->priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+	aw->priv->bias = 1.0;
+}
+
+GeditTheatricsAnimatedWidget *
+gedit_theatrics_animated_widget_new (GtkWidget                          *widget,
+				     guint                               duration,
+				     GeditTheatricsChoreographerEasing   easing,
+				     GeditTheatricsChoreographerBlocking blocking,
+				     GtkOrientation                      orientation)
+{
+	return g_object_new (GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET,
+			     "widget", widget,
+			     "duration", duration,
+			     "easing", easing,
+			     "blocking", blocking,
+			     "orientation", orientation,
+			     NULL);
+}
+
+GtkWidget *
+gedit_theatrics_animated_widget_get_widget (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), NULL);
+
+	return aw->priv->widget;
+}
+
+GeditTheatricsChoreographerEasing
+gedit_theatrics_animated_widget_get_easing (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR);
+
+	return aw->priv->easing;
+}
+
+void
+gedit_theatrics_animated_widget_set_easing (GeditTheatricsAnimatedWidget     *aw,
+					    GeditTheatricsChoreographerEasing easing)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	if (aw->priv->easing != easing)
+	{
+		aw->priv->easing = easing;
+
+		g_object_notify (G_OBJECT (aw), "easing");
+	}
+}
+
+GeditTheatricsChoreographerBlocking
+gedit_theatrics_animated_widget_get_blocking (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE);
+
+	return aw->priv->blocking;
+}
+
+void
+gedit_theatrics_animated_widget_set_blocking (GeditTheatricsAnimatedWidget       *aw,
+					      GeditTheatricsChoreographerBlocking blocking)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	if (aw->priv->blocking != blocking)
+	{
+		aw->priv->blocking = blocking;
+
+		g_object_notify (G_OBJECT (aw), "blocking");
+	}
+}
+
+GeditTheatricsAnimationState
+gedit_theatrics_animated_widget_get_animation_state (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), GEDIT_THEATRICS_ANIMATION_STATE_COMING);
+
+	return aw->priv->animation_state;
+}
+
+void
+gedit_theatrics_animated_widget_set_animation_state (GeditTheatricsAnimatedWidget *aw,
+						     GeditTheatricsAnimationState  animation_state)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	if (aw->priv->animation_state != animation_state)
+	{
+		aw->priv->animation_state = animation_state;
+
+		g_object_notify (G_OBJECT (aw), "animation-state");
+	}
+}
+
+guint
+gedit_theatrics_animated_widget_get_duration (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), 0);
+
+	return aw->priv->duration;
+}
+
+void
+gedit_theatrics_animated_widget_set_duration (GeditTheatricsAnimatedWidget *aw,
+					      guint                         duration)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	if (aw->priv->duration != duration)
+	{
+		aw->priv->duration = duration;
+
+		g_object_notify (G_OBJECT (aw), "duration");
+	}
+}
+
+gdouble
+gedit_theatrics_animated_widget_get_percent (GeditTheatricsAnimatedWidget *aw)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw), 0.0);
+
+	return aw->priv->duration;
+}
+
+void
+gedit_theatrics_animated_widget_set_percent (GeditTheatricsAnimatedWidget *aw,
+					     gdouble                       percent)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	if (aw->priv->percent != percent)
+	{
+		aw->priv->percent = aw->priv->bias * percent;
+
+		g_object_notify (G_OBJECT (aw), "percent");
+
+		gtk_widget_queue_resize_no_redraw (GTK_WIDGET (aw));
+	}
+}
+
+void
+gedit_theatrics_animated_widget_set_bias (GeditTheatricsAnimatedWidget *aw,
+                                          gdouble                       bias)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	aw->priv->bias = bias;
+}
+
+void
+gedit_theatrics_animated_widget_set_end_padding (GeditTheatricsAnimatedWidget *aw,
+                                                 gint                          end_padding)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_ANIMATED_WIDGET (aw));
+
+	aw->priv->end_padding = end_padding;
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-animated-widget.h b/gedit/theatrics/gedit-theatrics-animated-widget.h
new file mode 100644
index 0000000..603ce6c
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-animated-widget.h
@@ -0,0 +1,108 @@
+/*
+ * gedit-theatrics-animated-widget.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * 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_THEATRICS_ANIMATED_WIDGET_H__
+#define __GEDIT_THEATRICS_ANIMATED_WIDGET_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include "gedit-theatrics-animation.h"
+#include "gedit-theatrics-choreographer.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET		(gedit_theatrics_animated_widget_get_type ())
+#define GEDIT_THEATRICS_ANIMATED_WIDGET(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_CONST(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidget const))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass))
+#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET))
+#define GEDIT_IS_THEATRICS_ANIMATED_WIDGET_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET))
+#define GEDIT_THEATRICS_ANIMATED_WIDGET_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_ANIMATED_WIDGET, GeditTheatricsAnimatedWidgetClass))
+
+typedef struct _GeditTheatricsAnimatedWidget		GeditTheatricsAnimatedWidget;
+typedef struct _GeditTheatricsAnimatedWidgetClass	GeditTheatricsAnimatedWidgetClass;
+typedef struct _GeditTheatricsAnimatedWidgetPrivate	GeditTheatricsAnimatedWidgetPrivate;
+
+struct _GeditTheatricsAnimatedWidget
+{
+	GtkBin parent;
+	
+	GeditTheatricsAnimatedWidgetPrivate *priv;
+};
+
+struct _GeditTheatricsAnimatedWidgetClass
+{
+	GtkBinClass parent_class;
+
+	void (* remove_core) (GeditTheatricsAnimatedWidget *aw);
+};
+
+GType				 gedit_theatrics_animated_widget_get_type	(void) G_GNUC_CONST;
+
+GeditTheatricsAnimatedWidget	*gedit_theatrics_animated_widget_new		(GtkWidget                          *widget,
+										 guint                               duration,
+										 GeditTheatricsChoreographerEasing   easing,
+										 GeditTheatricsChoreographerBlocking blocking,
+										 GtkOrientation                      orientation);
+
+GtkWidget			*gedit_theatrics_animated_widget_get_widget	(GeditTheatricsAnimatedWidget *aw);
+
+GeditTheatricsChoreographerEasing
+				 gedit_theatrics_animated_widget_get_easing	(GeditTheatricsAnimatedWidget *aw);
+
+void				 gedit_theatrics_animated_widget_set_easing	(GeditTheatricsAnimatedWidget     *aw,
+										 GeditTheatricsChoreographerEasing easing);
+
+GeditTheatricsChoreographerBlocking
+				 gedit_theatrics_animated_widget_get_blocking	(GeditTheatricsAnimatedWidget *aw);
+
+void				 gedit_theatrics_animated_widget_set_blocking	(GeditTheatricsAnimatedWidget       *aw,
+										 GeditTheatricsChoreographerBlocking blocking);
+
+GeditTheatricsAnimationState	 gedit_theatrics_animated_widget_get_animation_state
+										(GeditTheatricsAnimatedWidget *aw);
+
+void				 gedit_theatrics_animated_widget_set_animation_state
+										(GeditTheatricsAnimatedWidget *aw,
+										 GeditTheatricsAnimationState  animation_state);
+
+guint				 gedit_theatrics_animated_widget_get_duration	(GeditTheatricsAnimatedWidget *aw);
+
+void				 gedit_theatrics_animated_widget_set_duration	(GeditTheatricsAnimatedWidget *aw,
+										 guint                         duration);
+
+gdouble				 gedit_theatrics_animated_widget_get_percent	(GeditTheatricsAnimatedWidget *aw);
+
+void				 gedit_theatrics_animated_widget_set_percent	(GeditTheatricsAnimatedWidget *aw,
+										 gdouble                       percent);
+
+void				 gedit_theatrics_animated_widget_set_bias	(GeditTheatricsAnimatedWidget *aw,
+										 gdouble                       bias);
+
+void				 gedit_theatrics_animated_widget_set_end_padding(GeditTheatricsAnimatedWidget *aw,
+										 gint                          end_padding);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_ANIMATED_WIDGET_H__ */
diff --git a/gedit/theatrics/gedit-theatrics-choreographer.c b/gedit/theatrics/gedit-theatrics-choreographer.c
new file mode 100644
index 0000000..1dbf582
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-choreographer.c
@@ -0,0 +1,85 @@
+/*
+ * gedit-theatrics-choreographer.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * 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 <math.h>
+#include "gedit-theatrics-choreographer.h"
+
+gint
+gedit_theatrics_choreographer_pixel_compose (gdouble                           percent,
+					     gint                              size,
+					     GeditTheatricsChoreographerEasing easing)
+{
+	return (gint)round (gedit_theatrics_choreographer_compose_with_scale (percent, size, easing));
+}
+
+gdouble
+gedit_theatrics_choreographer_compose_with_scale (gdouble                           percent,
+						  gdouble                           scale,
+						  GeditTheatricsChoreographerEasing easing)
+{
+	return scale * gedit_theatrics_choreographer_compose (percent, easing);
+}
+
+gdouble
+gedit_theatrics_choreographer_compose (gdouble                           percent,
+				       GeditTheatricsChoreographerEasing easing)
+{
+	g_return_val_if_fail (percent >= 0.0 && percent <= 1.0, 0.0);
+
+	switch (easing)
+	{
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN:
+			return percent * percent;
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT:
+			return -1.0 * percent * (percent - 2.0);
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN_OUT:
+			percent *= 2.0;
+			return percent < 1.0
+				? percent * percent * 0.5
+				: -0.5 * ((percent - 1.0) * (percent - 2.0) - 1.0);
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN:
+			return pow (2.0, 10.0 * (percent - 1.0));
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT:
+			return -pow (2.0, -10.0 * percent) + 1.0;
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT:
+			percent *= 2.0;
+			return percent < 1.0
+				? 0.5 * pow (2.0, 10.0 * (percent - 1.0))
+				: 0.5 * (-pow (2.0, -10.0 * (percent - 1.0)) + 2.0);
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_SINE:
+			return sin (percent * G_PI);
+
+		case GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR:
+		default:
+			return percent;
+	}
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-choreographer.h b/gedit/theatrics/gedit-theatrics-choreographer.h
new file mode 100644
index 0000000..310cc8f
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-choreographer.h
@@ -0,0 +1,74 @@
+/*
+ * gedit-theatrics-choreographer.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Scott Peterson <lunchtimemama gmail com> work.
+ *
+ * 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_THEATRICS_CHOREOGRAPHER_H__
+#define __GEDIT_THEATRICS_CHOREOGRAPHER_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+	GEDIT_THEATRICS_ANIMATION_STATE_COMING,
+	GEDIT_THEATRICS_ANIMATION_STATE_IDLE,
+	GEDIT_THEATRICS_ANIMATION_STATE_INTENDING_TO_GO,
+	GEDIT_THEATRICS_ANIMATION_STATE_GOING
+} GeditTheatricsAnimationState;
+
+typedef enum
+{
+	GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_UPSTAGE,
+	GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE
+} GeditTheatricsChoreographerBlocking;
+
+typedef enum
+{
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_LINEAR,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_OUT,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_QUADRATIC_IN_OUT,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_OUT,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+	GEDIT_THEATRICS_CHOREOGRAPHER_EASING_SINE
+} GeditTheatricsChoreographerEasing;
+
+gint	gedit_theatrics_choreographer_pixel_compose		(gdouble                           percent,
+								 gint                              size,
+								 GeditTheatricsChoreographerEasing easing);
+
+gdouble	gedit_theatrics_choreographer_compose_with_scale	(gdouble                           percent,
+								 gdouble                           scale,
+								 GeditTheatricsChoreographerEasing easing);
+
+gdouble	gedit_theatrics_choreographer_compose			(gdouble                           percent,
+								 GeditTheatricsChoreographerEasing easing);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_CHOREOGRAPHER_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-enum-types.c.template b/gedit/theatrics/gedit-theatrics-enum-types.c.template
new file mode 100644
index 0000000..9d53bbc
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-enum-types.c.template
@@ -0,0 +1,39 @@
+/*** BEGIN file-header ***/
+#include "gedit-theatrics-enum-types.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+#include "@filename@"
+
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ enum_name@_get_type (void)
+{
+	static GType the_type = 0;
+	
+	if (the_type == 0)
+	{
+		static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+			{ @VALUENAME@,
+			  "@VALUENAME@",
+			  "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+			{ 0, NULL, NULL }
+		};
+		the_type = g_ type@_register_static (
+				g_intern_static_string ("@EnumName@"),
+				values);
+	}
+	return the_type;
+}
+
+/*** END value-tail ***/
diff --git a/gedit/theatrics/gedit-theatrics-enum-types.h.template b/gedit/theatrics/gedit-theatrics-enum-types.h.template
new file mode 100644
index 0000000..4eb11eb
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-enum-types.h.template
@@ -0,0 +1,27 @@
+/*** BEGIN file-header ***/
+#ifndef __GEDIT_THEATRICS_ENUM_TYPES_H__
+#define __GEDIT_THEATRICS_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* Enumerations from "@filename@" */
+
+/*** END file-production ***/
+
+/*** BEGIN enumeration-production ***/
+#define GEDIT_TYPE_ ENUMSHORT@	(@enum_name _get_type())
+GType @enum_name _get_type	(void) G_GNUC_CONST;
+
+/*** END enumeration-production ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __GEDIT_ENUM_TYPES_H__ */
+/*** END file-tail ***/
+
diff --git a/gedit/theatrics/gedit-theatrics-marshal.list b/gedit/theatrics/gedit-theatrics-marshal.list
new file mode 100644
index 0000000..38076d6
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-marshal.list
@@ -0,0 +1 @@
+VOID:OBJECT,OBJECT
diff --git a/gedit/theatrics/gedit-theatrics-stage.c b/gedit/theatrics/gedit-theatrics-stage.c
new file mode 100644
index 0000000..fed1b05
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-stage.c
@@ -0,0 +1,313 @@
+/*
+ * gedit-theatrics-stage.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * 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-theatrics-stage.h"
+
+
+#define DEFAULT_UPDATE_FREQUENCY 30
+#define DEFAULT_DURATION 1000
+
+#define GEDIT_THEATRICS_STAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStagePrivate))
+
+struct _GeditTheatricsStagePrivate
+{
+	GHashTable *actors;
+	guint timeout_id;
+	guint update_frequency;
+	guint actor_duration;
+
+	guint playing : 1;
+};
+
+enum
+{
+	PROP_0,
+	PROP_ACTOR_DURATION
+};
+
+enum
+{
+	ACTOR_STEP,
+	ITERATION,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GeditTheatricsStage, gedit_theatrics_stage, G_TYPE_OBJECT)
+
+static void
+gedit_theatrics_stage_dispose (GObject *object)
+{
+	GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+	if (stage->priv->timeout_id != 0)
+	{
+		g_source_remove (stage->priv->timeout_id);
+		stage->priv->timeout_id = 0;
+	}
+
+	G_OBJECT_CLASS (gedit_theatrics_stage_parent_class)->dispose (object);
+}
+
+static void
+gedit_theatrics_stage_finalize (GObject *object)
+{
+	GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+	g_hash_table_destroy (stage->priv->actors);
+
+	G_OBJECT_CLASS (gedit_theatrics_stage_parent_class)->finalize (object);
+}
+
+static void
+gedit_theatrics_stage_get_property (GObject    *object,
+				    guint       prop_id,
+				    GValue     *value,
+				    GParamSpec *pspec)
+{
+	GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+	switch (prop_id)
+	{
+		case PROP_ACTOR_DURATION:
+			g_value_set_uint (value, stage->priv->actor_duration);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_stage_set_property (GObject      *object,
+				    guint         prop_id,
+				    const GValue *value,
+				    GParamSpec   *pspec)
+{
+	GeditTheatricsStage *stage = GEDIT_THEATRICS_STAGE (object);
+
+	switch (prop_id)
+	{
+		case PROP_ACTOR_DURATION:
+			stage->priv->actor_duration = g_value_get_uint (value);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+			break;
+	}
+}
+
+static void
+gedit_theatrics_stage_class_init (GeditTheatricsStageClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->dispose = gedit_theatrics_stage_dispose;
+	object_class->finalize = gedit_theatrics_stage_finalize;
+	object_class->get_property = gedit_theatrics_stage_get_property;
+	object_class->set_property = gedit_theatrics_stage_set_property;
+
+	g_object_class_install_property (object_class, PROP_ACTOR_DURATION,
+	                                 g_param_spec_uint ("actor-duration",
+	                                                    "Actor Duration",
+	                                                    "The actor duration",
+	                                                    0,
+	                                                    G_MAXUINT,
+	                                                    DEFAULT_DURATION,
+	                                                    G_PARAM_READWRITE |
+	                                                    G_PARAM_CONSTRUCT |
+	                                                    G_PARAM_STATIC_STRINGS));
+
+	signals[ACTOR_STEP] =
+		g_signal_new ("actor-step",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GeditTheatricsStageClass, actor_step),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__OBJECT,
+			      G_TYPE_NONE,
+			      1,
+			      GEDIT_TYPE_THEATRICS_ACTOR);
+
+	signals[ITERATION] =
+		g_signal_new ("iteration",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (GeditTheatricsStageClass, iteration),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+
+	g_type_class_add_private (object_class, sizeof (GeditTheatricsStagePrivate));
+}
+
+static void
+gedit_theatrics_stage_init (GeditTheatricsStage *stage)
+{
+	stage->priv = GEDIT_THEATRICS_STAGE_GET_PRIVATE (stage);
+
+	stage->priv->update_frequency = DEFAULT_UPDATE_FREQUENCY;
+	stage->priv->actor_duration = DEFAULT_DURATION;
+	stage->priv->playing = TRUE;
+
+	stage->priv->actors = g_hash_table_new (g_direct_hash,
+						g_direct_equal);
+}
+
+static void
+iterate_actors (gpointer             key,
+		gpointer             value,
+		GeditTheatricsStage *stage)
+{
+	GeditTheatricsActor *actor = GEDIT_THEATRICS_ACTOR (value);
+
+	gedit_theatrics_actor_step (actor);
+
+	g_signal_emit (G_OBJECT (stage), signals[ACTOR_STEP], 0, actor);
+
+	if (gedit_theatrics_actor_get_expired (actor))
+	{
+		g_hash_table_remove (stage->priv->actors, key);
+	}
+}
+
+static gboolean
+on_timeout (GeditTheatricsStage *stage)
+{
+	if (!stage->priv->playing || g_hash_table_size (stage->priv->actors) == 0)
+	{
+		stage->priv->timeout_id = 0;
+		return FALSE;
+	}
+
+	g_hash_table_foreach (stage->priv->actors,
+			      (GHFunc)iterate_actors,
+			      stage);
+
+	g_signal_emit (G_OBJECT (stage), signals[ITERATION], 0);
+
+	return TRUE;
+}
+
+static void
+check_timeout (GeditTheatricsStage *stage)
+{
+	if ((!stage->priv->playing ||
+	     g_hash_table_size (stage->priv->actors) == 0) &&
+	    stage->priv->timeout_id)
+	{
+		g_source_remove (stage->priv->timeout_id);
+		stage->priv->timeout_id = 0;
+	}
+	else if ((stage->priv->playing &&
+	          g_hash_table_size (stage->priv->actors) > 0) &&
+	         stage->priv->timeout_id <= 0)
+	{
+		stage->priv->timeout_id = g_timeout_add (stage->priv->update_frequency,
+							 (GSourceFunc) on_timeout,
+							 stage);
+	}
+}
+
+GeditTheatricsStage *
+gedit_theatrics_stage_new ()
+{
+	return g_object_new (GEDIT_TYPE_THEATRICS_STAGE, NULL);
+}
+
+GeditTheatricsStage *
+gedit_theatrics_stage_new_with_duration (guint actor_duration)
+{
+	return g_object_new (GEDIT_TYPE_THEATRICS_STAGE,
+			     "actor-duration", actor_duration,
+			     NULL);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_stage_add (GeditTheatricsStage *stage,
+			   GObject             *target)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), NULL);
+
+	return gedit_theatrics_stage_add_with_duration (stage, target,
+							stage->priv->actor_duration);
+}
+
+GeditTheatricsActor *
+gedit_theatrics_stage_add_with_duration (GeditTheatricsStage *stage,
+					 GObject             *target,
+					 guint                duration)
+{
+	GeditTheatricsActor *actor;
+
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), NULL);
+
+	actor = g_hash_table_lookup (stage->priv->actors,
+				     target);
+
+	if (actor != NULL)
+	{
+		g_warning ("Stage already contains this actor");
+		return NULL;
+	}
+
+	actor = gedit_theatrics_actor_new (target, duration);
+
+	g_hash_table_insert (stage->priv->actors,
+			     target, actor);
+
+	check_timeout (stage);
+
+	return actor;
+}
+
+void
+gedit_theatrics_stage_remove (GeditTheatricsStage *stage,
+			      GObject             *target)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_STAGE (stage));
+
+	g_hash_table_remove (stage->priv->actors, target);
+}
+
+void
+gedit_theatrics_stage_set_playing (GeditTheatricsStage *stage,
+				   gboolean             playing)
+{
+	g_return_if_fail (GEDIT_IS_THEATRICS_STAGE (stage));
+
+	stage->priv->playing = playing;
+}
+
+gboolean
+gedit_theatrics_stage_get_playing (GeditTheatricsStage *stage)
+{
+	g_return_val_if_fail (GEDIT_IS_THEATRICS_STAGE (stage), FALSE);
+
+	return stage->priv->playing;
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-stage.h b/gedit/theatrics/gedit-theatrics-stage.h
new file mode 100644
index 0000000..ed31759
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-stage.h
@@ -0,0 +1,87 @@
+/*
+ * gedit-theatrics-stage.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Aaron Bockover <abockover novell com> work.
+ *
+ * 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_THEATRICS_STAGE_H__
+#define __GEDIT_THEATRICS_STAGE_H__
+
+#include <glib-object.h>
+#include "gedit-theatrics-actor.h"
+
+G_BEGIN_DECLS
+
+#define GEDIT_TYPE_THEATRICS_STAGE		(gedit_theatrics_stage_get_type ())
+#define GEDIT_THEATRICS_STAGE(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStage))
+#define GEDIT_THEATRICS_STAGE_CONST(obj)	(G_TYPE_CHECK_INSTANCE_CAST ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStage const))
+#define GEDIT_THEATRICS_STAGE_CLASS(klass)	(G_TYPE_CHECK_CLASS_CAST ((klass), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStageClass))
+#define GEDIT_IS_THEATRICS_STAGE(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEDIT_TYPE_THEATRICS_STAGE))
+#define GEDIT_IS_THEATRICS_STAGE_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GEDIT_TYPE_THEATRICS_STAGE))
+#define GEDIT_THEATRICS_STAGE_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GEDIT_TYPE_THEATRICS_STAGE, GeditTheatricsStageClass))
+
+typedef struct _GeditTheatricsStage		GeditTheatricsStage;
+typedef struct _GeditTheatricsStageClass	GeditTheatricsStageClass;
+typedef struct _GeditTheatricsStagePrivate	GeditTheatricsStagePrivate;
+
+struct _GeditTheatricsStage
+{
+	GObject parent;
+
+	GeditTheatricsStagePrivate *priv;
+};
+
+struct _GeditTheatricsStageClass
+{
+	GObjectClass parent_class;
+
+	void (* actor_step) (GeditTheatricsStage *stage,
+			     GeditTheatricsActor *actor);
+
+	void (* iteration) (GeditTheatricsStage *stage);
+};
+
+GType			 gedit_theatrics_stage_get_type		(void) G_GNUC_CONST;
+
+GeditTheatricsStage	*gedit_theatrics_stage_new		(void);
+
+GeditTheatricsStage	*gedit_theatrics_stage_new_with_duration(guint actor_duration);
+
+GeditTheatricsActor	*gedit_theatrics_stage_add		(GeditTheatricsStage *stage,
+								 GObject             *target);
+
+GeditTheatricsActor	*gedit_theatrics_stage_add_with_duration(GeditTheatricsStage *stage,
+								 GObject             *target,
+								 guint                duration);
+
+void			 gedit_theatrics_stage_remove		(GeditTheatricsStage *stage,
+								 GObject             *target);
+
+void			 gedit_theatrics_stage_set_playing	(GeditTheatricsStage *stage,
+								 gboolean             playing);
+
+gboolean		 gedit_theatrics_stage_get_playing	(GeditTheatricsStage *stage);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_STAGE_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-utils.c b/gedit/theatrics/gedit-theatrics-utils.c
new file mode 100644
index 0000000..374b7d2
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-utils.c
@@ -0,0 +1,131 @@
+/*
+ * gedit-theatrics-utils.c
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gedit-theatrics-utils.h"
+
+void
+gedit_theatrics_utils_draw_round_rectangle (cairo_t *cr,
+					    gboolean top_left_round,
+					    gboolean top_right_round,
+					    gboolean bottom_left_round,
+					    gboolean bottom_right_round,
+					    gdouble  x,
+					    gdouble  y,
+					    gdouble  r,
+					    gdouble  w,
+					    gdouble  h)
+{
+	/*
+	   UA****BQ
+	   H      C
+	   *      *
+	   G      D
+	   TF****ES
+	*/
+
+	cairo_new_path (cr);
+
+	if (top_left_round)
+	{
+		/* Move to A */
+		cairo_move_to (cr, x + r, y);
+	}
+	else
+	{
+		/* Move to U */
+		cairo_move_to (cr, x, y);
+	}
+
+	if (top_right_round)
+	{
+		/* Straight line to B */
+		cairo_line_to (cr, x + w - r, y);
+
+		/* Curve to C, Control points are both at Q */
+		cairo_curve_to (cr, x + w, y, 
+		                x + w, y,
+		                x + w, y + r);
+	}
+	else
+	{
+		/* Straight line to Q */
+		cairo_line_to (cr, x + w, y);
+	}
+
+	if (bottom_right_round)
+	{
+		/* Move to D */
+		cairo_line_to (cr, x + w, y + h - r);
+
+		/* Curve to E */
+		cairo_curve_to (cr, x + w, y + h,
+		                x + w, y + h,
+		                x + w - r, y + h);
+	}
+	else
+	{
+		/* Move to S */
+		cairo_line_to (cr, x + w, y + h);
+	}
+
+	if (bottom_left_round)
+	{
+		/* Line to F */
+		cairo_line_to (cr, x + r, y + h);
+
+		/* Curve to G */
+		cairo_curve_to (cr, x, y + h, 
+		                x, y + h , 
+		                x, y + h - r);
+	}
+	else
+	{
+		/* Line to T */
+		cairo_line_to (cr, x, y + h);
+	}
+
+	if (top_left_round)
+	{
+		/* Line to H */
+		cairo_line_to (cr, x, y + r);
+
+		/* Curve to A */
+		cairo_curve_to (cr, x, y,
+		                x , y, 
+		                x + r, y);
+	}
+	else
+	{
+		/* Line to U */
+		cairo_line_to (cr, x, y);
+	}
+
+	cairo_close_path (cr);
+}
+
+/* ex:ts=8:noet: */
diff --git a/gedit/theatrics/gedit-theatrics-utils.h b/gedit/theatrics/gedit-theatrics-utils.h
new file mode 100644
index 0000000..8113c4b
--- /dev/null
+++ b/gedit/theatrics/gedit-theatrics-utils.h
@@ -0,0 +1,48 @@
+/*
+ * gedit-theatrics-utils.h
+ * This file is part of gedit
+ *
+ * Copyright (C) 2010 - Ignacio Casal Quinteiro
+ *
+ * Based on Mike Krüger <mkrueger novell com> work.
+ *
+ * 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_THEATRICS_UTILS_H__
+#define __GEDIT_THEATRICS_UTILS_H__
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void		gedit_theatrics_utils_draw_round_rectangle	(cairo_t *cr,
+								 gboolean top_left_round,
+								 gboolean top_right_round,
+								 gboolean bottom_left_round,
+								 gboolean bottom_right_round,
+								 gdouble  x,
+								 gdouble  y,
+								 gdouble  r,
+								 gdouble  w,
+								 gdouble  h);
+
+G_END_DECLS
+
+#endif /* __GEDIT_THEATRICS_UTILS_H__ */
+
+/* ex:ts=8:noet: */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index e4cd496..15fd334 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,6 +23,14 @@ TEST_PROGS			+= document-saver
 document_saver_SOURCES		= document-saver.c
 document_saver_LDADD		= $(progs_ldadd)
 
+TEST_PROGS			+= test-rounded-frame
+test_rounded_frame_SOURCES	= test-rounded-frame.c
+test_rounded_frame_LDADD	= $(progs_ldadd)
+
+TEST_PROGS			+= test-overlay
+test_overlay_SOURCES		= test-overlay.c
+test_overlay_LDADD		= $(progs_ldadd)
+
 TESTS = $(TEST_PROGS)
 
 EXTRA_DIST = setup-document-saver.sh
diff --git a/tests/test-overlay.c b/tests/test-overlay.c
new file mode 100644
index 0000000..4288473
--- /dev/null
+++ b/tests/test-overlay.c
@@ -0,0 +1,62 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+#include "gedit-overlay.h"
+#include "gedit-rounded-frame.h"
+
+static void
+on_button_clicked (GtkWidget *button,
+                   GtkWidget *frame)
+{
+	gtk_widget_destroy (frame);
+}
+
+gint
+main ()
+{
+	GtkWidget *window;
+	GtkWidget *textview;
+	GtkWidget *overlay;
+	GtkWidget *frame;
+	GtkWidget *entry;
+	GtkWidget *vbox;
+	GtkWidget *button;
+
+	gtk_init (NULL, NULL);
+
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);
+	vbox = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (window), vbox);
+
+	textview = gtk_text_view_new ();
+	overlay = gedit_overlay_new (textview);
+
+	gtk_box_pack_start (GTK_BOX (vbox), overlay, TRUE, TRUE, 0);
+
+	frame = gedit_rounded_frame_new ();
+	gtk_widget_show (frame);
+
+	entry = gtk_entry_new ();
+
+	gtk_container_add (GTK_CONTAINER (frame), entry);
+
+	gedit_overlay_add_animated_widget (GEDIT_OVERLAY (overlay),
+	                                   frame,
+	                                   1000,
+	                                   GEDIT_THEATRICS_CHOREOGRAPHER_EASING_EXPONENTIAL_IN_OUT,
+	                                   GEDIT_THEATRICS_CHOREOGRAPHER_BLOCKING_DOWNSTAGE,
+	                                   GTK_ORIENTATION_VERTICAL,
+	                                   0, 0);
+
+	button = gtk_button_new_with_label ("Hide");
+	gtk_box_pack_end (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+	g_signal_connect (button, "clicked",
+	                  G_CALLBACK (on_button_clicked),
+	                  frame);
+
+	gtk_widget_show_all (window);
+
+	gtk_main ();
+
+	return 0;
+}
diff --git a/tests/test-rounded-frame.c b/tests/test-rounded-frame.c
new file mode 100644
index 0000000..c0bdab9
--- /dev/null
+++ b/tests/test-rounded-frame.c
@@ -0,0 +1,29 @@
+#include <gtk/gtk.h>
+#include <glib.h>
+#include "gedit-rounded-frame.h"
+
+gint main ()
+{
+	GtkWidget *window;
+	GtkWidget *frame;
+	GtkWidget *entry;
+
+	gtk_init (NULL, NULL);
+
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+	frame = gedit_rounded_frame_new ();
+
+	gtk_container_add (GTK_CONTAINER (window), frame);
+
+	entry = gtk_entry_new ();
+
+	gtk_container_add (GTK_CONTAINER (frame), entry);
+	gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
+
+	gtk_widget_show_all (window);
+
+	gtk_main ();
+
+	return 0;
+}



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