[gnome-builder/wip/gtk4-port] libide/gtk: start on tree expander



commit 2b6553ad5cfdaf2ee82939a58567c63d31d0415e
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jul 7 12:20:52 2022 -0700

    libide/gtk: start on tree expander
    
    We are going to have our own tree expander instead of GTKs so that we can
    easily bind context menus, remove the use of expander arrows, and special
    grouping styling such that our replacement looks/feels similar to how
    Builder's project-tree design looks.

 src/libide/gtk/ide-gtk-init.c      |   2 +
 src/libide/gtk/ide-tree-expander.c | 505 +++++++++++++++++++++++++++++++++++++
 src/libide/gtk/ide-tree-expander.h |  69 +++++
 src/libide/gtk/libide-gtk.h        |   1 +
 src/libide/gtk/meson.build         |   2 +
 5 files changed, 579 insertions(+)
---
diff --git a/src/libide/gtk/ide-gtk-init.c b/src/libide/gtk/ide-gtk-init.c
index cdb73d880..21dbb1cde 100644
--- a/src/libide/gtk/ide-gtk-init.c
+++ b/src/libide/gtk/ide-gtk-init.c
@@ -35,6 +35,7 @@
 #include "ide-radio-box.h"
 #include "ide-search-entry.h"
 #include "ide-shortcut-accel-dialog.h"
+#include "ide-tree-expander.h"
 #include "ide-truncate-model.h"
 
 void
@@ -50,6 +51,7 @@ _ide_gtk_init (void)
   g_type_ensure (IDE_TYPE_RADIO_BOX);
   g_type_ensure (IDE_TYPE_SEARCH_ENTRY);
   g_type_ensure (IDE_TYPE_SHORTCUT_ACCEL_DIALOG);
+  g_type_ensure (IDE_TYPE_TREE_EXPANDER);
   g_type_ensure (IDE_TYPE_TRUNCATE_MODEL);
 
   g_resources_register (ide_gtk_get_resource ());
