[gnome-builder/wip/libide] libide: start on IdeSourceView



commit 0f53ef28049f5ba3f65070376ea6cbfbc45e2b33
Author: Christian Hergert <christian hergert me>
Date:   Tue Feb 24 12:42:52 2015 -0800

    libide: start on IdeSourceView
    
    There is a lot to move down here, but getting it into libide will generally
    make things a lot nicer for scripting and consuming libide.
    
    Other todo's involve moving snippets down.
    
    Emacs/Vim mode are a tough choice. I haven't decided where that should
    go yet.
    
    Eventually, we should be able to make a very basic example using the
    test application included. Once that is done, things are a candidate to
    merge with Builder UI layers.

 .gitignore                   |    1 +
 libide/Makefile.am           |    6 +
 libide/ide-source-view.c     |  319 ++++++++++++++++++++++++++++++++++++++++++
 libide/ide-source-view.h     |   57 ++++++++
 libide/ide.h                 |    1 +
 libide/util/ide-pango.c      |  180 ++++++++++++++++++++++++
 libide/util/ide-pango.h      |   30 ++++
 tests/test-ide-source-view.c |  133 ++++++++++++++++++
 tests/tests.mk               |    8 +
 9 files changed, 735 insertions(+), 0 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index b708f21..ef399f0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,4 +42,5 @@ test-c-parse-helper
 test-ide-back-forward-list
 test-ide-buffer-manager
 test-ide-context
+test-ide-source-view
 test-navigation-list
diff --git a/libide/Makefile.am b/libide/Makefile.am
index e4f6aef..c0df5b2 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -46,6 +46,8 @@ libide_1_0_la_public_sources = \
        libide/ide-buffer-manager.h \
        libide/ide-buffer.c \
        libide/ide-buffer.h \
+       libide/ide-source-view.c \
+       libide/ide-source-view.h \
        libide/ide-build-result.c \
        libide/ide-build-result.h \
        libide/ide-build-system.c \
@@ -185,6 +187,8 @@ libide_1_0_la_SOURCES = \
        libide/ide-internal.h \
        libide/tasks/ide-load-directory-task.c \
        libide/tasks/ide-load-directory-task.h \
+       libide/util/ide-pango.c \
+       libide/util/ide-pango.h \
        $(NULL)
 
 libide_1_0_la_includes = \
@@ -204,6 +208,7 @@ libide_1_0_la_includes = \
        -I$(top_srcdir)/libide/pygobject \
        -I$(top_srcdir)/libide/python \
        -I$(top_srcdir)/libide/tasks \
+       -I$(top_srcdir)/libide/util \
        -I$(top_srcdir)/libide/xml \
        $(CLANG_CFLAGS) \
        $(NULL)
@@ -235,6 +240,7 @@ libide_1_0_la_LIBADD = \
        $(CLANG_LDFLAGS) \
        $(LIBIDE_LIBS) \
        -lclang \
+       -lm \
        libeditorconfig.la \
        $(NULL)
 
