summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2007-05-26 04:10:42 +0000
committerMatthias Clasen <matthiasc@src.gnome.org>2007-05-26 04:10:42 +0000
commit6ac30db004c4a768aaf74286bcc21ff7123e0550 (patch)
tree15e8284ee1ef0b2905bf2c0f2d1f6ce60eea9c91
parenta7f95266a51e905b0fea0cfe43809023038a7428 (diff)
downloadgtk+-6ac30db004c4a768aaf74286bcc21ff7123e0550.tar.gz
Allow to separate GtkTextMark creation from buffer insertion. (#132818,
2007-05-25 Matthias Clasen <mclasen@redhat.com> Allow to separate GtkTextMark creation from buffer insertion. (#132818, Gustavo Giráldez, patch by Yevgen Muntyan) * gtk/gtktextmarkprivate.h: * gtk/gtktextmark.[hc] (gtk_text_mark_new): New function to create a GtkTextMark. * gtk/gtktextbuffer.[hc] (gtk_text_buffer_add_mark): New function to add an existing mark to a buffer. * gtk/gtktextbtree.c: Allow adding existing marks. * gtk/gtk.symbols: Add new functions. * tests/testtextbuffer.c: Add some tests for new mark functionality. svn path=/trunk/; revision=17922
-rw-r--r--ChangeLog19
-rw-r--r--docs/reference/ChangeLog4
-rw-r--r--docs/reference/gtk/gtk-sections.txt2
-rw-r--r--gtk/gtk.symbols2
-rw-r--r--gtk/gtktextbtree.c20
-rw-r--r--gtk/gtktextbuffer.c50
-rw-r--r--gtk/gtktextbuffer.h3
-rw-r--r--gtk/gtktextmark.c170
-rw-r--r--gtk/gtktextmark.h2
-rw-r--r--gtk/gtktextmarkprivate.h5
-rw-r--r--tests/testtextbuffer.c75
11 files changed, 317 insertions, 35 deletions
diff --git a/ChangeLog b/ChangeLog
index 9aeb1335dc..ece998228f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2007-05-25 Matthias Clasen <mclasen@redhat.com>
+
+ Allow to separate GtkTextMark creation from buffer insertion.
+ (#132818, Gustavo Giráldez, patch by Yevgen Muntyan)
+
+ * gtk/gtktextmarkprivate.h:
+ * gtk/gtktextmark.[hc] (gtk_text_mark_new): New function to
+ create a GtkTextMark.
+
+ * gtk/gtktextbuffer.[hc] (gtk_text_buffer_add_mark): New
+ function to add an existing mark to a buffer.
+
+ * gtk/gtktextbtree.c: Allow adding existing marks.
+
+ * gtk/gtk.symbols: Add new functions.
+
+ * tests/testtextbuffer.c: Add some tests for new mark
+ functionality.
+
2007-05-25 Xan Lopez <xan@gnome.org>
* gtk/gtkaction.c: (gtk_action_set_short_label):
diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog
index cbec4c0164..8a94a29a6c 100644
--- a/docs/reference/ChangeLog
+++ b/docs/reference/ChangeLog
@@ -1,3 +1,7 @@
+2007-05-25 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtk-sections.txt: Add new functions
+
2007-05-24 Matthias Clasen <mclasen@redhat.com>
* === Released 2.11.0 ===
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 37fbeea6d3..f4059825b9 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -3411,6 +3411,7 @@ gtk_text_buffer_create_child_anchor
gtk_text_buffer_create_mark
gtk_text_buffer_move_mark
gtk_text_buffer_move_mark_by_name
+gtk_text_buffer_add_mark
gtk_text_buffer_delete_mark
gtk_text_buffer_delete_mark_by_name
gtk_text_buffer_get_mark
@@ -3597,6 +3598,7 @@ gtk_text_iter_get_type
<FILE>gtktextmark</FILE>
<TITLE>GtkTextMark</TITLE>
GtkTextMark
+gtk_text_mark_new
gtk_text_mark_set_visible
gtk_text_mark_get_visible
gtk_text_mark_get_deleted
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 9f7e02fe15..5b28f13185 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -3552,6 +3552,7 @@ gtk_text_buffer_backspace
gtk_text_buffer_begin_user_action
gtk_text_buffer_copy_clipboard
gtk_text_buffer_create_child_anchor
+gtk_text_buffer_add_mark
gtk_text_buffer_create_mark
gtk_text_buffer_create_tag
gtk_text_buffer_cut_clipboard
@@ -3789,6 +3790,7 @@ gtk_text_line_segment_split
#if IN_HEADER(__GTK_TEXT_MARK_H__)
#if IN_FILE(__GTK_TEXT_MARK_C__)
+gtk_text_mark_new
gtk_text_mark_get_buffer
gtk_text_mark_get_deleted
gtk_text_mark_get_left_gravity
diff --git a/gtk/gtktextbtree.c b/gtk/gtktextbtree.c
index 7601803371..93f6b4b3d9 100644
--- a/gtk/gtktextbtree.c
+++ b/gtk/gtktextbtree.c
@@ -2692,7 +2692,12 @@ real_set_mark (GtkTextBTree *tree,
g_return_val_if_fail (_gtk_text_iter_get_btree (where) == tree, NULL);
if (existing_mark)
- mark = existing_mark->segment;
+ {
+ if (gtk_text_mark_get_buffer (existing_mark) != NULL)
+ mark = existing_mark->segment;
+ else
+ mark = NULL;
+ }
else if (name != NULL)
mark = g_hash_table_lookup (tree->mark_table,
name);
@@ -2752,9 +2757,13 @@ real_set_mark (GtkTextBTree *tree,
}
else
{
- mark = _gtk_mark_segment_new (tree,
- left_gravity,
- name);
+ if (existing_mark)
+ g_object_ref (existing_mark);
+ else
+ existing_mark = gtk_text_mark_new (name, left_gravity);
+
+ mark = existing_mark->segment;
+ _gtk_mark_segment_set_tree (mark, tree);
mark->body.mark.line = _gtk_text_iter_get_text_line (&iter);
@@ -2980,7 +2989,8 @@ gtk_text_mark_set_visible (GtkTextMark *mark,
{
seg->body.mark.visible = setting;
- redisplay_mark (seg);
+ if (seg->body.mark.tree)
+ redisplay_mark (seg);
}
}
diff --git a/gtk/gtktextbuffer.c b/gtk/gtktextbuffer.c
index 20e34be08b..68364b60b1 100644
--- a/gtk/gtktextbuffer.c
+++ b/gtk/gtktextbuffer.c
@@ -2080,6 +2080,44 @@ gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
}
/**
+ * gtk_text_buffer_add_mark:
+ * @buffer: a #GtkTextBuffer
+ * @mark: the mark to add
+ * @where: location to place mark
+ *
+ * Adds the mark at position @where. The mark must not be added to
+ * another buffer, and if its name is not %NULL then there must not
+ * be another mark in the buffer with the same name.
+ *
+ * Emits the "mark_set" signal as notification of the mark's initial
+ * placement.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_text_buffer_add_mark (GtkTextBuffer *buffer,
+ GtkTextMark *mark,
+ const GtkTextIter *where)
+{
+ const gchar *name;
+
+ g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
+ g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+ g_return_if_fail (where != NULL);
+ g_return_if_fail (gtk_text_mark_get_buffer (mark) == NULL);
+
+ name = gtk_text_mark_get_name (mark);
+
+ if (name != NULL && gtk_text_buffer_get_mark (buffer, name) != NULL)
+ {
+ g_critical ("Mark %s already exists in the buffer", name);
+ return;
+ }
+
+ gtk_text_buffer_set_mark (buffer, mark, NULL, where, FALSE, FALSE);
+}
+
+/**
* gtk_text_buffer_move_mark:
* @buffer: a #GtkTextBuffer
* @mark: a #GtkTextMark
@@ -2129,13 +2167,13 @@ gtk_text_buffer_get_iter_at_mark (GtkTextBuffer *buffer,
*
* Deletes @mark, so that it's no longer located anywhere in the
* buffer. Removes the reference the buffer holds to the mark, so if
- * you haven't called g_object_ref () on the mark, it will be freed. Even
+ * you haven't called g_object_ref() on the mark, it will be freed. Even
* if the mark isn't freed, most operations on @mark become
- * invalid. There is no way to undelete a
- * mark. gtk_text_mark_get_deleted () will return TRUE after this
- * function has been called on a mark; gtk_text_mark_get_deleted ()
- * indicates that a mark no longer belongs to a buffer. The "mark_deleted"
- * signal will be emitted as notification after the mark is deleted.
+ * invalid, until it gets added to a buffer again with
+ * gtk_text_buffer_add_mark(). Use gtk_text_mark_get_deleted() to
+ * find out if a mark has been removed from its buffer.
+ * The "mark_deleted" signal will be emitted as notification after
+ * the mark is deleted.
**/
void
gtk_text_buffer_delete_mark (GtkTextBuffer *buffer,
diff --git a/gtk/gtktextbuffer.h b/gtk/gtktextbuffer.h
index 715b514acf..9a0eb9d28e 100644
--- a/gtk/gtktextbuffer.h
+++ b/gtk/gtktextbuffer.h
@@ -247,6 +247,9 @@ GtkTextChildAnchor *gtk_text_buffer_create_child_anchor (GtkTextBuffer *buffer,
GtkTextIter *iter);
/* Mark manipulation */
+void gtk_text_buffer_add_mark (GtkTextBuffer *buffer,
+ GtkTextMark *mark,
+ const GtkTextIter *where);
GtkTextMark *gtk_text_buffer_create_mark (GtkTextBuffer *buffer,
const gchar *mark_name,
const GtkTextIter *where,
diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c
index 281538e3f9..febec6b4b3 100644
--- a/gtk/gtktextmark.c
+++ b/gtk/gtktextmark.c
@@ -50,18 +50,29 @@
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
#include <config.h>
#include "gtktextbtree.h"
+#include "gtkprivate.h"
#include "gtkintl.h"
#include "gtkalias.h"
-static void gtk_text_mark_finalize (GObject *obj);
+static void gtk_text_mark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gtk_text_mark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void gtk_text_mark_finalize (GObject *object);
+
+static GtkTextLineSegment *gtk_mark_segment_new (GtkTextMark *mark_obj);
G_DEFINE_TYPE (GtkTextMark, gtk_text_mark, G_TYPE_OBJECT)
-static void
-gtk_text_mark_init (GtkTextMark *mark)
-{
- mark->segment = NULL;
-}
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_LEFT_GRAVITY
+};
static void
gtk_text_mark_class_init (GtkTextMarkClass *klass)
@@ -69,6 +80,30 @@ gtk_text_mark_class_init (GtkTextMarkClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_text_mark_finalize;
+ object_class->set_property = gtk_text_mark_set_property;
+ object_class->get_property = gtk_text_mark_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ P_("Name"),
+ P_("Mark name"),
+ NULL,
+ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (object_class,
+ PROP_LEFT_GRAVITY,
+ g_param_spec_boolean ("left-gravity",
+ P_("Left gravity"),
+ P_("Whether the mark has left gravity"),
+ FALSE,
+ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gtk_text_mark_init (GtkTextMark *mark)
+{
+ mark->segment = gtk_mark_segment_new (mark);
}
static void
@@ -98,6 +133,88 @@ gtk_text_mark_finalize (GObject *obj)
G_OBJECT_CLASS (gtk_text_mark_parent_class)->finalize (obj);
}
+static void
+gtk_text_mark_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ gchar *tmp;
+ GtkTextMark *mark = GTK_TEXT_MARK (object);
+ GtkTextLineSegment *seg = mark->segment;
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ tmp = seg->body.mark.name;
+ seg->body.mark.name = g_value_dup_string (value);
+ g_free (tmp);
+ break;
+
+ case PROP_LEFT_GRAVITY:
+ if (g_value_get_boolean (value))
+ seg->type = &gtk_text_left_mark_type;
+ else
+ seg->type = &gtk_text_right_mark_type;
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gtk_text_mark_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkTextMark *mark = GTK_TEXT_MARK (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, gtk_text_mark_get_name (mark));
+ break;
+
+ case PROP_LEFT_GRAVITY:
+ g_value_set_boolean (value, gtk_text_mark_get_left_gravity (mark));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+/**
+ * gtk_text_mark_new:
+ * @name: mark name or %NULL
+ * @left_gravity: whether the mark should have left gravity
+ *
+ * Creates a text mark. Add it to a buffer using gtk_text_buffer_add_mark().
+ * If @name is %NULL, the mark is anonymous; otherwise, the mark can be
+ * retrieved by name using gtk_text_buffer_get_mark(). If a mark has left
+ * gravity, and text is inserted at the mark's current location, the mark
+ * will be moved to the left of the newly-inserted text. If the mark has
+ * right gravity (@left_gravity = %FALSE), the mark will end up on the
+ * right of newly-inserted text. The standard left-to-right cursor is a
+ * mark with right gravity (when you type, the cursor stays on the right
+ * side of the text you're typing).
+ *
+ * Return value: new #GtkTextMark
+ *
+ * Since: 2.12
+ **/
+GtkTextMark *
+gtk_text_mark_new (const gchar *name,
+ gboolean left_gravity)
+{
+ return g_object_new (GTK_TYPE_TEXT_MARK,
+ "name", name,
+ "left-gravity", left_gravity,
+ NULL);
+}
+
/**
* gtk_text_mark_get_visible:
* @mark: a #GtkTextMark
@@ -140,8 +257,8 @@ gtk_text_mark_get_name (GtkTextMark *mark)
* @mark: a #GtkTextMark
*
* Returns %TRUE if the mark has been removed from its buffer
- * with gtk_text_buffer_delete_mark(). Marks can't be used
- * once deleted.
+ * with gtk_text_buffer_delete_mark(). See gtk_text_buffer_add_mark()
+ * for a way to add it to a buffer again.
*
* Return value: whether the mark is deleted
**/
@@ -212,28 +329,22 @@ gtk_text_mark_get_left_gravity (GtkTextMark *mark)
+ sizeof (GtkTextMarkBody)))
-GtkTextLineSegment*
-_gtk_mark_segment_new (GtkTextBTree *tree,
- gboolean left_gravity,
- const gchar *name)
+static GtkTextLineSegment *
+gtk_mark_segment_new (GtkTextMark *mark_obj)
{
GtkTextLineSegment *mark;
mark = (GtkTextLineSegment *) g_malloc0 (MSEG_SIZE);
- mark->body.mark.name = g_strdup (name);
-
- if (left_gravity)
- mark->type = &gtk_text_left_mark_type;
- else
- mark->type = &gtk_text_right_mark_type;
+ mark->body.mark.name = NULL;
+ mark->type = &gtk_text_right_mark_type;
mark->byte_count = 0;
mark->char_count = 0;
- mark->body.mark.obj = g_object_new (GTK_TYPE_TEXT_MARK, NULL);
- mark->body.mark.obj->segment = mark;
+ mark->body.mark.obj = mark_obj;
+ mark_obj->segment = mark;
- mark->body.mark.tree = tree;
+ mark->body.mark.tree = NULL;
mark->body.mark.line = NULL;
mark->next = NULL;
@@ -243,6 +354,23 @@ _gtk_mark_segment_new (GtkTextBTree *tree,
return mark;
}
+void
+_gtk_mark_segment_set_tree (GtkTextLineSegment *mark,
+ GtkTextBTree *tree)
+{
+ g_assert (mark->body.mark.tree == NULL);
+ g_assert (mark->body.mark.obj != NULL);
+
+ mark->byte_count = 0;
+ mark->char_count = 0;
+
+ mark->body.mark.tree = tree;
+ mark->body.mark.line = NULL;
+ mark->next = NULL;
+
+ mark->body.mark.not_deleteable = FALSE;
+}
+
static int mark_segment_delete_func (GtkTextLineSegment *segPtr,
GtkTextLine *line,
int treeGone);
diff --git a/gtk/gtktextmark.h b/gtk/gtktextmark.h
index 851123c4ac..41bcb9492f 100644
--- a/gtk/gtktextmark.h
+++ b/gtk/gtktextmark.h
@@ -88,6 +88,8 @@ void gtk_text_mark_set_visible (GtkTextMark *mark,
gboolean setting);
gboolean gtk_text_mark_get_visible (GtkTextMark *mark);
+GtkTextMark *gtk_text_mark_new (const gchar *name,
+ gboolean left_gravity);
G_CONST_RETURN gchar* gtk_text_mark_get_name (GtkTextMark *mark);
gboolean gtk_text_mark_get_deleted (GtkTextMark *mark);
GtkTextBuffer* gtk_text_mark_get_buffer (GtkTextMark *mark);
diff --git a/gtk/gtktextmarkprivate.h b/gtk/gtktextmarkprivate.h
index 43e9797366..d2ff381371 100644
--- a/gtk/gtktextmarkprivate.h
+++ b/gtk/gtktextmarkprivate.h
@@ -49,9 +49,8 @@ struct _GtkTextMarkBody {
guint not_deleteable : 1;
};
-GtkTextLineSegment *_gtk_mark_segment_new (GtkTextBTree *tree,
- gboolean left_gravity,
- const gchar *name);
+void _gtk_mark_segment_set_tree (GtkTextLineSegment *mark,
+ GtkTextBTree *tree);
G_END_DECLS
diff --git a/tests/testtextbuffer.c b/tests/testtextbuffer.c
index b739deadcc..eaae8b7352 100644
--- a/tests/testtextbuffer.c
+++ b/tests/testtextbuffer.c
@@ -48,6 +48,8 @@ static void line_separator_tests (void);
static void logical_motion_tests (void);
+static void mark_tests (void);
+
int
main (int argc, char** argv)
{
@@ -75,6 +77,9 @@ main (int argc, char** argv)
/* Create a buffer */
buffer = gtk_text_buffer_new (NULL);
+ /* Marks */
+ mark_tests ();
+
/* Check that buffer starts with one empty line and zero chars */
n = gtk_text_buffer_get_line_count (buffer);
@@ -1210,3 +1215,73 @@ logical_motion_tests (void)
g_object_unref (buffer);
}
+
+static void
+mark_tests (void)
+{
+ GtkTextBuffer *buf1, *buf2;
+ GtkTextMark *mark;
+ GtkTextIter iter;
+
+ buf1 = gtk_text_buffer_new (NULL);
+ buf2 = gtk_text_buffer_new (NULL);
+
+ gtk_text_buffer_get_start_iter (buf1, &iter);
+ mark = gtk_text_buffer_create_mark (buf1, "foo", &iter, TRUE);
+ g_object_ref (mark);
+ gtk_text_mark_set_visible (mark, TRUE);
+ gtk_text_buffer_delete_mark (buf1, mark);
+
+ g_assert (gtk_text_mark_get_visible (mark));
+ g_assert (gtk_text_mark_get_left_gravity (mark));
+ g_assert (!strcmp ("foo", gtk_text_mark_get_name (mark)));
+ g_assert (gtk_text_mark_get_buffer (mark) == NULL);
+ g_assert (gtk_text_mark_get_deleted (mark));
+ g_assert (gtk_text_buffer_get_mark (buf1, "foo") == NULL);
+
+ gtk_text_buffer_get_start_iter (buf2, &iter);
+ gtk_text_buffer_add_mark (buf2, mark, &iter);
+ gtk_text_buffer_insert (buf2, &iter, "ewfwefwefwe", -1);
+ gtk_text_buffer_get_iter_at_mark (buf2, &iter, mark);
+
+ g_assert (gtk_text_mark_get_visible (mark));
+ g_assert (gtk_text_iter_is_start (&iter));
+ g_assert (gtk_text_mark_get_left_gravity (mark));
+ g_assert (!strcmp ("foo", gtk_text_mark_get_name (mark)));
+ g_assert (gtk_text_mark_get_buffer (mark) == buf2);
+ g_assert (!gtk_text_mark_get_deleted (mark));
+ g_assert (gtk_text_buffer_get_mark (buf2, "foo") == mark);
+
+ gtk_text_buffer_delete_mark (buf2, mark);
+ gtk_text_mark_set_visible (mark, FALSE);
+ g_object_unref (mark);
+
+ mark = gtk_text_mark_new ("blah", TRUE);
+ gtk_text_buffer_get_start_iter (buf1, &iter);
+ gtk_text_mark_set_visible (mark, TRUE);
+ gtk_text_buffer_add_mark (buf1, mark, &iter);
+
+ g_assert (gtk_text_mark_get_visible (mark));
+ g_assert (gtk_text_mark_get_buffer (mark) == buf1);
+ g_assert (!gtk_text_mark_get_deleted (mark));
+ g_assert (gtk_text_buffer_get_mark (buf1, "blah") == mark);
+ g_assert (!strcmp ("blah", gtk_text_mark_get_name (mark)));
+
+ gtk_text_mark_set_visible (mark, FALSE);
+ gtk_text_buffer_delete_mark (buf1, mark);
+ g_assert (!gtk_text_mark_get_visible (mark));
+ g_assert (gtk_text_buffer_get_mark (buf1, "blah") == NULL);
+ g_assert (gtk_text_mark_get_buffer (mark) == NULL);
+ g_assert (gtk_text_mark_get_deleted (mark));
+
+ gtk_text_buffer_get_start_iter (buf2, &iter);
+ gtk_text_buffer_add_mark (buf2, mark, &iter);
+ g_assert (gtk_text_mark_get_buffer (mark) == buf2);
+ g_assert (!gtk_text_mark_get_deleted (mark));
+ g_assert (gtk_text_buffer_get_mark (buf2, "blah") == mark);
+ g_assert (!strcmp ("blah", gtk_text_mark_get_name (mark)));
+
+ g_object_unref (mark);
+ g_object_unref (buf1);
+ g_object_unref (buf2);
+}