diff --git a/src/libide/gtk/ide-tree-expander.c b/src/libide/gtk/ide-tree-expander.c
new file mode 100644
index 000000000..5b429a31d
--- /dev/null
+++ b/src/libide/gtk/ide-tree-expander.c
@@ -0,0 +1,505 @@
+/* ide-tree-expander.c
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#define G_LOG_DOMAIN "ide-tree-expander"
+
+#include "config.h"
+
+#include "ide-tree-expander.h"
+
+struct _IdeTreeExpander
+{
+  GtkWidget       parent_instance;
+
+  GtkWidget      *image;
+  GtkWidget      *title;
+  GtkWidget      *suffix;
+
+  GMenuModel     *menu_model;
+
+  GtkTreeListRow *list_row;
+
+  const char     *icon_name;
+  const char     *expanded_icon_name;
+
+  gulong          list_row_notify_depth;
+  gulong          list_row_notify_expanded;
+};
+
+enum {
+  PROP_0,
+  PROP_EXPANDED_ICON_NAME,
+  PROP_ICON_NAME,
+  PROP_ITEM,
+  PROP_LIST_ROW,
+  PROP_MENU_MODEL,
+  PROP_SUFFIX,
+  PROP_TITLE,
+  N_PROPS
+};
+
+G_DEFINE_FINAL_TYPE (IdeTreeExpander, ide_tree_expander, GTK_TYPE_WIDGET)
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+ide_tree_expander_update_depth (IdeTreeExpander *self)
+{
+  static GType builtin_icon_type = G_TYPE_INVALID;
+  guint depth;
+
+  g_assert (IDE_IS_TREE_EXPANDER (self));
+
+  if (self->list_row != NULL)
+    depth = gtk_tree_list_row_get_depth (self->list_row);
+  else
+    depth = 0;
+
+  for (;;)
+    {
+      GtkWidget *child = gtk_widget_get_first_child (GTK_WIDGET (self));
+
+      if (child == self->image)
+        break;
+
+      gtk_widget_unparent (child);
+    }
+
+  if (builtin_icon_type == G_TYPE_INVALID)
+    builtin_icon_type = g_type_from_name ("GtkBuiltinIcon");
+
+  for (guint i = 0; i < depth; i++)
+    {
+      GtkWidget *child;
+
+      child = g_object_new (builtin_icon_type,
+                            "css-name", "indent",
+                            "accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
+                            NULL);
+      gtk_widget_insert_after (child, GTK_WIDGET (self), NULL);
+    }
+
+  /* The level property is >= 1 */
+  gtk_accessible_update_property (GTK_ACCESSIBLE (self),
+                                  GTK_ACCESSIBLE_PROPERTY_LEVEL, depth + 1,
+                                  -1);
+}
+
+static void
+ide_tree_expander_update_icon (IdeTreeExpander *self)
+{
+  const char *icon_name;
+
+  g_assert (IDE_IS_TREE_EXPANDER (self));
+
+  if (self->list_row != NULL && gtk_tree_list_row_get_expanded (self->list_row))
+    icon_name = self->expanded_icon_name ? self->expanded_icon_name : self->icon_name;
+  else
+    icon_name = self->icon_name;
+
+  gtk_image_set_from_icon_name (GTK_IMAGE (self->image), icon_name);
+}
+
+static void
+ide_tree_expander_notify_depth_cb (IdeTreeExpander *self,
+                                   GParamSpec      *pspec,
+                                   GtkTreeListRow  *list_row)
+{
+  g_assert (IDE_IS_TREE_EXPANDER (self));
+  g_assert (GTK_IS_TREE_LIST_ROW (list_row));
+
+  ide_tree_expander_update_depth (self);
+}
+
+static void
+ide_tree_expander_notify_expanded_cb (IdeTreeExpander *self,
+                                      GParamSpec      *pspec,
+                                      GtkTreeListRow  *list_row)
+{
+  g_assert (IDE_IS_TREE_EXPANDER (self));
+  g_assert (GTK_IS_TREE_LIST_ROW (list_row));
+
+  ide_tree_expander_update_icon (self);
+}
+
+static void
+ide_tree_expander_dispose (GObject *object)
+{
+  IdeTreeExpander *self = (IdeTreeExpander *)object;
+
+  ide_tree_expander_set_list_row (self, NULL);
+
+  g_clear_pointer (&self->image, gtk_widget_unparent);
+  g_clear_pointer (&self->title, gtk_widget_unparent);
+  g_clear_pointer (&self->suffix, gtk_widget_unparent);
+
+  g_clear_object (&self->list_row);
+  g_clear_object (&self->menu_model);
+
+  G_OBJECT_CLASS (ide_tree_expander_parent_class)->dispose (object);
+}
+
+static void
+ide_tree_expander_get_property (GObject    *object,
+                                guint       prop_id,
+                                GValue     *value,
+                                GParamSpec *pspec)
+{
+  IdeTreeExpander *self = IDE_TREE_EXPANDER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPANDED_ICON_NAME:
+      g_value_set_string (value, ide_tree_expander_get_expanded_icon_name (self));
+      break;
+
+    case PROP_ICON_NAME:
+      g_value_set_string (value, ide_tree_expander_get_icon_name (self));
+      break;
+
+    case PROP_ITEM:
+      g_value_take_object (value, ide_tree_expander_get_item (self));
+      break;
+
+    case PROP_LIST_ROW:
+      g_value_set_object (value, ide_tree_expander_get_list_row (self));
+      break;
+
+    case PROP_MENU_MODEL:
+      g_value_set_object (value, ide_tree_expander_get_menu_model (self));
+      break;
+
+    case PROP_SUFFIX:
+      g_value_set_object (value, ide_tree_expander_get_suffix (self));
+      break;
+
+    case PROP_TITLE:
+      g_value_set_string (value, ide_tree_expander_get_title (self));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_tree_expander_set_property (GObject      *object,
+                                guint         prop_id,
+                                const GValue *value,
+                                GParamSpec   *pspec)
+{
+  IdeTreeExpander *self = IDE_TREE_EXPANDER (object);
+
+  switch (prop_id)
+    {
+    case PROP_EXPANDED_ICON_NAME:
+      ide_tree_expander_set_expanded_icon_name (self, g_value_get_string (value));
+      break;
+
+    case PROP_ICON_NAME:
+      ide_tree_expander_set_icon_name (self, g_value_get_string (value));
+      break;
+
+    case PROP_LIST_ROW:
+      ide_tree_expander_set_list_row (self, g_value_get_object (value));
+      break;
+
+    case PROP_MENU_MODEL:
+      ide_tree_expander_set_menu_model (self, g_value_get_object (value));
+      break;
+
+    case PROP_SUFFIX:
+      ide_tree_expander_set_suffix (self, g_value_get_object (value));
+      break;
+
+    case PROP_TITLE:
+      ide_tree_expander_set_title (self, g_value_get_string (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+ide_tree_expander_class_init (IdeTreeExpanderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = ide_tree_expander_dispose;
+  object_class->get_property = ide_tree_expander_get_property;
+  object_class->set_property = ide_tree_expander_set_property;
+
+  properties[PROP_EXPANDED_ICON_NAME] =
+    g_param_spec_string ("expanded-icon-name", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_ICON_NAME] =
+    g_param_spec_string ("icon-name", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_ITEM] =
+    g_param_spec_object ("item", NULL, NULL,
+                         G_TYPE_OBJECT,
+                         (G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_LIST_ROW] =
+    g_param_spec_object ("list-row", NULL, NULL,
+                         GTK_TYPE_TREE_LIST_ROW,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_MENU_MODEL] =
+    g_param_spec_object ("menu-model", NULL, NULL,
+                         G_TYPE_MENU_MODEL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties[PROP_SUFFIX] =
+    g_param_spec_object ("suffix", NULL, NULL,
+                         GTK_TYPE_WIDGET,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  properties [PROP_TITLE] =
+    g_param_spec_string ("title", NULL, NULL,
+                         NULL,
+                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
+  gtk_widget_class_set_css_name (widget_class, "treeexpander");
+  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_GROUP);
+}
+
+static void
+ide_tree_expander_init (IdeTreeExpander *self)
+{
+  self->image = g_object_new (GTK_TYPE_IMAGE, NULL);
+  gtk_widget_insert_after (self->image, GTK_WIDGET (self), NULL);
+
+  self->title = g_object_new (GTK_TYPE_LABEL,
+                              "halign", GTK_ALIGN_START,
+                              "ellipsize", PANGO_ELLIPSIZE_END,
+                              NULL);
+  gtk_widget_insert_after (self->title, GTK_WIDGET (self), self->image);
+}
+
+/**
+ * ide_tree_expander_get_item:
+ * @self: a #IdeTreeExpander
+ *
+ * Gets the item instance from the model.
+ *
+ * Returns: (transfer full) (nullable) (type GObject): a #GObject or %NULL
+ */
+gpointer
+ide_tree_expander_get_item (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  if (self->list_row == NULL)
+    return NULL;
+
+  return gtk_tree_list_row_get_item (self->list_row);
+}
+
+/**
+ * ide_tree_expander_get_menu_model:
+ * @self: a #IdeTreeExpander
+ *
+ * Sets the menu model to use for context menus.
+ *
+ * Returns: (transfer none) (nullable): a #GMenuModel or %NULL
+ */
+GMenuModel *
+ide_tree_expander_get_menu_model (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return self->menu_model;
+}
+
+void
+ide_tree_expander_set_menu_model (IdeTreeExpander *self,
+                                  GMenuModel      *menu_model)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+  g_return_if_fail (!menu_model || G_IS_MENU_MODEL (menu_model));
+
+  if (g_set_object (&self->menu_model, menu_model))
+    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MENU_MODEL]);
+}
+
+const char *
+ide_tree_expander_get_expanded_icon_name (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return self->expanded_icon_name;
+}
+
+void
+ide_tree_expander_set_expanded_icon_name (IdeTreeExpander *self,
+                                          const char      *expanded_icon_name)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+
+  if (!ide_str_equal0 (self->expanded_icon_name, expanded_icon_name))
+    {
+      self->expanded_icon_name = g_intern_string (expanded_icon_name);
+      ide_tree_expander_update_icon (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPANDED_ICON_NAME]);
+    }
+}
+
+const char *
+ide_tree_expander_get_icon_name (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return self->icon_name;
+}
+
+void
+ide_tree_expander_set_icon_name (IdeTreeExpander *self,
+                                 const char      *icon_name)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+
+  if (!ide_str_equal0 (self->icon_name, icon_name))
+    {
+      self->icon_name = g_intern_string (icon_name);
+      ide_tree_expander_update_icon (self);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON_NAME]);
+    }
+}
+
+/**
+ * ide_tree_expander_get_suffix:
+ * @self: a #IdeTreeExpander
+ *
+ * Get the suffix widget, if any.
+ *
+ * Returns: (transfer none) (nullable): a #GtkWidget
+ */
+GtkWidget *
+ide_tree_expander_get_suffix (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return self->suffix;
+}
+
+void
+ide_tree_expander_set_suffix (IdeTreeExpander *self,
+                              GtkWidget       *suffix)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+  g_return_if_fail (!suffix || GTK_IS_WIDGET (suffix));
+
+  if (self->suffix == suffix)
+    return;
+
+  g_clear_pointer (&self->suffix, gtk_widget_unparent);
+
+  self->suffix = suffix;
+
+  if (self->suffix)
+    gtk_widget_insert_before (suffix, GTK_WIDGET (self), NULL);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SUFFIX]);
+}
+
+const char *
+ide_tree_expander_get_title (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return gtk_label_get_label (GTK_LABEL (self->title));
+}
+
+void
+ide_tree_expander_set_title (IdeTreeExpander *self,
+                             const char      *title)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+
+  if (!ide_str_equal0 (title, ide_tree_expander_get_title (self)))
+    {
+      gtk_label_set_label (GTK_LABEL (self->title), title);
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TITLE]);
+    }
+}
+
+/**
+ * ide_tree_expander_get_list_row:
+ * @self: a #IdeTreeExpander
+ *
+ * Gets the list row for the expander.
+ *
+ * Returns: (transfer none) (nullable): a #GtkTreeListRow or %NULL
+ */
+GtkTreeListRow *
+ide_tree_expander_get_list_row (IdeTreeExpander *self)
+{
+  g_return_val_if_fail (IDE_IS_TREE_EXPANDER (self), NULL);
+
+  return self->list_row;
+}
+
+void
+ide_tree_expander_set_list_row (IdeTreeExpander *self,
+                                GtkTreeListRow  *list_row)
+{
+  g_return_if_fail (IDE_IS_TREE_EXPANDER (self));
+  g_return_if_fail (!list_row || GTK_IS_TREE_LIST_ROW (list_row));
+
+  if (self->list_row == list_row)
+    return;
+
+  if (self->list_row != NULL)
+    {
+      g_clear_signal_handler (&self->list_row_notify_depth, self->list_row);
+      g_clear_signal_handler (&self->list_row_notify_expanded, self->list_row);
+    }
+
+  g_set_object (&self->list_row, list_row);
+
+  if (self->list_row != NULL)
+    {
+      self->list_row_notify_expanded = g_signal_connect_object (self->list_row,
+                                                                "notify::expanded",
+                                                                G_CALLBACK 
(ide_tree_expander_notify_expanded_cb),
+                                                                self,
+                                                                G_CONNECT_SWAPPED);
+      self->list_row_notify_depth = g_signal_connect_object (self->list_row,
+                                                             "notify::depth",
+                                                             G_CALLBACK (ide_tree_expander_notify_depth_cb),
+                                                             self,
+                                                             G_CONNECT_SWAPPED);
+    }
+
+  ide_tree_expander_update_depth (self);
+  ide_tree_expander_update_icon (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LIST_ROW]);
+}
diff --git a/src/libide/gtk/ide-tree-expander.h b/src/libide/gtk/ide-tree-expander.h
new file mode 100644
index 000000000..8481a97c3
--- /dev/null
+++ b/src/libide/gtk/ide-tree-expander.h
@@ -0,0 +1,69 @@
+/* ide-tree-expander.h
+ *
+ * Copyright 2022 Christian Hergert <chergert redhat com>
+ *
+ * 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/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TREE_EXPANDER (ide_tree_expander_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeTreeExpander, ide_tree_expander, IDE, TREE_EXPANDER, GtkWidget)
+
+IDE_AVAILABLE_IN_ALL
+GtkWidget      *ide_tree_expander_new                    (void);
+IDE_AVAILABLE_IN_ALL
+GMenuModel     *ide_tree_expander_get_menu_model         (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_menu_model         (IdeTreeExpander *self,
+                                                          GMenuModel      *menu_model);
+IDE_AVAILABLE_IN_ALL
+const char     *ide_tree_expander_get_icon_name          (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_icon_name          (IdeTreeExpander *self,
+                                                          const char      *icon_name);
+IDE_AVAILABLE_IN_ALL
+const char     *ide_tree_expander_get_expanded_icon_name (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_expanded_icon_name (IdeTreeExpander *self,
+                                                          const char      *expanded_icon_name);
+IDE_AVAILABLE_IN_ALL
+const char     *ide_tree_expander_get_title              (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_title              (IdeTreeExpander *self,
+                                                          const char      *title);
+IDE_AVAILABLE_IN_ALL
+GtkWidget      *ide_tree_expander_get_suffix             (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_suffix             (IdeTreeExpander *self,
+                                                          GtkWidget       *suffix);
+IDE_AVAILABLE_IN_ALL
+GtkTreeListRow *ide_tree_expander_get_list_row           (IdeTreeExpander *self);
+IDE_AVAILABLE_IN_ALL
+void            ide_tree_expander_set_list_row           (IdeTreeExpander *self,
+                                                          GtkTreeListRow  *list_row);
+IDE_AVAILABLE_IN_ALL
+gpointer        ide_tree_expander_get_item               (IdeTreeExpander *self);
+
+G_END_DECLS
diff --git a/src/libide/gtk/libide-gtk.h b/src/libide/gtk/libide-gtk.h
index 56a2ad058..18929e199 100644
--- a/src/libide/gtk/libide-gtk.h
+++ b/src/libide/gtk/libide-gtk.h
@@ -37,5 +37,6 @@
 # include "ide-radio-box.h"
 # include "ide-search-entry.h"
 # include "ide-shortcut-accel-dialog.h"
+# include "ide-tree-expander.h"
 # include "ide-truncate-model.h"
 #undef IDE_GTK_INSIDE
diff --git a/src/libide/gtk/meson.build b/src/libide/gtk/meson.build
index d8cd4f011..908c983a8 100644
--- a/src/libide/gtk/meson.build
+++ b/src/libide/gtk/meson.build
@@ -22,6 +22,7 @@ libide_gtk_public_headers = [
   'ide-radio-box.h',
   'ide-search-entry.h',
   'ide-shortcut-accel-dialog.h',
+  'ide-tree-expander.h',
   'ide-truncate-model.h',
   'libide-gtk.h',
 ]
@@ -52,6 +53,7 @@ libide_gtk_public_sources = [
   'ide-radio-box.c',
   'ide-search-entry.c',
   'ide-shortcut-accel-dialog.c',
+  'ide-tree-expander.c',
   'ide-truncate-model.c',
 ]
 


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