summaryrefslogtreecommitdiffstats
path: root/third_party
diff options
context:
space:
mode:
authortfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-28 02:32:12 +0000
committertfarina@chromium.org <tfarina@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-28 02:32:12 +0000
commit6803ce1b07793a2c81ab26241198df8cb98d4b0a (patch)
tree2fa55b661f2770ae99d2d3a0b9b56f319d751619 /third_party
parente65dda8abfda0fc35d837e275771b53719946cd3 (diff)
downloadchromium_src-6803ce1b07793a2c81ab26241198df8cb98d4b0a.zip
chromium_src-6803ce1b07793a2c81ab26241198df8cb98d4b0a.tar.gz
chromium_src-6803ce1b07793a2c81ab26241198df8cb98d4b0a.tar.bz2
Landing http://codereview.chromium.org/3387008 for sadrul:
linux: Add support for undo in the omnibox. GtkTextView does not support undo. So borrow the relevant code from GtkSourceView. BUG=18210 TEST=None Patch from sadrul <sadrul@chromium.org> Review URL: http://codereview.chromium.org/3429025 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60744 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'third_party')
-rw-r--r--third_party/undoview/LICENSE165
-rw-r--r--third_party/undoview/README.chromium9
-rw-r--r--third_party/undoview/undo_manager.c1084
-rw-r--r--third_party/undoview/undo_manager.h86
-rw-r--r--third_party/undoview/undo_view.c83
-rw-r--r--third_party/undoview/undo_view.h51
-rw-r--r--third_party/undoview/undoview.gyp22
7 files changed, 1500 insertions, 0 deletions
diff --git a/third_party/undoview/LICENSE b/third_party/undoview/LICENSE
new file mode 100644
index 0000000..65c5ca8
--- /dev/null
+++ b/third_party/undoview/LICENSE
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/third_party/undoview/README.chromium b/third_party/undoview/README.chromium
new file mode 100644
index 0000000..260d8e3
--- /dev/null
+++ b/third_party/undoview/README.chromium
@@ -0,0 +1,9 @@
+Name: undoview
+URL: http://projects.gnome.org/gtksourceview/
+
+This contains GtkUndoView, which is GtkTextView with undo/redo
+support. The code to add the support is borrowed from GtkSourceView.
+However since SV has a lot of other stuff we don't want, we borrow
+only the undo support and add it to GtkTextView to create a
+GtkUndoView.
+
diff --git a/third_party/undoview/undo_manager.c b/third_party/undoview/undo_manager.c
new file mode 100644
index 0000000..9136b37
--- /dev/null
+++ b/third_party/undoview/undo_manager.c
@@ -0,0 +1,1084 @@
+/*
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002-2005 Paolo Maggi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "undo_manager.h"
+
+#define DEFAULT_MAX_UNDO_LEVELS 25
+
+typedef struct _GtkSourceUndoAction GtkSourceUndoAction;
+typedef struct _GtkSourceUndoInsertAction GtkSourceUndoInsertAction;
+typedef struct _GtkSourceUndoDeleteAction GtkSourceUndoDeleteAction;
+
+typedef enum {
+ GTK_SOURCE_UNDO_ACTION_INSERT,
+ GTK_SOURCE_UNDO_ACTION_DELETE,
+} GtkSourceUndoActionType;
+
+/*
+ * We use offsets instead of GtkTextIters because the last ones
+ * require to much memory in this context without giving us any advantage.
+ */
+
+struct _GtkSourceUndoInsertAction {
+ gint pos;
+ gchar *text;
+ gint length;
+ gint chars;
+};
+
+struct _GtkSourceUndoDeleteAction {
+ gint start;
+ gint end;
+ gchar *text;
+ gboolean forward;
+};
+
+struct _GtkSourceUndoAction {
+ GtkSourceUndoActionType action_type;
+
+ union {
+ GtkSourceUndoInsertAction insert;
+ GtkSourceUndoDeleteAction delete;
+ } action;
+
+ gint order_in_group;
+
+ /* It is TRUE whether the action can be merged with the following action. */
+ guint mergeable : 1;
+
+ /* It is TRUE whether the action is marked as "modified".
+ * An action is marked as "modified" if it changed the
+ * state of the buffer from "not modified" to "modified". Only the first
+ * action of a group can be marked as modified.
+ * There can be a single action marked as "modified" in the actions list.
+ */
+ guint modified : 1;
+};
+
+/* INVALID is a pointer to an invalid action */
+#define INVALID ((void *) "IA")
+
+struct _GtkSourceUndoManagerPrivate {
+ GtkTextBuffer *document;
+
+ GList* actions;
+ gint next_redo;
+
+ gint actions_in_current_group;
+
+ gint running_not_undoable_actions;
+
+ gint num_of_groups;
+
+ gint max_undo_levels;
+
+ guint can_undo : 1;
+ guint can_redo : 1;
+
+ /* It is TRUE whether, while undoing an action of the current group (with order_in_group > 1),
+ * the state of the buffer changed from "not modified" to "modified".
+ */
+ guint modified_undoing_group : 1;
+
+ /* Pointer to the action (in the action list) marked as "modified".
+ * It is NULL when no action is marked as "modified".
+ * It is INVALID when the action marked as "modified" has been removed
+ * from the action list (freeing the list or resizing it) */
+ GtkSourceUndoAction *modified_action;
+};
+
+enum {
+ CAN_UNDO,
+ CAN_REDO,
+ LAST_SIGNAL
+};
+
+static void gtk_source_undo_manager_class_init(GtkSourceUndoManagerClass *klass);
+static void gtk_source_undo_manager_init(GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_finalize(GObject *object);
+
+static void gtk_source_undo_manager_insert_text_handler(GtkTextBuffer *buffer,
+ GtkTextIter *pos,
+ const gchar *text,
+ gint length,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_delete_range_handler(GtkTextBuffer *buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_begin_user_action_handler(GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um);
+static void gtk_source_undo_manager_modified_changed_handler(GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um);
+
+static void gtk_source_undo_manager_free_action_list(GtkSourceUndoManager *um);
+
+static void gtk_source_undo_manager_add_action(GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action);
+static void gtk_source_undo_manager_free_first_n_actions(GtkSourceUndoManager *um,
+ gint n);
+static void gtk_source_undo_manager_check_list_size(GtkSourceUndoManager *um);
+
+static gboolean gtk_source_undo_manager_merge_action(GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action);
+
+static GObjectClass *parent_class = NULL;
+static guint undo_manager_signals [LAST_SIGNAL] = { 0 };
+
+GType
+gtk_source_undo_manager_get_type(void) {
+ static GType undo_manager_type = 0;
+
+ if(undo_manager_type == 0)
+ {
+ static const GTypeInfo our_info =
+ {
+ sizeof(GtkSourceUndoManagerClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gtk_source_undo_manager_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof(GtkSourceUndoManager),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gtk_source_undo_manager_init,
+ NULL /* value_table */
+ };
+
+ undo_manager_type = g_type_register_static(G_TYPE_OBJECT,
+ "GtkSourceUndoManager",
+ &our_info,
+ 0);
+ }
+
+ return undo_manager_type;
+}
+
+static void
+gtk_source_undo_manager_class_init(GtkSourceUndoManagerClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ object_class->finalize = gtk_source_undo_manager_finalize;
+
+ klass->can_undo = NULL;
+ klass->can_redo = NULL;
+
+ undo_manager_signals[CAN_UNDO] =
+ g_signal_new("can_undo",
+ G_OBJECT_CLASS_TYPE(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GtkSourceUndoManagerClass, can_undo),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ undo_manager_signals[CAN_REDO] =
+ g_signal_new("can_redo",
+ G_OBJECT_CLASS_TYPE(object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GtkSourceUndoManagerClass, can_redo),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+}
+
+static void
+gtk_source_undo_manager_init(GtkSourceUndoManager *um) {
+ um->priv = g_new0(GtkSourceUndoManagerPrivate, 1);
+
+ um->priv->actions = NULL;
+ um->priv->next_redo = 0;
+
+ um->priv->can_undo = FALSE;
+ um->priv->can_redo = FALSE;
+
+ um->priv->running_not_undoable_actions = 0;
+
+ um->priv->num_of_groups = 0;
+
+ um->priv->max_undo_levels = DEFAULT_MAX_UNDO_LEVELS;
+
+ um->priv->modified_action = NULL;
+
+ um->priv->modified_undoing_group = FALSE;
+}
+
+static void
+gtk_source_undo_manager_finalize(GObject *object) {
+ GtkSourceUndoManager *um;
+
+ g_return_if_fail(object != NULL);
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(object));
+
+ um = GTK_SOURCE_UNDO_MANAGER(object);
+
+ g_return_if_fail(um->priv != NULL);
+
+ if(um->priv->actions != NULL)
+ gtk_source_undo_manager_free_action_list(um);
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
+ G_CALLBACK(gtk_source_undo_manager_delete_range_handler),
+ um);
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
+ G_CALLBACK(gtk_source_undo_manager_insert_text_handler),
+ um);
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
+ G_CALLBACK(gtk_source_undo_manager_begin_user_action_handler),
+ um);
+
+ g_signal_handlers_disconnect_by_func(G_OBJECT(um->priv->document),
+ G_CALLBACK(gtk_source_undo_manager_modified_changed_handler),
+ um);
+
+ g_free(um->priv);
+
+ G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+GtkSourceUndoManager*
+gtk_source_undo_manager_new(GtkTextBuffer* buffer) {
+ GtkSourceUndoManager *um;
+
+ um = GTK_SOURCE_UNDO_MANAGER(g_object_new(GTK_SOURCE_TYPE_UNDO_MANAGER, NULL));
+
+ g_return_val_if_fail(um->priv != NULL, NULL);
+ um->priv->document = buffer;
+
+ g_signal_connect(G_OBJECT(buffer), "insert_text",
+ G_CALLBACK(gtk_source_undo_manager_insert_text_handler),
+ um);
+
+ g_signal_connect(G_OBJECT(buffer), "delete_range",
+ G_CALLBACK(gtk_source_undo_manager_delete_range_handler),
+ um);
+
+ g_signal_connect(G_OBJECT(buffer), "begin_user_action",
+ G_CALLBACK(gtk_source_undo_manager_begin_user_action_handler),
+ um);
+
+ g_signal_connect(G_OBJECT(buffer), "modified_changed",
+ G_CALLBACK(gtk_source_undo_manager_modified_changed_handler),
+ um);
+ return um;
+}
+
+void
+gtk_source_undo_manager_begin_not_undoable_action(GtkSourceUndoManager *um) {
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ ++um->priv->running_not_undoable_actions;
+}
+
+static void
+gtk_source_undo_manager_end_not_undoable_action_internal(GtkSourceUndoManager *um) {
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ g_return_if_fail(um->priv->running_not_undoable_actions > 0);
+
+ --um->priv->running_not_undoable_actions;
+}
+
+void
+gtk_source_undo_manager_end_not_undoable_action(GtkSourceUndoManager *um) {
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ gtk_source_undo_manager_end_not_undoable_action_internal(um);
+
+ if(um->priv->running_not_undoable_actions == 0)
+ {
+ gtk_source_undo_manager_free_action_list(um);
+
+ um->priv->next_redo = -1;
+
+ if(um->priv->can_undo)
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit(G_OBJECT(um),
+ undo_manager_signals [CAN_UNDO],
+ 0,
+ FALSE);
+ }
+
+ if(um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit(G_OBJECT(um),
+ undo_manager_signals [CAN_REDO],
+ 0,
+ FALSE);
+ }
+ }
+}
+
+gboolean
+gtk_source_undo_manager_can_undo(const GtkSourceUndoManager *um) {
+ g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
+ g_return_val_if_fail(um->priv != NULL, FALSE);
+
+ return um->priv->can_undo;
+}
+
+gboolean
+gtk_source_undo_manager_can_redo(const GtkSourceUndoManager *um) {
+ g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
+ g_return_val_if_fail(um->priv != NULL, FALSE);
+
+ return um->priv->can_redo;
+}
+
+static void
+set_cursor(GtkTextBuffer *buffer, gint cursor) {
+ GtkTextIter iter;
+
+ /* Place the cursor at the requested position */
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, cursor);
+ gtk_text_buffer_place_cursor(buffer, &iter);
+}
+
+static void
+insert_text(GtkTextBuffer *buffer, gint pos, const gchar *text, gint len) {
+ GtkTextIter iter;
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
+ gtk_text_buffer_insert(buffer, &iter, text, len);
+}
+
+static void
+delete_text(GtkTextBuffer *buffer, gint start, gint end) {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
+
+ if(end < 0)
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ else
+ gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
+
+ gtk_text_buffer_delete(buffer, &start_iter, &end_iter);
+}
+
+static gchar*
+get_chars(GtkTextBuffer *buffer, gint start, gint end) {
+ GtkTextIter start_iter;
+ GtkTextIter end_iter;
+
+ gtk_text_buffer_get_iter_at_offset(buffer, &start_iter, start);
+
+ if(end < 0)
+ gtk_text_buffer_get_end_iter(buffer, &end_iter);
+ else
+ gtk_text_buffer_get_iter_at_offset(buffer, &end_iter, end);
+
+ return gtk_text_buffer_get_slice(buffer, &start_iter, &end_iter, TRUE);
+}
+
+void
+gtk_source_undo_manager_undo(GtkSourceUndoManager *um) {
+ GtkSourceUndoAction *undo_action;
+ gboolean modified = FALSE;
+
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+ g_return_if_fail(um->priv->can_undo);
+
+ um->priv->modified_undoing_group = FALSE;
+
+ gtk_source_undo_manager_begin_not_undoable_action(um);
+
+ do
+ {
+ undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo + 1);
+ g_return_if_fail(undo_action != NULL);
+
+ /* undo_action->modified can be TRUE only if undo_action->order_in_group <= 1 */
+ g_return_if_fail((undo_action->order_in_group <= 1) ||
+ ((undo_action->order_in_group > 1) && !undo_action->modified));
+
+ if(undo_action->order_in_group <= 1)
+ {
+ /* Set modified to TRUE only if the buffer did not change its state from
+ * "not modified" to "modified" undoing an action(with order_in_group > 1)
+ * in current group. */
+ modified =(undo_action->modified && !um->priv->modified_undoing_group);
+ }
+
+ switch(undo_action->action_type)
+ {
+ case GTK_SOURCE_UNDO_ACTION_DELETE:
+ insert_text(
+ um->priv->document,
+ undo_action->action.delete.start,
+ undo_action->action.delete.text,
+ strlen(undo_action->action.delete.text));
+
+ if(undo_action->action.delete.forward)
+ set_cursor(
+ um->priv->document,
+ undo_action->action.delete.start);
+ else
+ set_cursor(
+ um->priv->document,
+ undo_action->action.delete.end);
+
+ break;
+
+ case GTK_SOURCE_UNDO_ACTION_INSERT:
+ delete_text(
+ um->priv->document,
+ undo_action->action.insert.pos,
+ undo_action->action.insert.pos +
+ undo_action->action.insert.chars);
+
+ set_cursor(
+ um->priv->document,
+ undo_action->action.insert.pos);
+ break;
+
+ default:
+ /* Unknown action type. */
+ g_return_if_reached();
+ }
+
+ ++um->priv->next_redo;
+
+ } while(undo_action->order_in_group > 1);
+
+ if(modified)
+ {
+ --um->priv->next_redo;
+ gtk_text_buffer_set_modified(um->priv->document, FALSE);
+ ++um->priv->next_redo;
+ }
+
+ gtk_source_undo_manager_end_not_undoable_action_internal(um);
+
+ um->priv->modified_undoing_group = FALSE;
+
+ if(!um->priv->can_redo)
+ {
+ um->priv->can_redo = TRUE;
+ g_signal_emit(G_OBJECT(um),
+ undo_manager_signals [CAN_REDO],
+ 0,
+ TRUE);
+ }
+
+ if(um->priv->next_redo >=(gint)(g_list_length(um->priv->actions) - 1))
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit(G_OBJECT(um),
+ undo_manager_signals [CAN_UNDO],
+ 0,
+ FALSE);
+ }
+}
+
+void
+gtk_source_undo_manager_redo(GtkSourceUndoManager *um) {
+ GtkSourceUndoAction *undo_action;
+ gboolean modified = FALSE;
+
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+ g_return_if_fail(um->priv->can_redo);
+
+ undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo);
+ g_return_if_fail(undo_action != NULL);
+
+ gtk_source_undo_manager_begin_not_undoable_action(um);
+
+ do
+ {
+ if(undo_action->modified)
+ {
+ g_return_if_fail(undo_action->order_in_group <= 1);
+ modified = TRUE;
+ }
+
+ --um->priv->next_redo;
+
+ switch(undo_action->action_type)
+ {
+ case GTK_SOURCE_UNDO_ACTION_DELETE:
+ delete_text(
+ um->priv->document,
+ undo_action->action.delete.start,
+ undo_action->action.delete.end);
+
+ set_cursor(
+ um->priv->document,
+ undo_action->action.delete.start);
+
+ break;
+
+ case GTK_SOURCE_UNDO_ACTION_INSERT:
+ set_cursor(
+ um->priv->document,
+ undo_action->action.insert.pos);
+
+ insert_text(
+ um->priv->document,
+ undo_action->action.insert.pos,
+ undo_action->action.insert.text,
+ undo_action->action.insert.length);
+
+ break;
+
+ default:
+ /* Unknown action type */
+ ++um->priv->next_redo;
+ g_return_if_reached();
+ }
+
+ if(um->priv->next_redo < 0)
+ undo_action = NULL;
+ else
+ undo_action = g_list_nth_data(um->priv->actions, um->priv->next_redo);
+
+ } while((undo_action != NULL) &&(undo_action->order_in_group > 1));
+
+ if(modified)
+ {
+ ++um->priv->next_redo;
+ gtk_text_buffer_set_modified(um->priv->document, FALSE);
+ --um->priv->next_redo;
+ }
+
+ gtk_source_undo_manager_end_not_undoable_action_internal(um);
+
+ if(um->priv->next_redo < 0)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+
+ if(!um->priv->can_undo)
+ {
+ um->priv->can_undo = TRUE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, TRUE);
+ }
+}
+
+static void
+gtk_source_undo_action_free(GtkSourceUndoAction *action) {
+ if(action == NULL)
+ return;
+
+ if(action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ g_free(action->action.insert.text);
+ else if(action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ g_free(action->action.delete.text);
+ else
+ g_return_if_reached();
+
+ g_free(action);
+}
+
+static void
+gtk_source_undo_manager_free_action_list(GtkSourceUndoManager *um) {
+ GList *l;
+
+ l = um->priv->actions;
+
+ while(l != NULL)
+ {
+ GtkSourceUndoAction *action = l->data;
+
+ if(action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if(action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free(action);
+
+ l = g_list_next(l);
+ }
+
+ g_list_free(um->priv->actions);
+ um->priv->actions = NULL;
+}
+
+static void
+gtk_source_undo_manager_insert_text_handler(GtkTextBuffer *buffer,
+ GtkTextIter *pos,
+ const gchar *text,
+ gint length,
+ GtkSourceUndoManager *um) {
+ GtkSourceUndoAction undo_action;
+
+ if(um->priv->running_not_undoable_actions > 0)
+ return;
+
+ undo_action.action_type = GTK_SOURCE_UNDO_ACTION_INSERT;
+
+ undo_action.action.insert.pos = gtk_text_iter_get_offset(pos);
+ undo_action.action.insert.text =(gchar*) text;
+ undo_action.action.insert.length = length;
+ undo_action.action.insert.chars = g_utf8_strlen(text, length);
+
+ if((undo_action.action.insert.chars > 1) ||(g_utf8_get_char(text) == '\n'))
+
+ undo_action.mergeable = FALSE;
+ else
+ undo_action.mergeable = TRUE;
+
+ undo_action.modified = FALSE;
+
+ gtk_source_undo_manager_add_action(um, &undo_action);
+}
+
+static void
+gtk_source_undo_manager_delete_range_handler(GtkTextBuffer *buffer,
+ GtkTextIter *start,
+ GtkTextIter *end,
+ GtkSourceUndoManager *um) {
+ GtkSourceUndoAction undo_action;
+ GtkTextIter insert_iter;
+
+ if(um->priv->running_not_undoable_actions > 0)
+ return;
+
+ undo_action.action_type = GTK_SOURCE_UNDO_ACTION_DELETE;
+
+ gtk_text_iter_order(start, end);
+
+ undo_action.action.delete.start = gtk_text_iter_get_offset(start);
+ undo_action.action.delete.end = gtk_text_iter_get_offset(end);
+
+ undo_action.action.delete.text = get_chars(
+ buffer,
+ undo_action.action.delete.start,
+ undo_action.action.delete.end);
+
+ /* figure out if the user used the Delete or the Backspace key */
+ gtk_text_buffer_get_iter_at_mark(buffer, &insert_iter,
+ gtk_text_buffer_get_insert(buffer));
+ if(gtk_text_iter_get_offset(&insert_iter) <= undo_action.action.delete.start)
+ undo_action.action.delete.forward = TRUE;
+ else
+ undo_action.action.delete.forward = FALSE;
+
+ if(((undo_action.action.delete.end - undo_action.action.delete.start) > 1) ||
+ (g_utf8_get_char(undo_action.action.delete.text ) == '\n'))
+ undo_action.mergeable = FALSE;
+ else
+ undo_action.mergeable = TRUE;
+
+ undo_action.modified = FALSE;
+
+ gtk_source_undo_manager_add_action(um, &undo_action);
+
+ g_free(undo_action.action.delete.text);
+
+}
+
+static void
+gtk_source_undo_manager_begin_user_action_handler(GtkTextBuffer *buffer, GtkSourceUndoManager *um) {
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ if(um->priv->running_not_undoable_actions > 0)
+ return;
+
+ um->priv->actions_in_current_group = 0;
+}
+
+static void
+gtk_source_undo_manager_add_action(GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action) {
+ GtkSourceUndoAction* action;
+
+ if(um->priv->next_redo >= 0)
+ {
+ gtk_source_undo_manager_free_first_n_actions(um, um->priv->next_redo + 1);
+ }
+
+ um->priv->next_redo = -1;
+
+ if(!gtk_source_undo_manager_merge_action(um, undo_action))
+ {
+ action = g_new(GtkSourceUndoAction, 1);
+ *action = *undo_action;
+
+ if(action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ action->action.insert.text = g_strndup(undo_action->action.insert.text, undo_action->action.insert.length);
+ else if(action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ action->action.delete.text = g_strdup(undo_action->action.delete.text);
+ else
+ {
+ g_free(action);
+ g_return_if_reached();
+ }
+
+ ++um->priv->actions_in_current_group;
+ action->order_in_group = um->priv->actions_in_current_group;
+
+ if(action->order_in_group == 1)
+ ++um->priv->num_of_groups;
+
+ um->priv->actions = g_list_prepend(um->priv->actions, action);
+ }
+
+ gtk_source_undo_manager_check_list_size(um);
+
+ if(!um->priv->can_undo)
+ {
+ um->priv->can_undo = TRUE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, TRUE);
+ }
+
+ if(um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+}
+
+static void
+gtk_source_undo_manager_free_first_n_actions(GtkSourceUndoManager *um,
+ gint n) {
+ gint i;
+
+ if(um->priv->actions == NULL)
+ return;
+
+ for(i = 0; i < n; i++)
+ {
+ GtkSourceUndoAction *action = g_list_first(um->priv->actions)->data;
+
+ if(action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if(action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free(action);
+
+ um->priv->actions = g_list_delete_link(um->priv->actions,
+ um->priv->actions);
+
+ if(um->priv->actions == NULL)
+ return;
+ }
+}
+
+static void
+gtk_source_undo_manager_check_list_size(GtkSourceUndoManager *um) {
+ gint undo_levels;
+
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ undo_levels = gtk_source_undo_manager_get_max_undo_levels(um);
+
+ if(undo_levels < 1)
+ return;
+
+ if(um->priv->num_of_groups > undo_levels)
+ {
+ GtkSourceUndoAction *undo_action;
+ GList *last;
+
+ last = g_list_last(um->priv->actions);
+ undo_action =(GtkSourceUndoAction*) last->data;
+
+ do
+ {
+ GList *tmp;
+
+ if(undo_action->order_in_group == 1)
+ --um->priv->num_of_groups;
+
+ if(undo_action->modified)
+ um->priv->modified_action = INVALID;
+
+ gtk_source_undo_action_free(undo_action);
+
+ tmp = g_list_previous(last);
+ um->priv->actions = g_list_delete_link(um->priv->actions, last);
+ last = tmp;
+ g_return_if_fail(last != NULL);
+
+ undo_action =(GtkSourceUndoAction*) last->data;
+
+ } while((undo_action->order_in_group > 1) ||
+ (um->priv->num_of_groups > undo_levels));
+ }
+}
+
+/**
+ * gtk_source_undo_manager_merge_action:
+ * @um: a #GtkSourceUndoManager.
+ * @undo_action: a #GtkSourceUndoAction.
+ *
+ * This function tries to merge the undo action at the top of
+ * the stack with a new undo action. So when we undo for example
+ * typing, we can undo the whole word and not each letter by itself.
+ *
+ * Return Value: %TRUE is merge was successful, %FALSE otherwise.
+ **/
+static gboolean
+gtk_source_undo_manager_merge_action(GtkSourceUndoManager *um,
+ const GtkSourceUndoAction *undo_action) {
+ GtkSourceUndoAction *last_action;
+
+ g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), FALSE);
+ g_return_val_if_fail(um->priv != NULL, FALSE);
+
+ if(um->priv->actions == NULL)
+ return FALSE;
+
+ last_action =(GtkSourceUndoAction*) g_list_nth_data(um->priv->actions, 0);
+
+ if(!last_action->mergeable)
+ return FALSE;
+
+ if((!undo_action->mergeable) ||
+ (undo_action->action_type != last_action->action_type))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ if(undo_action->action_type == GTK_SOURCE_UNDO_ACTION_DELETE)
+ {
+ if((last_action->action.delete.forward != undo_action->action.delete.forward) ||
+ ((last_action->action.delete.start != undo_action->action.delete.start) &&
+ (last_action->action.delete.start != undo_action->action.delete.end)))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ if(last_action->action.delete.start == undo_action->action.delete.start)
+ {
+ gchar *str;
+
+#define L (last_action->action.delete.end - last_action->action.delete.start - 1)
+#define g_utf8_get_char_at(p,i) g_utf8_get_char(g_utf8_offset_to_pointer((p),(i)))
+
+ /* Deleted with the delete key */
+ if((g_utf8_get_char(undo_action->action.delete.text) != ' ') &&
+ (g_utf8_get_char(undo_action->action.delete.text) != '\t') &&
+ ((g_utf8_get_char_at(last_action->action.delete.text, L) == ' ') ||
+ (g_utf8_get_char_at(last_action->action.delete.text, L) == '\t')))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf("%s%s", last_action->action.delete.text,
+ undo_action->action.delete.text);
+
+ g_free(last_action->action.delete.text);
+ last_action->action.delete.end +=(undo_action->action.delete.end -
+ undo_action->action.delete.start);
+ last_action->action.delete.text = str;
+ }
+ else
+ {
+ gchar *str;
+
+ /* Deleted with the backspace key */
+ if((g_utf8_get_char(undo_action->action.delete.text) != ' ') &&
+ (g_utf8_get_char(undo_action->action.delete.text) != '\t') &&
+ ((g_utf8_get_char(last_action->action.delete.text) == ' ') ||
+ (g_utf8_get_char(last_action->action.delete.text) == '\t')))
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf("%s%s", undo_action->action.delete.text,
+ last_action->action.delete.text);
+
+ g_free(last_action->action.delete.text);
+ last_action->action.delete.start = undo_action->action.delete.start;
+ last_action->action.delete.text = str;
+ }
+ }
+ else if(undo_action->action_type == GTK_SOURCE_UNDO_ACTION_INSERT)
+ {
+ gchar* str;
+
+#define I (last_action->action.insert.chars - 1)
+
+ if((undo_action->action.insert.pos !=
+ (last_action->action.insert.pos + last_action->action.insert.chars)) ||
+ ((g_utf8_get_char(undo_action->action.insert.text) != ' ') &&
+ (g_utf8_get_char(undo_action->action.insert.text) != '\t') &&
+ ((g_utf8_get_char_at(last_action->action.insert.text, I) == ' ') ||
+ (g_utf8_get_char_at(last_action->action.insert.text, I) == '\t')))
+ )
+ {
+ last_action->mergeable = FALSE;
+ return FALSE;
+ }
+
+ str = g_strdup_printf("%s%s", last_action->action.insert.text,
+ undo_action->action.insert.text);
+
+ g_free(last_action->action.insert.text);
+ last_action->action.insert.length += undo_action->action.insert.length;
+ last_action->action.insert.text = str;
+ last_action->action.insert.chars += undo_action->action.insert.chars;
+
+ }
+ else
+ /* Unknown action inside undo merge encountered */
+ g_return_val_if_reached(TRUE);
+
+ return TRUE;
+}
+
+gint
+gtk_source_undo_manager_get_max_undo_levels(GtkSourceUndoManager *um) {
+ g_return_val_if_fail(um != NULL, 0);
+ g_return_val_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um), 0);
+
+ return um->priv->max_undo_levels;
+}
+
+void
+gtk_source_undo_manager_set_max_undo_levels(GtkSourceUndoManager *um,
+ gint max_undo_levels) {
+ gint old_levels;
+
+ g_return_if_fail(um != NULL);
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+
+ old_levels = um->priv->max_undo_levels;
+ um->priv->max_undo_levels = max_undo_levels;
+
+ if(max_undo_levels < 1)
+ return;
+
+ if(old_levels > max_undo_levels)
+ {
+ /* strip redo actions first */
+ while(um->priv->next_redo >= 0 &&(um->priv->num_of_groups > max_undo_levels))
+ {
+ gtk_source_undo_manager_free_first_n_actions(um, 1);
+ um->priv->next_redo--;
+ }
+
+ /* now remove undo actions if necessary */
+ gtk_source_undo_manager_check_list_size(um);
+
+ /* emit "can_undo" and/or "can_redo" if appropiate */
+ if(um->priv->next_redo < 0 && um->priv->can_redo)
+ {
+ um->priv->can_redo = FALSE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_REDO], 0, FALSE);
+ }
+
+ if(um->priv->can_undo &&
+ um->priv->next_redo >=(gint)(g_list_length(um->priv->actions) - 1))
+ {
+ um->priv->can_undo = FALSE;
+ g_signal_emit(G_OBJECT(um), undo_manager_signals [CAN_UNDO], 0, FALSE);
+ }
+ }
+}
+
+static void
+gtk_source_undo_manager_modified_changed_handler(GtkTextBuffer *buffer,
+ GtkSourceUndoManager *um) {
+ GtkSourceUndoAction *action;
+ GList *list;
+
+ g_return_if_fail(GTK_SOURCE_IS_UNDO_MANAGER(um));
+ g_return_if_fail(um->priv != NULL);
+
+ if(um->priv->actions == NULL)
+ return;
+
+ list = g_list_nth(um->priv->actions, um->priv->next_redo + 1);
+
+ if(list != NULL)
+ action =(GtkSourceUndoAction*) list->data;
+ else
+ action = NULL;
+
+ if(gtk_text_buffer_get_modified(buffer) == FALSE)
+ {
+ if(action != NULL)
+ action->mergeable = FALSE;
+
+ if(um->priv->modified_action != NULL)
+ {
+ if(um->priv->modified_action != INVALID)
+ um->priv->modified_action->modified = FALSE;
+
+ um->priv->modified_action = NULL;
+ }
+
+ return;
+ }
+
+ if(action == NULL)
+ {
+ g_return_if_fail(um->priv->running_not_undoable_actions > 0);
+
+ return;
+ }
+
+ /* gtk_text_buffer_get_modified(buffer) == TRUE */
+
+ g_return_if_fail(um->priv->modified_action == NULL);
+
+ if(action->order_in_group > 1)
+ um->priv->modified_undoing_group = TRUE;
+
+ while(action->order_in_group > 1)
+ {
+ list = g_list_next(list);
+ g_return_if_fail(list != NULL);
+
+ action =(GtkSourceUndoAction*) list->data;
+ g_return_if_fail(action != NULL);
+ }
+
+ action->modified = TRUE;
+ um->priv->modified_action = action;
+}
+
diff --git a/third_party/undoview/undo_manager.h b/third_party/undoview/undo_manager.h
new file mode 100644
index 0000000..9be582c
--- /dev/null
+++ b/third_party/undoview/undo_manager.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 1998, 1999 Alex Roberts, Evan Lawrence
+ * Copyright (C) 2000, 2001 Chema Celorio, Paolo Maggi
+ * Copyright (C) 2002, 2003 Paolo Maggi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_UNDO_MANAGER_H_
+#define CHROME_BROWSER_AUTOCOMPLETE_UNDO_MANAGER_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_UNDO_MANAGER (gtk_source_undo_manager_get_type())
+
+#define GTK_SOURCE_UNDO_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManager))
+
+#define GTK_SOURCE_UNDO_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
+
+#define GTK_SOURCE_IS_UNDO_MANAGER(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_SOURCE_TYPE_UNDO_MANAGER))
+
+#define GTK_SOURCE_IS_UNDO_MANAGER_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_SOURCE_TYPE_UNDO_MANAGER))
+
+#define GTK_SOURCE_UNDO_MANAGER_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_SOURCE_TYPE_UNDO_MANAGER, GtkSourceUndoManagerClass))
+
+typedef struct _GtkSourceUndoManager GtkSourceUndoManager;
+typedef struct _GtkSourceUndoManagerClass GtkSourceUndoManagerClass;
+
+typedef struct _GtkSourceUndoManagerPrivate GtkSourceUndoManagerPrivate;
+
+struct _GtkSourceUndoManager
+{
+ GObject base;
+
+ GtkSourceUndoManagerPrivate *priv;
+};
+
+struct _GtkSourceUndoManagerClass
+{
+ GObjectClass parent_class;
+
+ /* Signals */
+ void (*can_undo)(GtkSourceUndoManager *um, gboolean can_undo);
+ void (*can_redo)(GtkSourceUndoManager *um, gboolean can_redo);
+};
+
+GType gtk_source_undo_manager_get_type(void) G_GNUC_CONST;
+
+GtkSourceUndoManager* gtk_source_undo_manager_new(GtkTextBuffer *buffer);
+
+gboolean gtk_source_undo_manager_can_undo(const GtkSourceUndoManager *um);
+gboolean gtk_source_undo_manager_can_redo(const GtkSourceUndoManager *um);
+
+void gtk_source_undo_manager_undo(GtkSourceUndoManager *um);
+void gtk_source_undo_manager_redo(GtkSourceUndoManager *um);
+
+void gtk_source_undo_manager_begin_not_undoable_action(GtkSourceUndoManager *um);
+void gtk_source_undo_manager_end_not_undoable_action(GtkSourceUndoManager *um);
+
+gint gtk_source_undo_manager_get_max_undo_levels(GtkSourceUndoManager *um);
+void gtk_source_undo_manager_set_max_undo_levels(GtkSourceUndoManager *um,
+ gint undo_levels);
+
+G_END_DECLS
+
+#endif // CHROME_BROWSER_AUTOCOMPLETE_UNDO_MANAGER_H_
+
diff --git a/third_party/undoview/undo_view.c b/third_party/undoview/undo_view.c
new file mode 100644
index 0000000..03ea16a
--- /dev/null
+++ b/third_party/undoview/undo_view.c
@@ -0,0 +1,83 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Boilerplate code was generated by http://burtonini.com/cgi/gobject.py
+
+#include <gdk/gdkkeysyms.h>
+
+#include "undo_view.h"
+
+G_DEFINE_TYPE (GtkUndoView, gtk_undo_view, GTK_TYPE_TEXT_VIEW)
+
+static void
+gtk_undo_view_dispose(GObject *object) {
+ GtkUndoView *uview = GTK_UNDO_VIEW(object);
+
+ if(uview->undo_manager_) {
+ g_object_unref(G_OBJECT(uview->undo_manager_));
+ uview->undo_manager_ = NULL;
+ }
+ G_OBJECT_CLASS(gtk_undo_view_parent_class)->dispose(object);
+}
+
+static void
+gtk_undo_view_undo(GtkUndoView *uview) {
+ if(gtk_source_undo_manager_can_undo(uview->undo_manager_))
+ gtk_source_undo_manager_undo(uview->undo_manager_);
+}
+
+static void
+gtk_undo_view_redo(GtkUndoView *uview) {
+ if(gtk_source_undo_manager_can_redo(uview->undo_manager_))
+ gtk_source_undo_manager_redo(uview->undo_manager_);
+}
+
+static void
+gtk_undo_view_class_init(GtkUndoViewClass *klass) {
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GtkBindingSet *binding_set;
+
+ g_signal_new("undo",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(GtkUndoViewClass, undo),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ g_signal_new("redo",
+ G_TYPE_FROM_CLASS(klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(GtkUndoViewClass, redo),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ klass->undo = gtk_undo_view_undo;
+ klass->redo = gtk_undo_view_redo;
+
+ binding_set = gtk_binding_set_by_class(klass);
+ gtk_binding_entry_add_signal(binding_set, GDK_z, GDK_CONTROL_MASK, "undo", 0);
+ gtk_binding_entry_add_signal(binding_set, GDK_y, GDK_CONTROL_MASK, "redo", 0);
+ gtk_binding_entry_add_signal(binding_set, GDK_z, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "redo", 0);
+ gtk_binding_entry_add_signal(binding_set, GDK_F14, 0, "undo", 0);
+
+ object_class->dispose = gtk_undo_view_dispose;
+}
+
+static void
+gtk_undo_view_init(GtkUndoView *self) {
+}
+
+GtkWidget*
+gtk_undo_view_new(GtkTextBuffer *buffer) {
+ GtkWidget *ret = g_object_new(GTK_TYPE_UNDO_VIEW, "buffer", buffer, NULL);
+ GTK_UNDO_VIEW(ret)->undo_manager_ = gtk_source_undo_manager_new(GTK_TEXT_BUFFER(buffer));
+
+ return ret;
+}
+
diff --git a/third_party/undoview/undo_view.h b/third_party/undoview/undo_view.h
new file mode 100644
index 0000000..57ab570
--- /dev/null
+++ b/third_party/undoview/undo_view.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Boilerplate code was generated by http://burtonini.com/cgi/gobject.py
+
+#ifndef CHROME_BROWSER_AUTOCOMPLETE_UNDO_VIEW_H_
+#define CHROME_BROWSER_AUTOCOMPLETE_UNDO_VIEW_H_
+
+#include <gtk/gtk.h>
+#include "undo_manager.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_UNDO_VIEW gtk_undo_view_get_type()
+
+#define GTK_UNDO_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_UNDO_VIEW, GtkUndoView))
+
+#define GTK_UNDO_VIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_UNDO_VIEW, GtkUndoViewClass))
+
+#define GTK_IS_UNDO_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_UNDO_VIEW))
+
+#define GTK_IS_UNDO_VIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_UNDO_VIEW))
+
+#define GTK_UNDO_VIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_UNDO_VIEW, GtkUndoViewClass))
+
+typedef struct {
+ GtkTextView parent;
+ GtkSourceUndoManager *undo_manager_;
+} GtkUndoView;
+
+typedef struct {
+ GtkTextViewClass parent_class;
+
+ void (*undo)(GtkUndoView *);
+ void (*redo)(GtkUndoView *);
+} GtkUndoViewClass;
+
+GType gtk_undo_view_get_type(void);
+
+GtkWidget* gtk_undo_view_new(GtkTextBuffer *buffer);
+
+G_END_DECLS
+
+#endif // CHROME_BROWSER_AUTOCOMPLETE_UNDO_VIEW_H_
+
diff --git a/third_party/undoview/undoview.gyp b/third_party/undoview/undoview.gyp
new file mode 100644
index 0000000..430a321
--- /dev/null
+++ b/third_party/undoview/undoview.gyp
@@ -0,0 +1,22 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'undoview',
+ 'type': '<(library)',
+ 'sources': [
+ 'undo_manager.h',
+ 'undo_manager.c',
+ 'undo_view.h',
+ 'undo_view.c',
+ ],
+
+ 'dependencies' : [
+ '../../build/linux/system.gyp:gtk',
+ ],
+ },
+ ],
+}