[gtksourceview/wip/marks-sequence] Implement private class GtkSourceMarksSequence



commit 45b34e31bebace3adb7a2843fae24d5b4e894d22
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Sun Sep 8 15:25:55 2013 +0200

    Implement private class GtkSourceMarksSequence

 docs/reference/Makefile.am             |    1 +
 gtksourceview/Makefile.am              |    2 +
 gtksourceview/gtksourcemarkssequence.c |  322 ++++++++++++++++++++++++++++++++
 gtksourceview/gtksourcemarkssequence.h |   76 ++++++++
 gtksourceview/gtksourcetypes-private.h |    1 +
 5 files changed, 402 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 8acf0b3..1987d7f 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -36,6 +36,7 @@ IGNORE_HFILES =                                       \
        gtksourcegutterrenderermarks.h          \
        gtksourcegutterrenderer-private.h       \
        gtksourcelanguage-private.h             \
+       gtksourcemarkssequence.h                \
        gtksourcepixbufhelper.h                 \
        gtksourceregex.h                        \
        gtksourcestyle-private.h                \
diff --git a/gtksourceview/Makefile.am b/gtksourceview/Makefile.am
index 735bfb6..e27d220 100644
--- a/gtksourceview/Makefile.am
+++ b/gtksourceview/Makefile.am
@@ -61,6 +61,7 @@ libgtksourceview_private_headers = \
        gtksourcegutterrenderermarks.h          \
        gtksourcegutterrenderer-private.h       \
        gtksourcelanguage-private.h             \
+       gtksourcemarkssequence.h                \
        gtksourcepixbufhelper.h                 \
        gtksourceregex.h                        \
        gtksourcestyle-private.h                \
@@ -79,6 +80,7 @@ libgtksourceview_private_c_files = \
        gtksourcegutterrenderermarks.c  \
        gtksourcelanguage-parser-1.c    \
        gtksourcelanguage-parser-2.c    \
+       gtksourcemarkssequence.c        \
        gtksourcepixbufhelper.c         \
        gtksourceregex.c                \
        gtksourceundomanager.c          \
