[gtksourceview/wip/chergert/gsv-gtk4: 88/189] gutter: add GtkSourceGutterLines
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtksourceview/wip/chergert/gsv-gtk4: 88/189] gutter: add GtkSourceGutterLines
- Date: Mon, 22 Jun 2020 21:53:23 +0000 (UTC)
commit d576897fe7af8bc9733e8f0d95b1a797fd8c9f62
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 15 13:47:45 2020 -0800
gutter: add GtkSourceGutterLines
This new object provides an abstraction over tracking line information
while working with gutters. In particular, it can help avoid many costly
iterations over the text B-Tree.
docs/reference/meson.build | 1 +
gtksourceview/gtksource.h | 1 +
gtksourceview/gtksourcegutterlines-private.h | 38 ++
gtksourceview/gtksourcegutterlines.c | 657 +++++++++++++++++++++++++++
gtksourceview/gtksourcegutterlines.h | 96 ++++
gtksourceview/gtksourcetypes.h | 1 +
gtksourceview/meson.build | 2 +
gtksourceview/quarkset-inline.h | 185 ++++++++
8 files changed, 981 insertions(+)
---
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
index 26cd21b3..622a4de8 100644
--- a/docs/reference/meson.build
+++ b/docs/reference/meson.build
@@ -40,6 +40,7 @@ reference_private_h = [
'gtksourcestyleschememanager-private.h',
'gtksourcetypes-private.h',
'gtksourceutils-private.h',
+ 'quarkset-inline.h',
]
reference_content_files = files([
diff --git a/gtksourceview/gtksource.h b/gtksourceview/gtksource.h
index 2f795750..517c06ae 100644
--- a/gtksourceview/gtksource.h
+++ b/gtksourceview/gtksource.h
@@ -39,6 +39,7 @@
#include "gtksourceinit.h"
#include "gtksourcelanguage.h"
#include "gtksourcelanguagemanager.h"
+#include "gtksourcegutterlines.h"
#include "gtksourcemap.h"
#include "gtksourcemark.h"
#include "gtksourcemarkattributes.h"
diff --git a/gtksourceview/gtksourcegutterlines-private.h b/gtksourceview/gtksourcegutterlines-private.h
new file mode 100644
index 00000000..6852218d
--- /dev/null
+++ b/gtksourceview/gtksourcegutterlines-private.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- /
+ *
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2019 - Christian Hergert <chergert redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include "gtksourcegutterlines.h"
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL
+GtkSourceGutterLines *_gtk_source_gutter_lines_new (GtkTextView *text_view,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ gboolean needs_wrap_first,
+ gboolean needs_wrap_last);
+G_GNUC_INTERNAL
+guint _gtk_source_gutter_lines_get_cursor_line (GtkSourceGutterLines *lines);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourcegutterlines.c b/gtksourceview/gtksourcegutterlines.c
new file mode 100644
index 00000000..718bae2c
--- /dev/null
+++ b/gtksourceview/gtksourcegutterlines.c
@@ -0,0 +1,657 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- /
+ *
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2019 - Christian Hergert <chergert redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtksourcegutterlines.h"
+#include "gtksourcegutterlines-private.h"
+
+#include "quarkset-inline.h"
+
+/**
+ * SECTION:gutterlines
+ * @title: GtkSourceGutterLines
+ * @short_description: Collected information about visible lines
+ *
+ * The #GtkSourceGutterLines object is used to collect information about
+ * visible lines.
+ *
+ * Use this from your #GtkSourceGutterRenderer::query-data to collect the
+ * necessary information on visible lines. Doing so reduces the number of
+ * passes through the text btree allowing GtkSourceView to reach more
+ * frames-per-second while performing kinetic scrolling.
+ *
+ * Since: 5.0
+ */
+
+struct _GtkSourceGutterLines
+{
+ GObject parent_instance;
+ GtkTextView *view;
+ GArray *lines;
+ GdkRectangle visible_rect;
+ guint first;
+ guint last;
+ guint cursor_line;
+};
+
+typedef struct
+{
+ QuarkSet classes;
+ gint y;
+ gint height;
+ gint first_height;
+ gint last_height;
+} LineInfo;
+
+G_DEFINE_TYPE (GtkSourceGutterLines, gtk_source_gutter_lines, G_TYPE_OBJECT)
+
+static GQuark q_cursor_line;
+static GQuark q_prelit;
+static GQuark q_selected;
+
+static void
+gtk_source_gutter_lines_finalize (GObject *object)
+{
+ GtkSourceGutterLines *lines = (GtkSourceGutterLines *)object;
+
+ g_clear_pointer (&lines->lines, g_array_unref);
+ g_clear_object (&lines->view);
+
+ G_OBJECT_CLASS (gtk_source_gutter_lines_parent_class)->finalize (object);
+}
+
+static void
+gtk_source_gutter_lines_class_init (GtkSourceGutterLinesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gtk_source_gutter_lines_finalize;
+
+ q_cursor_line = g_quark_from_static_string ("cursor-line");
+ q_prelit = g_quark_from_static_string ("prelit");
+ q_selected = g_quark_from_static_string ("selected");
+}
+
+static void
+gtk_source_gutter_lines_init (GtkSourceGutterLines *self)
+{
+ self->cursor_line = -1;
+}
+
+static void
+clear_line_info (gpointer data)
+{
+ LineInfo *info = data;
+
+ info->y = 0;
+ info->height = 0;
+ quark_set_clear (&info->classes);
+}
+
+GtkSourceGutterLines *
+_gtk_source_gutter_lines_new (GtkTextView *text_view,
+ const GtkTextIter *begin,
+ const GtkTextIter *end,
+ gboolean needs_wrap_first,
+ gboolean needs_wrap_last)
+{
+ GtkSourceGutterLines *lines;
+ GtkTextBuffer *buffer;
+ GtkTextMark *mark;
+ GtkTextIter iter;
+ gboolean single_line;
+ guint cursor_line;
+ guint i;
+
+ g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
+ g_return_val_if_fail (begin != NULL, NULL);
+ g_return_val_if_fail (end != NULL, NULL);
+ g_return_val_if_fail (begin != end, NULL);
+
+ buffer = gtk_text_view_get_buffer (text_view);
+
+ g_return_val_if_fail (gtk_text_iter_get_buffer (begin) == buffer, NULL);
+ g_return_val_if_fail (gtk_text_iter_get_buffer (end) == buffer, NULL);
+
+ if (gtk_text_iter_compare (begin, end) > 0)
+ {
+ const GtkTextIter *tmp = begin;
+ begin = end;
+ end = tmp;
+ }
+
+ g_return_val_if_fail (begin != end, NULL);
+
+ lines = g_object_new (GTK_SOURCE_TYPE_GUTTER_LINES, NULL);
+ lines->view = g_object_ref (text_view);
+ lines->first = gtk_text_iter_get_line (begin);
+ lines->last = gtk_text_iter_get_line (end);
+ lines->lines = g_array_sized_new (FALSE,
+ FALSE,
+ sizeof (LineInfo),
+ lines->last - lines->first + 1);
+ g_array_set_clear_func (lines->lines, clear_line_info);
+ gtk_text_view_get_visible_rect (text_view, &lines->visible_rect);
+
+ /* No need to calculate special wrapping if wrap mode is none */
+ if (gtk_text_view_get_wrap_mode (text_view) == GTK_WRAP_NONE)
+ {
+ needs_wrap_first = FALSE;
+ needs_wrap_last = FALSE;
+ }
+
+ single_line = !needs_wrap_first && !needs_wrap_last;
+
+ /* Get the line number containing the cursor to compare while
+ * building the lines to add the "cursor-line" quark.
+ */
+ mark = gtk_text_buffer_get_insert (buffer);
+ gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
+ cursor_line = gtk_text_iter_get_line (&iter);
+
+ lines->cursor_line = cursor_line;
+
+ iter = *begin;
+
+ if (!gtk_text_iter_starts_line (&iter))
+ {
+ gtk_text_iter_set_line_offset (&iter, 0);
+ }
+
+ for (i = lines->first; i <= lines->last; i++)
+ {
+ LineInfo info = {0};
+
+ if G_LIKELY (single_line)
+ {
+ GdkRectangle rect;
+
+ gtk_text_view_get_iter_location (text_view, &iter, &rect);
+
+ info.y = rect.y;
+ info.height = rect.height;
+ info.first_height = rect.height;
+ info.last_height = rect.height;
+ }
+ else
+ {
+ gtk_text_view_get_line_yrange (text_view,
+ &iter,
+ &info.y,
+ &info.height);
+
+ if (gtk_text_iter_starts_line (&iter) &&
+ gtk_text_iter_ends_line (&iter))
+ {
+ info.first_height = info.height;
+ info.last_height = info.height;
+ }
+ else
+ {
+ GdkRectangle rect;
+
+ if (needs_wrap_first)
+ {
+
+ gtk_text_view_get_iter_location (text_view,
+ &iter,
+ &rect);
+ info.first_height = rect.height;
+ }
+ else
+ {
+ info.first_height = info.height;
+ }
+
+ if (needs_wrap_last)
+ {
+ gtk_text_iter_forward_to_line_end (&iter);
+ gtk_text_view_get_iter_location (text_view,
+ &iter,
+ &rect);
+ info.last_height = rect.height;
+ }
+ else
+ {
+ info.last_height = info.height;
+ }
+ }
+ }
+
+ if G_UNLIKELY (i == cursor_line)
+ {
+ quark_set_add (&info.classes, q_cursor_line);
+ }
+
+ g_array_append_val (lines->lines, info);
+
+ if G_UNLIKELY (!gtk_text_iter_forward_line (&iter) &&
+ !gtk_text_iter_is_end (&iter))
+ {
+ break;
+ }
+ }
+
+ g_return_val_if_fail (lines->lines->len > 0, NULL);
+ g_return_val_if_fail ((lines->last - lines->first) >= (lines->lines->len - 1), NULL);
+
+ return g_steal_pointer (&lines);
+}
+
+/**
+ * gtk_source_gutter_lines_add_qclass:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @qname: a class name as a #GQuark
+ *
+ * Adds the class denoted by @qname to @line.
+ *
+ * You may check if a line has @qname by calling
+ * gtk_source_gutter_lines_has_qclass().
+ *
+ * You can remove @qname by calling
+ * gtk_source_gutter_lines_remove_qclass().
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_add_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname)
+{
+ LineInfo *info;
+
+ g_return_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines));
+ g_return_if_fail (qname != 0);
+ g_return_if_fail (line >= lines->first);
+ g_return_if_fail (line <= lines->last);
+ g_return_if_fail (line - lines->first < lines->lines->len);
+
+ info = &g_array_index (lines->lines, LineInfo, line - lines->first);
+ quark_set_add (&info->classes, qname);
+}
+
+/**
+ * gtk_source_gutter_lines_add_class:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @name: a class name
+ *
+ * Adds the class @name to @line.
+ *
+ * @name will be converted to a #GQuark as part of this process. A
+ * faster version of this function is available via
+ * gtk_source_gutter_lines_add_qclass() for situations where the #GQuark is
+ * known ahead of time.
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_add_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name)
+{
+ g_return_if_fail (name != NULL);
+
+ gtk_source_gutter_lines_add_qclass (lines,
+ line,
+ g_quark_from_string (name));
+}
+
+/**
+ * gtk_source_gutter_lines_remove_class:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @name: a class name
+ *
+ * Removes the class matching @name from @line.
+ *
+ * A faster version of this function is available via
+ * gtk_source_gutter_lines_remove_qclass() for situations where the
+ * #GQuark is known ahead of time.
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_remove_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name)
+{
+ GQuark qname;
+
+ g_return_if_fail (name != NULL);
+
+ qname = g_quark_try_string (name);
+
+ if (qname != 0)
+ {
+ gtk_source_gutter_lines_remove_qclass (lines, line, qname);
+ }
+}
+
+/**
+ * gtk_source_gutter_lines_remove_qclass:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @qname: a #GQuark to remove from @line
+ *
+ * Reverses a call to gtk_source_gutter_lines_add_qclass() by removing
+ * the #GQuark matching @qname.
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_remove_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname)
+{
+ LineInfo *info;
+
+ g_return_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines));
+ g_return_if_fail (qname != 0);
+ g_return_if_fail (line >= lines->first);
+ g_return_if_fail (line <= lines->last);
+ g_return_if_fail (line - lines->first < lines->lines->len);
+
+ info = &g_array_index (lines->lines, LineInfo, line - lines->first);
+ quark_set_remove (&info->classes, qname);
+}
+
+/**
+ * gtk_source_gutter_lines_has_class:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @name: a class name that may be convered to a #GQuark
+ *
+ * Checks to see if gtk_source_gutter_lines_add_class() was called with
+ * the @name for @line.
+ *
+ * A faster version of this function is provided via
+ * gtk_source_gutter_lines_has_qclass() for situations where the quark
+ * is known ahead of time.
+ *
+ * Returns: %TRUE if @line contains @name
+ *
+ * Since: 5.0
+ */
+gboolean
+gtk_source_gutter_lines_has_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name)
+{
+ GQuark qname;
+
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ qname = g_quark_try_string (name);
+
+ if (qname == 0)
+ {
+ return FALSE;
+ }
+
+ return gtk_source_gutter_lines_has_qclass (lines, line, qname);
+}
+
+/**
+ * gtk_source_gutter_lines_has_qclass:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @qname: a #GQuark containing the class name
+ *
+ * Checks to see if gtk_source_gutter_lines_add_qclass() was called with
+ * the quark denoted by @qname for @line.
+ *
+ * Returns: %TRUE if @line contains @qname
+ *
+ * Since: 5.0
+ */
+gboolean
+gtk_source_gutter_lines_has_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname)
+{
+ LineInfo *info;
+
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), FALSE);
+ g_return_val_if_fail (qname != 0, FALSE);
+ g_return_val_if_fail (line >= lines->first, FALSE);
+ g_return_val_if_fail (line <= lines->last, FALSE);
+ g_return_val_if_fail (line - lines->first < lines->lines->len, FALSE);
+
+ info = &g_array_index (lines->lines, LineInfo, line - lines->first);
+
+ return quark_set_contains (&info->classes, qname);
+}
+
+/**
+ * gtk_source_gutter_lines_is_cursor:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ *
+ * Checks to see if @line contains the insertion cursor.
+ *
+ * Returns: %TRUE if the insertion cursor is on @line
+ *
+ * Since: 5.0
+ */
+gboolean
+gtk_source_gutter_lines_is_cursor (GtkSourceGutterLines *lines,
+ guint line)
+{
+ return gtk_source_gutter_lines_has_qclass (lines, line, q_cursor_line);
+}
+
+/**
+ * gtk_source_gutter_lines_is_prelit:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ *
+ * Checks to see if @line is marked as prelit. Generally, this means
+ * the mouse pointer is over the line within the gutter.
+ *
+ * Returns: %TRUE if the line is prelit
+ *
+ * Since: 5.0
+ */
+gboolean
+gtk_source_gutter_lines_is_prelit (GtkSourceGutterLines *lines,
+ guint line)
+{
+ return gtk_source_gutter_lines_has_qclass (lines, line, q_prelit);
+}
+
+/**
+ * gtk_source_gutter_lines_is_selected:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ *
+ * Checks to see if the view had a selection and if that selection overlaps
+ * @line in some way.
+ *
+ * Returns: %TRUE if the line contains a selection
+ *
+ * Since: 5.0
+ */
+gboolean
+gtk_source_gutter_lines_is_selected (GtkSourceGutterLines *lines,
+ guint line)
+{
+ return gtk_source_gutter_lines_has_qclass (lines, line, q_selected);
+}
+
+/**
+ * gtk_source_gutter_lines_get_first:
+ * @lines: a #GtkSourceGutterLines
+ *
+ * Gets the line number (starting from 0) for the first line that is
+ * user visible.
+ *
+ * Returns: a line number starting from 0
+ *
+ * Since: 5.0
+ */
+guint
+gtk_source_gutter_lines_get_first (GtkSourceGutterLines *lines)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), 0);
+
+ return lines->first;
+}
+
+/**
+ * gtk_source_gutter_lines_get_last:
+ * @lines: a #GtkSourceGutterLines
+ *
+ * Gets the line number (starting from 0) for the last line that is
+ * user visible.
+ *
+ * Returns: a line number starting from 0
+ *
+ * Since: 5.0
+ */
+guint
+gtk_source_gutter_lines_get_last (GtkSourceGutterLines *lines)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), 0);
+
+ return lines->last;
+}
+
+/**
+ * gtk_source_gutter_lines_get_iter_at_line:
+ * @lines: a #GtkSourceGutterLines
+ * @iter: (out): a location for a #GtkTextIter
+ * @line: the line number
+ *
+ * Gets a #GtkTextIter for the current buffer at @line
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_get_iter_at_line (GtkSourceGutterLines *lines,
+ GtkTextIter *iter,
+ guint line)
+{
+ GtkTextBuffer *buffer;
+
+ g_return_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines));
+ g_return_if_fail (iter != NULL);
+
+ buffer = gtk_text_view_get_buffer (lines->view);
+ gtk_text_buffer_get_iter_at_line (buffer, iter, line);
+}
+
+/**
+ * gtk_source_gutter_lines_get_view:
+ * @lines: a #GtkSourceGutterLines
+ *
+ * Gets the #GtkTextView that the #GtkSourceGutterLines represents.
+ *
+ * Returns: (transfer none) (not nullable): a #GtkTextView
+ *
+ * Since: 5.0
+ */
+GtkTextView *
+gtk_source_gutter_lines_get_view (GtkSourceGutterLines *lines)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), NULL);
+
+ return lines->view;
+}
+
+/**
+ * gtk_source_gutter_lines_get_buffer:
+ * @lines: a #GtkSourceGutterLines
+ *
+ * Gets the #GtkTextBuffer that the #GtkSourceGutterLines represents.
+ *
+ * Returns: (transfer none) (not nullable): a #GtkTextBuffer
+ *
+ * Since: 5.0
+ */
+GtkTextBuffer *
+gtk_source_gutter_lines_get_buffer (GtkSourceGutterLines *lines)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), NULL);
+
+ return gtk_text_view_get_buffer (lines->view);
+}
+
+/**
+ * gtk_source_gutter_lines_get_line_yrange:
+ * @lines: a #GtkSourceGutterLines
+ * @line: a line number starting from zero
+ * @mode: a #GtkSourceGutterRendererAlignmentMode
+ * @y: (out): a location for the Y position in widget coordinates
+ * @height: (out): the line height based on @mode
+ *
+ * Gets the Y range for a line based on @mode.
+ *
+ * The value for @y is relative to the renderers widget coordinates.
+ *
+ * Since: 5.0
+ */
+void
+gtk_source_gutter_lines_get_line_yrange (GtkSourceGutterLines *lines,
+ guint line,
+ GtkSourceGutterRendererAlignmentMode mode,
+ gint *y,
+ gint *height)
+{
+ LineInfo *info;
+
+ g_return_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines));
+ g_return_if_fail (line >= lines->first);
+ g_return_if_fail (line <= lines->last);
+
+ info = &g_array_index (lines->lines, LineInfo, line - lines->first);
+
+ if (mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_CELL)
+ {
+ *y = info->y;
+ *height = info->height;
+ }
+ else if (mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_FIRST)
+ {
+ *y = info->y;
+ *height = info->first_height;
+ }
+ else if (mode == GTK_SOURCE_GUTTER_RENDERER_ALIGNMENT_MODE_LAST)
+ {
+ *y = info->y + info->height - info->last_height;
+ *height = info->last_height;
+ }
+ else
+ {
+ g_return_if_reached ();
+ }
+
+ *y -= lines->visible_rect.y;
+}
+
+guint
+_gtk_source_gutter_lines_get_cursor_line (GtkSourceGutterLines *lines)
+{
+ g_return_val_if_fail (GTK_SOURCE_IS_GUTTER_LINES (lines), 0);
+
+ return lines->cursor_line;
+}
diff --git a/gtksourceview/gtksourcegutterlines.h b/gtksourceview/gtksourcegutterlines.h
new file mode 100644
index 00000000..173f27c1
--- /dev/null
+++ b/gtksourceview/gtksourcegutterlines.h
@@ -0,0 +1,96 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- /
+ *
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2019 - Christian Hergert <chergert redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#if !defined (GTK_SOURCE_H_INSIDE) && !defined (GTK_SOURCE_COMPILATION)
+#error "Only <gtksourceview/gtksource.h> can be included directly."
+#endif
+
+#include <gtk/gtk.h>
+
+#include "gtksourcetypes.h"
+#include "gtksourcegutterrenderer.h"
+
+G_BEGIN_DECLS
+
+#define GTK_SOURCE_TYPE_GUTTER_LINES (gtk_source_gutter_lines_get_type())
+
+GTK_SOURCE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (GtkSourceGutterLines, gtk_source_gutter_lines, GTK_SOURCE, GUTTER_LINES, GObject)
+
+GTK_SOURCE_AVAILABLE_IN_ALL
+guint gtk_source_gutter_lines_get_first (GtkSourceGutterLines *lines);
+GTK_SOURCE_AVAILABLE_IN_ALL
+guint gtk_source_gutter_lines_get_last (GtkSourceGutterLines *lines);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_get_iter_at_line (GtkSourceGutterLines *lines,
+ GtkTextIter *iter,
+ guint line);
+GTK_SOURCE_AVAILABLE_IN_ALL
+GtkTextView *gtk_source_gutter_lines_get_view (GtkSourceGutterLines *lines);
+GTK_SOURCE_AVAILABLE_IN_ALL
+GtkTextBuffer *gtk_source_gutter_lines_get_buffer (GtkSourceGutterLines *lines);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_get_yrange (GtkSourceGutterLines *lines,
+ guint line,
+ guint *line_y,
+ guint *line_height);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_add_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_add_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_remove_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_remove_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname);
+GTK_SOURCE_AVAILABLE_IN_ALL
+gboolean gtk_source_gutter_lines_has_class (GtkSourceGutterLines *lines,
+ guint line,
+ const gchar *name);
+GTK_SOURCE_AVAILABLE_IN_ALL
+gboolean gtk_source_gutter_lines_has_qclass (GtkSourceGutterLines *lines,
+ guint line,
+ GQuark qname);
+GTK_SOURCE_AVAILABLE_IN_ALL
+gboolean gtk_source_gutter_lines_is_cursor (GtkSourceGutterLines *lines,
+ guint line);
+GTK_SOURCE_AVAILABLE_IN_ALL
+gboolean gtk_source_gutter_lines_is_prelit (GtkSourceGutterLines *lines,
+ guint line);
+GTK_SOURCE_AVAILABLE_IN_ALL
+gboolean gtk_source_gutter_lines_is_selected (GtkSourceGutterLines *lines,
+ guint line);
+GTK_SOURCE_AVAILABLE_IN_ALL
+void gtk_source_gutter_lines_get_line_yrange (GtkSourceGutterLines *lines,
+ guint line,
+ GtkSourceGutterRendererAlignmentMode mode,
+ gint *y,
+ gint *height);
+
+G_END_DECLS
diff --git a/gtksourceview/gtksourcetypes.h b/gtksourceview/gtksourcetypes.h
index d6632d59..3ac09423 100644
--- a/gtksourceview/gtksourcetypes.h
+++ b/gtksourceview/gtksourcetypes.h
@@ -47,6 +47,7 @@ typedef struct _GtkSourceFile GtkSourceFile;
typedef struct _GtkSourceFileLoader GtkSourceFileLoader;
typedef struct _GtkSourceFileSaver GtkSourceFileSaver;
typedef struct _GtkSourceGutter GtkSourceGutter;
+typedef struct _GtkSourceGutterLines GtkSourceGutterLines;
typedef struct _GtkSourceGutterRenderer GtkSourceGutterRenderer;
typedef struct _GtkSourceGutterRendererPixbuf GtkSourceGutterRendererPixbuf;
typedef struct _GtkSourceGutterRendererText GtkSourceGutterRendererText;
diff --git a/gtksourceview/meson.build b/gtksourceview/meson.build
index 1d1fbbc6..2ead915e 100644
--- a/gtksourceview/meson.build
+++ b/gtksourceview/meson.build
@@ -25,6 +25,7 @@ core_public_h = files([
'gtksourceinit.h',
'gtksourcelanguage.h',
'gtksourcelanguagemanager.h',
+ 'gtksourcegutterlines.h',
'gtksourcemap.h',
'gtksourcemark.h',
'gtksourcemarkattributes.h',
@@ -64,6 +65,7 @@ core_public_c = files([
'gtksourceinit.c',
'gtksourcelanguage.c',
'gtksourcelanguagemanager.c',
+ 'gtksourcegutterlines.c',
'gtksourcemap.c',
'gtksourcemark.c',
'gtksourcemarkattributes.c',
diff --git a/gtksourceview/quarkset-inline.h b/gtksourceview/quarkset-inline.h
new file mode 100644
index 00000000..c744c0a2
--- /dev/null
+++ b/gtksourceview/quarkset-inline.h
@@ -0,0 +1,185 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*- */
+/*
+ * This file is part of GtkSourceView
+ *
+ * Copyright 2019 Christian Hergert <chergert redhat com>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _QuarkSet
+{
+ gint32 len;
+ union {
+ GQuark embed[2];
+ GQuark *alloc;
+ } u;
+} QuarkSet;
+
+static inline gboolean
+quark_set_is_embed (QuarkSet *set)
+{
+ return set->len >= 0;
+}
+
+static inline void
+quark_set_clear (QuarkSet *set)
+{
+ if (set->len < 0)
+ {
+ g_free (set->u.alloc);
+ }
+
+ set->len = 0;
+ set->u.alloc = NULL;
+}
+
+static inline gboolean
+quark_set_contains (QuarkSet *set,
+ GQuark quark)
+{
+ GQuark *quarks;
+ guint i;
+ guint len;
+
+ if (set->len == 0)
+ {
+ return FALSE;
+ }
+
+ if (quark_set_is_embed (set))
+ {
+ quarks = set->u.embed;
+ len = set->len;
+ }
+ else
+ {
+ quarks = set->u.alloc;
+ len = ABS (set->len);
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ if (quarks[i] == quark)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static inline void
+quark_set_add (QuarkSet *set,
+ GQuark quark)
+{
+ if (quark_set_contains (set, quark))
+ {
+ return;
+ }
+
+ if G_LIKELY (set->len == 0 || set->len == 1)
+ {
+ G_STATIC_ASSERT (G_N_ELEMENTS (set->u.embed) == 2);
+
+ set->u.embed[set->len++] = quark;
+ }
+ else if (set->len == G_N_ELEMENTS (set->u.embed))
+ {
+ GQuark *alloc = g_new (GQuark, set->len + 1);
+ guint i;
+
+ for (i = 0; i < set->len; i++)
+ {
+ alloc[i] = set->u.embed[i];
+ }
+
+ alloc[set->len] = quark;
+ set->len = -(set->len + 1);
+ set->u.alloc = alloc;
+ }
+ else if (set->len < 0)
+ {
+ guint len = ABS (set->len);
+
+ set->u.alloc = g_realloc_n (set->u.alloc, len + 1, sizeof (GQuark));
+ set->u.alloc[len] = quark;
+ set->len--; /* = -(len + 1) */
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+}
+
+static inline void
+quark_set_remove (QuarkSet *set,
+ GQuark quark)
+{
+ if (set->len == 0)
+ {
+ return;
+ }
+ else if (set->len == -1 && set->u.alloc[0] == quark)
+ {
+ quark_set_clear (set);
+ return;
+ }
+ else if (set->len > 0)
+ {
+ G_STATIC_ASSERT (G_N_ELEMENTS (set->u.embed) == 2);
+
+ if (set->u.embed[0] == quark)
+ {
+ set->u.embed[0] = set->u.embed[1];
+ set->len--;
+ }
+ else if (set->u.embed[1] == quark)
+ {
+ set->len--;
+ }
+ }
+ else if (set->len < 0)
+ {
+ guint len = ABS (set->len);
+ guint i;
+
+ for (i = 0; i < len; i++)
+ {
+ if (set->u.alloc[i] == quark)
+ {
+ if (i + 1 < len)
+ {
+ set->u.alloc[i] = set->u.alloc[len - 1];
+ }
+
+ set->len++; /* = -(len - 1) */
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+}
+
+G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]