diff --git a/libide/ide-source-view.c b/libide/ide-source-view.c
new file mode 100644
index 0000000..e2f5ed5
--- /dev/null
+++ b/libide/ide-source-view.c
@@ -0,0 +1,319 @@
+/* ide-source-view.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-source-view"
+
+#include <glib/gi18n.h>
+
+#include "ide-buffer.h"
+#include "ide-file.h"
+#include "ide-file-settings.h"
+#include "ide-highlighter.h"
+#include "ide-indenter.h"
+#include "ide-language.h"
+#include "ide-pango.h"
+#include "ide-source-view.h"
+
+#define DEFAULT_FONT_DESC "Monospace 11"
+
+typedef struct
+{
+  IdeBuffer            *buffer;
+  GtkCssProvider       *css_provider;
+  PangoFontDescription *font_desc;
+} IdeSourceViewPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (IdeSourceView, ide_source_view, GTK_SOURCE_TYPE_VIEW)
+
+enum {
+  PROP_0,
+  PROP_FONT_NAME,
+  PROP_FONT_DESC,
+  LAST_PROP
+};
+
+static GParamSpec *gParamSpecs [LAST_PROP];
+
+static void
+ide_source_view__buffer_notify_file_cb (IdeSourceView *self,
+                                        GParamSpec    *pspec,
+                                        IdeBuffer     *buffer)
+{
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+}
+
+static void
+ide_source_view__buffer_notify_language_cb (IdeSourceView *self,
+                                            GParamSpec    *pspec,
+                                            IdeBuffer     *buffer)
+{
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+}
+
+static void
+ide_source_view__buffer_changed_cb (IdeSourceView *self,
+                                    IdeBuffer     *buffer)
+{
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+}
+
+static void
+ide_source_view_rebuild_css (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  if (!priv->css_provider)
+    {
+      GtkStyleContext *style_context;
+
+      priv->css_provider = gtk_css_provider_new ();
+      style_context = gtk_widget_get_style_context (GTK_WIDGET (self));
+      gtk_style_context_add_provider (style_context,
+                                      GTK_STYLE_PROVIDER (priv->css_provider),
+                                      GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+    }
+
+  if (priv->font_desc)
+    {
+      g_autofree gchar *str = NULL;
+      g_autofree gchar *css = NULL;
+
+      str = ide_pango_font_description_to_css (priv->font_desc);
+      css = g_strdup_printf ("IdeSourceView { %s }", str ?: "");
+      gtk_css_provider_load_from_data (priv->css_provider, css, -1, NULL);
+    }
+}
+
+static void
+ide_source_view_connect_buffer (IdeSourceView *self,
+                                IdeBuffer     *buffer)
+{
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  g_signal_connect_object (buffer,
+                           "changed",
+                           G_CALLBACK (ide_source_view__buffer_changed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (buffer,
+                           "notify::file",
+                           G_CALLBACK (ide_source_view__buffer_notify_file_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (buffer,
+                           "notify::language",
+                           G_CALLBACK (ide_source_view__buffer_notify_language_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+ide_source_view_disconnect_buffer (IdeSourceView *self,
+                                   IdeBuffer     *buffer)
+{
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+  g_assert (IDE_IS_BUFFER (buffer));
+
+  g_signal_handlers_disconnect_by_func (buffer,
+                                        G_CALLBACK (ide_source_view__buffer_notify_file_cb),
+                                        self);
+
+  g_signal_handlers_disconnect_by_func (buffer,
+                                        G_CALLBACK (ide_source_view__buffer_notify_language_cb),
+                                        self);
+}
+
+static void
+ide_source_view_notify_buffer (IdeSourceView *self,
+                               GParamSpec    *pspec,
+                               gpointer       user_data)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+  GtkTextBuffer *buffer;
+
+  g_assert (IDE_IS_SOURCE_VIEW (self));
+
+  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (self));
+
+  if (priv->buffer != (IdeBuffer *)buffer)
+    {
+      if (priv->buffer != NULL)
+        {
+          ide_source_view_disconnect_buffer (self, priv->buffer);
+          g_clear_object (&priv->buffer);
+        }
+
+      /*
+       * Only enable IdeSourceView features if this is an IdeBuffer.
+       * Ignore for GtkSourceBuffer, and GtkTextBuffer.
+       */
+      if (IDE_IS_BUFFER (buffer))
+        {
+          priv->buffer = g_object_ref (buffer);
+          ide_source_view_connect_buffer (self, priv->buffer);
+        }
+    }
+}
+
+static void
+ide_source_view_dispose (GObject *object)
+{
+  IdeSourceView *self = (IdeSourceView *)object;
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  if (priv->buffer)
+    {
+      ide_source_view_disconnect_buffer (self, priv->buffer);
+      g_clear_object (&priv->buffer);
+    }
+
+  g_clear_pointer (&priv->font_desc, pango_font_description_free);
+
+  G_OBJECT_CLASS (ide_source_view_parent_class)->dispose (object);
+}
+
+static void
+ide_source_view_get_property (GObject    *object,
+                              guint       prop_id,
+                              GValue     *value,
+                              GParamSpec *pspec)
+{
+  IdeSourceView *self = IDE_SOURCE_VIEW (object);
+
+  switch (prop_id)
+    {
+    case PROP_FONT_DESC:
+      g_value_set_boxed (value, ide_source_view_get_font_desc (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_source_view_set_property (GObject      *object,
+                              guint         prop_id,
+                              const GValue *value,
+                              GParamSpec   *pspec)
+{
+  IdeSourceView *self = IDE_SOURCE_VIEW (object);
+
+  switch (prop_id)
+    {
+    case PROP_FONT_NAME:
+      ide_source_view_set_font_name (self, g_value_get_string (value));
+      break;
+
+    case PROP_FONT_DESC:
+      ide_source_view_set_font_desc (self, g_value_get_boxed (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_source_view_class_init (IdeSourceViewClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_source_view_dispose;
+  object_class->get_property = ide_source_view_get_property;
+  object_class->set_property = ide_source_view_set_property;
+
+  gParamSpecs [PROP_FONT_DESC] =
+    g_param_spec_boxed ("font-desc",
+                        _("Font Description"),
+                        _("The Pango font description to use for rendering source."),
+                        PANGO_TYPE_FONT_DESCRIPTION,
+                        (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_FONT_DESC,
+                                   gParamSpecs [PROP_FONT_DESC]);
+
+  gParamSpecs [PROP_FONT_NAME] =
+    g_param_spec_string ("font-name",
+                         _("Font Name"),
+                         _("The pango font name ot use for rendering source."),
+                         "Monospace",
+                         (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (object_class, PROP_FONT_NAME,
+                                   gParamSpecs [PROP_FONT_NAME]);
+}
+
+static void
+ide_source_view_init (IdeSourceView *self)
+{
+  g_signal_connect (self, "notify::buffer", G_CALLBACK (ide_source_view_notify_buffer), NULL);
+}
+
+const PangoFontDescription *
+ide_source_view_get_font_desc (IdeSourceView *self)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_val_if_fail (IDE_IS_SOURCE_VIEW (self), NULL);
+
+  return priv->font_desc;
+}
+
+void
+ide_source_view_set_font_desc (IdeSourceView              *self,
+                               const PangoFontDescription *font_desc)
+{
+  IdeSourceViewPrivate *priv = ide_source_view_get_instance_private (self);
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  if (font_desc != priv->font_desc)
+    {
+      g_clear_pointer (&priv->font_desc, pango_font_description_free);
+
+      if (font_desc)
+        priv->font_desc = pango_font_description_copy (font_desc);
+      else
+        priv->font_desc = pango_font_description_from_string (DEFAULT_FONT_DESC);
+
+      ide_source_view_rebuild_css (self);
+    }
+}
+
+void
+ide_source_view_set_font_name (IdeSourceView *self,
+                               const gchar   *font_name)
+{
+  PangoFontDescription *font_desc = NULL;
+
+  g_return_if_fail (IDE_IS_SOURCE_VIEW (self));
+
+  if (font_name)
+    font_desc = pango_font_description_from_string (font_name);
+  ide_source_view_set_font_desc (self, font_desc);
+  if (font_desc)
+    pango_font_description_free (font_desc);
+}
diff --git a/libide/ide-source-view.h b/libide/ide-source-view.h
new file mode 100644
index 0000000..b726516
--- /dev/null
+++ b/libide/ide-source-view.h
@@ -0,0 +1,57 @@
+/* ide-source-view.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_SOURCE_VIEW_H
+#define IDE_SOURCE_VIEW_H
+
+#include <gtksourceview/gtksource.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_SOURCE_VIEW            (ide_source_view_get_type())
+#define IDE_SOURCE_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDE_TYPE_SOURCE_VIEW, 
IdeSourceView))
+#define IDE_SOURCE_VIEW_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), IDE_TYPE_SOURCE_VIEW, 
IdeSourceView const))
+#define IDE_SOURCE_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  IDE_TYPE_SOURCE_VIEW, 
IdeSourceViewClass))
+#define IDE_IS_SOURCE_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IDE_TYPE_SOURCE_VIEW))
+#define IDE_IS_SOURCE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  IDE_TYPE_SOURCE_VIEW))
+#define IDE_SOURCE_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  IDE_TYPE_SOURCE_VIEW, 
IdeSourceViewClass))
+
+typedef struct _IdeSourceView      IdeSourceView;
+typedef struct _IdeSourceViewClass IdeSourceViewClass;
+
+struct _IdeSourceView
+{
+  GtkSourceView parent;
+};
+
+struct _IdeSourceViewClass
+{
+  GtkSourceViewClass parent_class;
+};
+
+GType ide_source_view_get_type (void);
+
+void                        ide_source_view_set_font_name (IdeSourceView              *self,
+                                                           const gchar                *font_name);
+const PangoFontDescription *ide_source_view_get_font_desc (IdeSourceView              *self);
+void                        ide_source_view_set_font_desc (IdeSourceView              *self,
+                                                           const PangoFontDescription *font_desc);
+
+G_END_DECLS
+
+#endif /* IDE_SOURCE_VIEW_H */
diff --git a/libide/ide.h b/libide/ide.h
index c8e3ad4..e43dd7e 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -67,6 +67,7 @@ G_BEGIN_DECLS
 #include "ide-service.h"
 #include "ide-source-location.h"
 #include "ide-source-range.h"
+#include "ide-source-view.h"
 #include "ide-symbol-resolver.h"
 #include "ide-symbol.h"
 #include "ide-target.h"
diff --git a/libide/util/ide-pango.c b/libide/util/ide-pango.c
new file mode 100644
index 0000000..68400bf
--- /dev/null
+++ b/libide/util/ide-pango.c
@@ -0,0 +1,180 @@
+/* ide-pango.c
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gstdio.h>
+#include <math.h>
+
+#include "ide-pango.h"
+
+#define FONT_FAMILY  "font-family"
+#define FONT_VARIANT "font-variant"
+#define FONT_STRETCH "font-stretch"
+#define FONT_WEIGHT  "font-weight"
+#define FONT_SIZE    "font-size"
+
+gchar *
+ide_pango_font_description_to_css (const PangoFontDescription *font_desc)
+{
+  PangoFontMask mask;
+  GString *str;
+
+#define ADD_KEYVAL(key,fmt) \
+  g_string_append(str,key":"fmt";")
+#define ADD_KEYVAL_PRINTF(key,fmt,...) \
+  g_string_append_printf(str,key":"fmt";", __VA_ARGS__)
+
+  g_return_val_if_fail (font_desc, NULL);
+
+  str = g_string_new (NULL);
+
+  mask = pango_font_description_get_set_fields (font_desc);
+
+  if ((mask & PANGO_FONT_MASK_FAMILY) != 0)
+    {
+      const gchar *family;
+
+      family = pango_font_description_get_family (font_desc);
+      ADD_KEYVAL_PRINTF (FONT_FAMILY, "\"%s\"", family);
+    }
+
+  if ((mask & PANGO_FONT_MASK_STYLE) != 0)
+    {
+      PangoVariant variant;
+
+      variant = pango_font_description_get_variant (font_desc);
+
+      switch (variant)
+        {
+        case PANGO_VARIANT_NORMAL:
+          ADD_KEYVAL (FONT_VARIANT, "normal");
+          break;
+
+        case PANGO_VARIANT_SMALL_CAPS:
+          ADD_KEYVAL (FONT_VARIANT, "small-caps");
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  if ((mask & PANGO_FONT_MASK_WEIGHT))
+    {
+      gint weight;
+
+      weight = pango_font_description_get_weight (font_desc);
+
+      /*
+       * WORKAROUND:
+       *
+       * font-weight with numbers does not appear to be working as expected
+       * right now. So for the common (bold/normal), let's just use the string
+       * and let gtk warn for the other values, which shouldn't really be
+       * used for this.
+       */
+
+      switch (weight)
+        {
+        case PANGO_WEIGHT_SEMILIGHT:
+          /*
+           * 350 is not actually a valid css font-weight, so we will just round
+           * up to 400.
+           */
+        case PANGO_WEIGHT_NORMAL:
+          ADD_KEYVAL (FONT_WEIGHT, "normal");
+          break;
+
+        case PANGO_WEIGHT_BOLD:
+          ADD_KEYVAL (FONT_WEIGHT, "bold");
+          break;
+
+        case PANGO_WEIGHT_THIN:
+        case PANGO_WEIGHT_ULTRALIGHT:
+        case PANGO_WEIGHT_LIGHT:
+        case PANGO_WEIGHT_BOOK:
+        case PANGO_WEIGHT_MEDIUM:
+        case PANGO_WEIGHT_SEMIBOLD:
+        case PANGO_WEIGHT_ULTRABOLD:
+        case PANGO_WEIGHT_HEAVY:
+        case PANGO_WEIGHT_ULTRAHEAVY:
+        default:
+          /* round to nearest hundred */
+          weight = round (weight / 100.0) * 100;
+          ADD_KEYVAL_PRINTF ("font-weight", "%d", weight);
+          break;
+        }
+    }
+
+  if ((mask & PANGO_FONT_MASK_STRETCH))
+    {
+      switch (pango_font_description_get_stretch (font_desc))
+        {
+        case PANGO_STRETCH_ULTRA_CONDENSED:
+          ADD_KEYVAL (FONT_STRETCH, "untra-condensed");
+          break;
+
+        case PANGO_STRETCH_EXTRA_CONDENSED:
+          ADD_KEYVAL (FONT_STRETCH, "extra-condensed");
+          break;
+
+        case PANGO_STRETCH_CONDENSED:
+          ADD_KEYVAL (FONT_STRETCH, "condensed");
+          break;
+
+        case PANGO_STRETCH_SEMI_CONDENSED:
+          ADD_KEYVAL (FONT_STRETCH, "semi-condensed");
+          break;
+
+        case PANGO_STRETCH_NORMAL:
+          ADD_KEYVAL (FONT_STRETCH, "normal");
+          break;
+
+        case PANGO_STRETCH_SEMI_EXPANDED:
+          ADD_KEYVAL (FONT_STRETCH, "semi-expanded");
+          break;
+
+        case PANGO_STRETCH_EXPANDED:
+          ADD_KEYVAL (FONT_STRETCH, "expanded");
+          break;
+
+        case PANGO_STRETCH_EXTRA_EXPANDED:
+          ADD_KEYVAL (FONT_STRETCH, "extra-expanded");
+          break;
+
+        case PANGO_STRETCH_ULTRA_EXPANDED:
+          ADD_KEYVAL (FONT_STRETCH, "untra-expanded");
+          break;
+
+        default:
+          break;
+        }
+    }
+
+  if ((mask & PANGO_FONT_MASK_SIZE))
+    {
+      gint font_size;
+
+      font_size = pango_font_description_get_size (font_desc) / PANGO_SCALE;
+      ADD_KEYVAL_PRINTF ("font-size", "%dpx", font_size);
+    }
+
+  return g_string_free (str, FALSE);
+
+#undef ADD_KEYVAL
+#undef ADD_KEYVAL_PRINTF
+}
diff --git a/libide/util/ide-pango.h b/libide/util/ide-pango.h
new file mode 100644
index 0000000..aa4fb55
--- /dev/null
+++ b/libide/util/ide-pango.h
@@ -0,0 +1,30 @@
+/* ide-pango.h
+ *
+ * Copyright (C) 2014 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_PANGO_H
+#define IDE_PANGO_H
+
+#include <pango/pango.h>
+
+G_BEGIN_DECLS
+
+gchar *ide_pango_font_description_to_css (const PangoFontDescription *font_desc);
+
+G_END_DECLS
+
+#endif /* GB_PANGO_H */
diff --git a/tests/test-ide-source-view.c b/tests/test-ide-source-view.c
new file mode 100644
index 0000000..274d5b5
--- /dev/null
+++ b/tests/test-ide-source-view.c
@@ -0,0 +1,133 @@
+/* test-ide-source-view.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ide.h>
+
+static IdeContext *gContext;
+
+static void
+load_cb (GObject      *object,
+         GAsyncResult *result,
+         gpointer      user_data)
+{
+  IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
+  g_autoptr(IdeBuffer) buffer = NULL;
+  g_autoptr(GError) error = NULL;
+  IdeSourceView *source_view = user_data;
+
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+  buffer = ide_buffer_manager_load_file_finish (buffer_manager, result, &error);
+
+  if (!buffer)
+    {
+      g_warning ("%s", error->message);
+      gtk_main_quit ();
+      return;
+    }
+
+  gtk_text_view_set_buffer (GTK_TEXT_VIEW (source_view), GTK_TEXT_BUFFER (buffer));
+  gtk_widget_set_sensitive (GTK_WIDGET (source_view), TRUE);
+  gtk_widget_grab_focus (GTK_WIDGET (source_view));
+}
+
+static void
+context_cb (GObject      *object,
+            GAsyncResult *result,
+            gpointer      user_data)
+{
+  IdeSourceView *source_view = user_data;
+  g_autoptr(IdeContext) context = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(IdeFile) file = NULL;
+  IdeProject *project;
+  IdeBufferManager *buffer_manager;
+
+  g_assert (IDE_IS_SOURCE_VIEW (source_view));
+
+  if (!(context = ide_context_new_finish (result, &error)))
+    {
+      g_warning ("%s", error->message);
+      gtk_main_quit ();
+      return;
+    }
+
+  project = ide_context_get_project (context);
+  file = ide_project_get_file_for_path (project, "test.c");
+
+  buffer_manager = ide_context_get_buffer_manager (context);
+  ide_buffer_manager_load_file_async (buffer_manager, file, FALSE,
+                                      NULL, NULL, load_cb, source_view);
+
+  gContext = g_object_ref (context);
+}
+
+static gboolean
+cancel_ops (GCancellable *cancellable)
+{
+  g_cancellable_cancel (cancellable);
+  return FALSE;
+}
+
+gint
+main (gint   argc,
+      gchar *argv[])
+{
+  GFile             *project_file;
+  GtkScrolledWindow *scroller;
+  IdeSourceView     *source_view;
+  GtkWindow         *window;
+  GCancellable      *cancellable;
+
+  ide_set_program_name ("gnome-builder");
+
+  gtk_init (&argc, &argv);
+
+  cancellable = g_cancellable_new ();
+
+  window = g_object_new (GTK_TYPE_WINDOW,
+                         "title", "IdeSourceView Test",
+                         "default-width", 600,
+                         "default-height", 600,
+                         NULL);
+  scroller = g_object_new (GTK_TYPE_SCROLLED_WINDOW,
+                           "visible", TRUE,
+                           NULL);
+  gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (scroller));
+  source_view = g_object_new (IDE_TYPE_SOURCE_VIEW,
+                              "sensitive", FALSE,
+                              "show-line-numbers", TRUE,
+                              "visible", TRUE,
+                              NULL);
+  gtk_container_add (GTK_CONTAINER (scroller), GTK_WIDGET (source_view));
+
+  project_file = g_file_new_for_path (TEST_DATA_DIR"/project1/configure.ac");
+  ide_context_new_async (project_file, cancellable, context_cb, source_view);
+
+  g_signal_connect_swapped (window, "delete-event", G_CALLBACK (cancel_ops), cancellable);
+  g_signal_connect (window, "delete-event", gtk_main_quit, NULL);
+  gtk_window_present (window);
+
+  gtk_main ();
+
+  g_clear_object (&project_file);
+  g_clear_object (&cancellable);
+  g_clear_object (&gContext);
+
+  return 0;
+}
diff --git a/tests/tests.mk b/tests/tests.mk
index 03fa032..ddeb3cc 100644
--- a/tests/tests.mk
+++ b/tests/tests.mk
@@ -39,6 +39,14 @@ test_ide_buffer_manager_CFLAGS = \
 test_ide_buffer_manager_LDADD = libide-1.0.la $(LIBIDE_LIBS)
 
 
+noinst_PROGRAMS += test-ide-source-view
+test_ide_source_view_SOURCES = tests/test-ide-source-view.c
+test_ide_source_view_CFLAGS = \
+       $(libide_1_0_la_CFLAGS) \
+       -DTEST_DATA_DIR="\"$(top_srcdir)/tests/data\""
+test_ide_source_view_LDADD = libide-1.0.la $(LIBIDE_LIBS)
+
+
 EXTRA_DIST += \
        tests/data/project1/configure.ac \
        $(NULL)


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