diff --git a/gtksourceview/gtksourcemarkssequence.c b/gtksourceview/gtksourcemarkssequence.c
new file mode 100644
index 0000000..2046f85
--- /dev/null
+++ b/gtksourceview/gtksourcemarkssequence.c
@@ -0,0 +1,322 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcemarkssequence.c
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView 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.
+ *
+ * GtkSourceView 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "gtksourcemarkssequence.h"
+
+/* An object for storing GtkTextMarks. The text marks are sorted internally with
+ * a GSequence. Going to the previous or next text mark has a O(1) complexity.
+ * Finding a text mark in the neighborhood of a text iter has a O(log n)
+ * complexity, with 'n' the number of marks in the sequence.
+ *
+ * The GSequenceIter associated to a text mark is inserted into the text mark,
+ * with g_object_set_qdata(). So the text mark knows its position in the
+ * GSequence. This allows to use normal GtkTextMarks in the API, instead of
+ * using a subclass or a custom iter.
+ */
+
+enum
+{
+       PROP_0,
+       PROP_BUFFER,
+};
+
+struct _GtkSourceMarksSequencePrivate
+{
+       GtkTextBuffer *buffer;
+       GSequence *seq;
+
+       /* The quark used for storing the GSequenceIter into the text mark, with
+        * g_object_set_qdata().
+        */
+       GQuark quark;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtkSourceMarksSequence, _gtk_source_marks_sequence, G_TYPE_OBJECT)
+
+static void
+remove_qdata (GtkTextMark            *mark,
+             GtkSourceMarksSequence *seq)
+{
+       g_object_set_qdata (G_OBJECT (mark),
+                           seq->priv->quark,
+                           NULL);
+}
+
+static void
+free_sequence (GtkSourceMarksSequence *seq)
+{
+       if (seq->priv->seq != NULL)
+       {
+               g_sequence_foreach (seq->priv->seq,
+                                   (GFunc)remove_qdata,
+                                   seq);
+
+               g_sequence_free (seq->priv->seq);
+               seq->priv->seq = NULL;
+       }
+}
+
+static gint
+compare_marks (GtkTextMark *mark1,
+              GtkTextMark *mark2)
+{
+       GtkTextBuffer *buffer;
+       GtkTextIter iter1;
+       GtkTextIter iter2;
+
+       g_assert (GTK_IS_TEXT_MARK (mark1));
+       g_assert (GTK_IS_TEXT_MARK (mark2));
+
+       buffer = gtk_text_mark_get_buffer (mark1);
+
+       g_assert (buffer == gtk_text_mark_get_buffer (mark2));
+
+       gtk_text_buffer_get_iter_at_mark (buffer, &iter1, mark1);
+       gtk_text_buffer_get_iter_at_mark (buffer, &iter2, mark2);
+
+       return gtk_text_iter_compare (&iter1, &iter2);
+}
+
+static void
+mark_set_cb (GtkTextBuffer          *buffer,
+            GtkTextIter            *location,
+            GtkTextMark            *mark,
+            GtkSourceMarksSequence *seq)
+{
+       GSequenceIter *seq_iter;
+
+       seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+       if (seq_iter != NULL)
+       {
+               g_sequence_sort_changed (seq_iter,
+                                        (GCompareDataFunc)compare_marks,
+                                        NULL);
+       }
+}
+
+static void
+set_buffer (GtkSourceMarksSequence *seq,
+           GtkTextBuffer          *buffer)
+{
+       g_assert (seq->priv->buffer == NULL);
+
+       seq->priv->buffer = g_object_ref (buffer);
+
+       g_signal_connect_object (buffer,
+                                "mark-set",
+                                G_CALLBACK (mark_set_cb),
+                                seq,
+                                0);
+}
+
+static void
+_gtk_source_marks_sequence_dispose (GObject *object)
+{
+       GtkSourceMarksSequence *seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+       g_clear_object (&seq->priv->buffer);
+
+       free_sequence (seq);
+
+       G_OBJECT_CLASS (_gtk_source_marks_sequence_parent_class)->dispose (object);
+}
+
+static void
+_gtk_source_marks_sequence_get_property (GObject    *object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+       GtkSourceMarksSequence *seq;
+
+       g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (object));
+
+       seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+       switch (prop_id)
+       {
+               case PROP_BUFFER:
+                       g_value_set_object (value, seq->priv->buffer);
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+_gtk_source_marks_sequence_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+       GtkSourceMarksSequence *seq;
+
+       g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (object));
+
+       seq = GTK_SOURCE_MARKS_SEQUENCE (object);
+
+       switch (prop_id)
+       {
+               case PROP_BUFFER:
+                       set_buffer (seq, g_value_get_object (value));
+                       break;
+
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+                       break;
+       }
+}
+
+static void
+_gtk_source_marks_sequence_class_init (GtkSourceMarksSequenceClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->dispose = _gtk_source_marks_sequence_dispose;
+       object_class->get_property = _gtk_source_marks_sequence_get_property;
+       object_class->set_property = _gtk_source_marks_sequence_set_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_BUFFER,
+                                        g_param_spec_object ("buffer",
+                                                             "Buffer",
+                                                             "The text buffer",
+                                                             GTK_TYPE_TEXT_BUFFER,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+_gtk_source_marks_sequence_init (GtkSourceMarksSequence *seq)
+{
+       gchar *unique_str;
+
+       seq->priv = _gtk_source_marks_sequence_get_instance_private (seq);
+
+       seq->priv->seq = g_sequence_new ((GDestroyNotify)g_object_unref);
+
+       unique_str = g_strdup_printf ("gtk-source-marks-sequence-%p", seq);
+       seq->priv->quark = g_quark_from_string (unique_str);
+       g_free (unique_str);
+}
+
+GtkSourceMarksSequence *
+_gtk_source_marks_sequence_new (GtkTextBuffer *buffer)
+{
+       g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
+
+       return g_object_new (GTK_SOURCE_TYPE_MARKS_SEQUENCE,
+                            "buffer", buffer,
+                            NULL);
+}
+
+void
+_gtk_source_marks_sequence_add (GtkSourceMarksSequence *seq,
+                               GtkTextMark            *mark)
+{
+       GSequenceIter *seq_iter;
+
+       g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq));
+       g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+       g_return_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer);
+
+       seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+       if (seq_iter != NULL)
+       {
+               /* The mark is already added. */
+               return;
+       }
+
+       seq_iter = g_sequence_insert_sorted (seq->priv->seq,
+                                            mark,
+                                            (GCompareDataFunc)compare_marks,
+                                            NULL);
+
+       g_object_ref (mark);
+       g_object_set_qdata (G_OBJECT (mark),
+                           seq->priv->quark,
+                           seq_iter);
+}
+
+void
+_gtk_source_marks_sequence_remove (GtkSourceMarksSequence *seq,
+                                  GtkTextMark            *mark)
+{
+       GSequenceIter *seq_iter;
+
+       g_return_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq));
+       g_return_if_fail (GTK_IS_TEXT_MARK (mark));
+       g_return_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer);
+
+       seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+       if (seq_iter != NULL)
+       {
+               g_object_set_qdata (G_OBJECT (mark), seq->priv->quark, NULL);
+               g_sequence_remove (seq_iter);
+       }
+}
+
+GtkTextMark *
+_gtk_source_marks_sequence_next (GtkSourceMarksSequence *seq,
+                                GtkTextMark            *mark)
+{
+       GSequenceIter *seq_iter;
+
+       g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), NULL);
+       g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), NULL);
+       g_return_val_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer, NULL);
+
+       seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+       g_return_val_if_fail (seq_iter != NULL, NULL);
+
+       seq_iter = g_sequence_iter_next (seq_iter);
+
+       return g_sequence_iter_is_end (seq_iter) ? NULL : g_sequence_get (seq_iter);
+}
+
+GtkTextMark *
+_gtk_source_marks_sequence_prev (GtkSourceMarksSequence *seq,
+                                GtkTextMark            *mark)
+{
+       GSequenceIter *seq_iter;
+
+       g_return_val_if_fail (GTK_SOURCE_IS_MARKS_SEQUENCE (seq), NULL);
+       g_return_val_if_fail (GTK_IS_TEXT_MARK (mark), NULL);
+       g_return_val_if_fail (gtk_text_mark_get_buffer (mark) == seq->priv->buffer, NULL);
+
+       seq_iter = g_object_get_qdata (G_OBJECT (mark), seq->priv->quark);
+
+       g_return_val_if_fail (seq_iter != NULL, NULL);
+
+       if (g_sequence_iter_is_begin (seq_iter))
+       {
+               return NULL;
+       }
+
+       seq_iter = g_sequence_iter_prev (seq_iter);
+
+       return g_sequence_get (seq_iter);
+}
diff --git a/gtksourceview/gtksourcemarkssequence.h b/gtksourceview/gtksourcemarkssequence.h
new file mode 100644
index 0000000..5bed4b0
--- /dev/null
+++ b/gtksourceview/gtksourcemarkssequence.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/* gtksourcemarkssequence.h
+ * This file is part of GtkSourceView
+ *
+ * Copyright (C) 2013 - Sébastien Wilmet <swilmet gnome org>
+ *
+ * GtkSourceView 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.
+ *
+ * GtkSourceView 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __GTK_SOURCE_MARKS_SEQUENCE_H__
+#define __GTK_SOURCE_MARKS_SEQUENCE_H__
+
+#include <gtk/gtk.h>
+#include "gtksourcetypes-private.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_MARKS_SEQUENCE             (_gtk_source_marks_sequence_get_type ())
+#define GTK_SOURCE_MARKS_SEQUENCE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequence))
+#define GTK_SOURCE_MARKS_SEQUENCE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequenceClass))
+#define GTK_SOURCE_IS_MARKS_SEQUENCE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GTK_SOURCE_TYPE_MARKS_SEQUENCE))
+#define GTK_SOURCE_IS_MARKS_SEQUENCE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
GTK_SOURCE_TYPE_MARKS_SEQUENCE))
+#define GTK_SOURCE_MARKS_SEQUENCE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), 
GTK_SOURCE_TYPE_MARKS_SEQUENCE, GtkSourceMarksSequenceClass))
+
+typedef struct _GtkSourceMarksSequenceClass    GtkSourceMarksSequenceClass;
+typedef struct _GtkSourceMarksSequencePrivate  GtkSourceMarksSequencePrivate;
+
+struct _GtkSourceMarksSequence
+{
+       GObject parent;
+
+       GtkSourceMarksSequencePrivate *priv;
+};
+
+struct _GtkSourceMarksSequenceClass
+{
+       GObjectClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType                   _gtk_source_marks_sequence_get_type    (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GtkSourceMarksSequence *_gtk_source_marks_sequence_new         (GtkTextBuffer          *buffer);
+
+G_GNUC_INTERNAL
+void                    _gtk_source_marks_sequence_add         (GtkSourceMarksSequence *seq,
+                                                                GtkTextMark            *mark);
+
+G_GNUC_INTERNAL
+void                    _gtk_source_marks_sequence_remove      (GtkSourceMarksSequence *seq,
+                                                                GtkTextMark            *mark);
+
+G_GNUC_INTERNAL
+GtkTextMark            *_gtk_source_marks_sequence_next        (GtkSourceMarksSequence *seq,
+                                                                GtkTextMark            *mark);
+
+G_GNUC_INTERNAL
+GtkTextMark            *_gtk_source_marks_sequence_prev        (GtkSourceMarksSequence *seq,
+                                                                GtkTextMark            *mark);
+
+G_END_DECLS
+
+#endif /* __GTK_SOURCE_MARKS_SEQUENCE_H__ */
diff --git a/gtksourceview/gtksourcetypes-private.h b/gtksourceview/gtksourcetypes-private.h
index 6b88c2c..afb1c8a 100644
--- a/gtksourceview/gtksourcetypes-private.h
+++ b/gtksourceview/gtksourcetypes-private.h
@@ -32,6 +32,7 @@ typedef struct _GtkSourceContextEngine                GtkSourceContextEngine;
 typedef struct _GtkSourceEngine                        GtkSourceEngine;
 typedef struct _GtkSourceGutterRendererLines   GtkSourceGutterRendererLines;
 typedef struct _GtkSourceGutterRendererMarks   GtkSourceGutterRendererMarks;
+typedef struct _GtkSourceMarksSequence         GtkSourceMarksSequence;
 typedef struct _GtkSourcePixbufHelper          GtkSourcePixbufHelper;
 typedef struct _GtkSourceRegex                 GtkSourceRegex;
 typedef struct _GtkSourceUndoManagerDefault    GtkSourceUndoManagerDefault;


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