[gtk/wip/otte/listmodel: 10/22] inspector: Turn object tree into a GtkListBox



commit 95ff0381487dc5a1360cdcba5662ce47a1948ecf
Author: Benjamin Otte <otte redhat com>
Date:   Wed Aug 29 16:19:37 2018 +0200

    inspector: Turn object tree into a GtkListBox
    
    The code gets rid of the GtkTreeView and replaces it with a GtkListBox.
    
    Most of the logic is now done via GListModel subclasses.
    
    A big change is that this new list is now tracking updates itself and
    doesn't need to be manually updated. All code that used to cause rescans
    or add forgotten objects to the tree has been removed.
    
    If objects are missing from the object tree, the logic for tracking them
    needs to be added.

 gtk/gtkwindow.c                |    1 -
 gtk/inspector/data-list.c      |    7 +-
 gtk/inspector/inspect-button.c |    6 +-
 gtk/inspector/misc-info.c      |   18 +-
 gtk/inspector/object-tree.c    | 1475 ++++++++++++++++++++--------------------
 gtk/inspector/object-tree.h    |   13 +-
 gtk/inspector/object-tree.ui   |   91 +--
 gtk/inspector/prop-list.c      |   15 +-
 gtk/inspector/recorder.c       |    2 +
 gtk/inspector/window.c         |   16 +-
 gtk/inspector/window.h         |    2 -
 11 files changed, 752 insertions(+), 894 deletions(-)
---
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index e2cc8525f6..cffe43e686 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -10797,7 +10797,6 @@ warn_response (GtkDialog *dialog,
 static gboolean
 update_debugging (gpointer data)
 {
-  gtk_inspector_window_rescan (inspector_window);
   gtk_window_update_debugging_id = 0;
   return G_SOURCE_REMOVE;
 }
diff --git a/gtk/inspector/data-list.c b/gtk/inspector/data-list.c
index 188ed9940f..6ba7955f0e 100644
--- a/gtk/inspector/data-list.c
+++ b/gtk/inspector/data-list.c
@@ -20,6 +20,8 @@
 
 #include "data-list.h"
 
+#include "object-tree.h"
+
 #include "gtktreeview.h"
 #include "gtkcellrenderertext.h"
 #include "gtktogglebutton.h"
@@ -114,7 +116,7 @@ void
 gtk_inspector_data_list_set_object (GtkInspectorDataList *sl,
                                     GObject              *object)
 {
-  const gchar *title;
+  gchar *title;
 
   clear_view (sl);
   sl->priv->object = NULL;
@@ -126,8 +128,9 @@ gtk_inspector_data_list_set_object (GtkInspectorDataList *sl,
       return;
     }
 
-  title = (const gchar *)g_object_get_data (object, "gtk-inspector-object-title");
+  title = gtk_inspector_get_object_title (object);
   gtk_label_set_label (GTK_LABEL (sl->priv->object_title), title);
+  g_free (title);
 
   gtk_widget_show (GTK_WIDGET (sl));
 
diff --git a/gtk/inspector/inspect-button.c b/gtk/inspector/inspect-button.c
index 5fa28f25d3..2ce9ca2d02 100644
--- a/gtk/inspector/inspect-button.c
+++ b/gtk/inspector/inspect-button.c
@@ -157,11 +157,7 @@ select_widget (GtkInspectorWindow *iw,
 
   iw->selected_widget = widget;
 
-  if (!gtk_inspector_object_tree_select_object (wt, G_OBJECT (widget)))
-    {
-      gtk_inspector_object_tree_scan (wt, gtk_widget_get_toplevel (widget));
-      gtk_inspector_object_tree_select_object (wt, G_OBJECT (widget));
-    }
+  gtk_inspector_object_tree_select_object (wt, G_OBJECT (widget));
 }
 
 static void
diff --git a/gtk/inspector/misc-info.c b/gtk/inspector/misc-info.c
index 536f735eb0..37aa839904 100644
--- a/gtk/inspector/misc-info.c
+++ b/gtk/inspector/misc-info.c
@@ -180,24 +180,8 @@ show_object (GtkInspectorMiscInfo *sl,
              GObject              *object,
              const gchar          *tab)
 {
-  GtkTreeIter iter;
-
   g_object_set_data (G_OBJECT (sl->priv->object_tree), "next-tab", (gpointer)tab);
-  if (gtk_inspector_object_tree_find_object (sl->priv->object_tree, object, &iter))
-    {
-      gtk_inspector_object_tree_select_object (sl->priv->object_tree, object);
-    }
-  else if (GTK_IS_WIDGET (object) &&
-           gtk_inspector_object_tree_find_object (sl->priv->object_tree, G_OBJECT (gtk_widget_get_parent 
(GTK_WIDGET (object))), &iter))
-
-    {
-      gtk_inspector_object_tree_append_object (sl->priv->object_tree, object, &iter, NULL);
-      gtk_inspector_object_tree_select_object (sl->priv->object_tree, object);
-    }
-  else
-    {
-      g_warning ("GtkInspector: couldn't find the object in the tree");
-    }
+  gtk_inspector_object_tree_select_object (sl->priv->object_tree, object);
 }
 
 static void
diff --git a/gtk/inspector/object-tree.c b/gtk/inspector/object-tree.c
index 08f3aa85af..adf50f1347 100644
--- a/gtk/inspector/object-tree.c
+++ b/gtk/inspector/object-tree.c
@@ -34,11 +34,18 @@
 #include "gtkbutton.h"
 #include "gtkcelllayout.h"
 #include "gtkcomboboxprivate.h"
+#include "gtkfilterlistmodel.h"
+#include "gtkflattenlistmodel.h"
+#include "gtkiconprivate.h"
 #include "gtkiconview.h"
 #include "gtklabel.h"
+#include "gtklistbox.h"
 #include "gtkmenuitem.h"
 #include "gtksettings.h"
+#include "gtksizegroup.h"
 #include "gtktextview.h"
+#include "gtktogglebutton.h"
+#include "gtktreelistmodel.h"
 #include "gtktreeview.h"
 #include "gtktreeselection.h"
 #include "gtktreestore.h"
@@ -49,7 +56,6 @@
 #include "gtksearchbar.h"
 #include "gtksearchentry.h"
 #include "gtkeventcontrollerkey.h"
-#include "treewalk.h"
 
 enum
 {
@@ -72,15 +78,13 @@ enum
 
 struct _GtkInspectorObjectTreePrivate
 {
-  GtkTreeView *tree;
-  GtkTreeStore *model;
-  gulong map_hook;
-  gulong unmap_hook;
-  GtkTreeViewColumn *object_column;
+  GtkListBox *list;
+  GtkTreeListModel *tree_model;
   GtkWidget *search_bar;
   GtkWidget *search_entry;
-  GtkTreeWalk *walk;
-  gint search_length;
+  GtkSizeGroup *type_size_group;
+  GtkSizeGroup *name_size_group;
+  GtkSizeGroup *label_size_group;
 };
 
 typedef struct _ObjectTreeClassFuncs ObjectTreeClassFuncs;
@@ -91,10 +95,7 @@ typedef void (* ObjectTreeForallFunc) (GObject    *object,
 struct _ObjectTreeClassFuncs {
   GType         (* get_type)            (void);
   GObject *     (* get_parent)          (GObject                *object);
-  void          (* forall)              (GObject                *object,
-                                         ObjectTreeForallFunc    forall_func,
-                                         gpointer                forall_data);
-  gboolean      (* get_sensitive)       (GObject                *object);
+  GListModel *  (* get_children)        (GObject                *object);
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
@@ -107,17 +108,10 @@ object_tree_get_parent_default (GObject *object)
   return g_object_get_data (object, "inspector-object-tree-parent");
 }
 
-static void
-object_tree_forall_default (GObject              *object,
-                            ObjectTreeForallFunc  forall_func,
-                            gpointer              forall_data)
+static GListModel *
+object_tree_get_children_default (GObject *object)
 {
-}
-
-static gboolean
-object_tree_get_sensitive_default (GObject *object)
-{
-  return TRUE;
+  return NULL;
 }
 
 static GObject *
@@ -134,265 +128,361 @@ object_tree_menu_get_parent (GObject *object)
   return w ? G_OBJECT (w) : NULL;
 }
 
-static gboolean
-object_tree_widget_get_sensitive (GObject *object)
+static GListModel *
+object_tree_widget_get_children (GObject *object)
 {
-  return gtk_widget_get_mapped (GTK_WIDGET (object));
-}
+  GtkWidget *widget = GTK_WIDGET (object);
+  GtkFlattenListModel *flatten;
+  GListStore *list;
+  GListModel *sublist;
 
-typedef struct {
-  ObjectTreeForallFunc forall_func;
-  gpointer             forall_data;
-} ForallData;
+  list = g_list_store_new (G_TYPE_LIST_MODEL);
 
-static void
-object_tree_widget_forall (GObject              *object,
-                           ObjectTreeForallFunc  forall_func,
-                           gpointer              forall_data)
+  sublist = gtk_widget_observe_children (widget);
+  g_list_store_append (list, sublist);
+  g_object_unref (sublist);
+
+  sublist = gtk_widget_observe_controllers (widget);
+  g_list_store_append (list, sublist);
+  g_object_unref (sublist);
+
+  flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
+  g_object_unref (list);
+
+  return G_LIST_MODEL (flatten);
+}
+
+static GListModel *
+object_tree_tree_model_sort_get_children (GObject *object)
 {
-  struct {
-    GtkPropagationPhase  phase;
-    const gchar         *name;
-  } phases[] = {
-    { GTK_PHASE_CAPTURE, "capture" },
-    { GTK_PHASE_TARGET,  "target" },
-    { GTK_PHASE_BUBBLE,  "bubble" },
-    { GTK_PHASE_NONE,    "" }
-  };
-  gint i;
-  GtkWidget *child;
-
-  for (i = 0; i < G_N_ELEMENTS (phases); i++)
-    {
-      GList *list, *l;
+  GListStore *store;
 
-      list = _gtk_widget_list_controllers (GTK_WIDGET (object), phases[i].phase);
-      for (l = list; l; l = l->next)
-        {
-          GObject *controller = l->data;
-          forall_func (controller, phases[i].name, forall_data);
-        }
-      g_list_free (list);
-    }
+  store = g_list_store_new (G_TYPE_OBJECT);
+  g_list_store_append (store, gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (object)));
 
-   if (gtk_widget_is_toplevel (GTK_WIDGET (object)))
-     {
-       GObject *clock;
-
-       clock = G_OBJECT (gtk_widget_get_frame_clock (GTK_WIDGET (object)));
-       if (clock)
-         forall_func (clock, "frame-clock", forall_data);
-     }
-
-  for (child = gtk_widget_get_first_child (GTK_WIDGET (object));
-       child != NULL;
-       child = gtk_widget_get_next_sibling (child))
-     {
-       forall_func (G_OBJECT (child), NULL, forall_data);
-     }
+  return G_LIST_MODEL (store);
 }
 
-static void
-object_tree_tree_model_sort_forall (GObject              *object,
-                                    ObjectTreeForallFunc  forall_func,
-                                    gpointer              forall_data)
+static GListModel *
+object_tree_tree_model_filter_get_children (GObject *object)
 {
-  GObject *child = G_OBJECT (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (object)));
+  GListStore *store;
 
-  if (child)
-    forall_func (child, "model", forall_data);
+  store = g_list_store_new (G_TYPE_OBJECT);
+  g_list_store_append (store, gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (object)));
+
+  return G_LIST_MODEL (store);
 }
 
 static void
-object_tree_tree_model_filter_forall (GObject              *object,
-                                      ObjectTreeForallFunc  forall_func,
-                                      gpointer              forall_data)
+update_list_store (GListStore *store,
+                   GObject    *object,
+                   const char *property)
 {
-  GObject *child = G_OBJECT (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (object)));
+  gpointer value;
 
-  if (child)
-    forall_func (child, "model", forall_data);
+  g_object_get (object, property, &value, NULL);
+  if (value)
+    {
+      g_list_store_splice (store,
+                           0,
+                           g_list_model_get_n_items (G_LIST_MODEL (store)),
+                           &value,
+                           1);
+      g_object_unref (value);
+    }
+  else
+    {
+      g_list_store_remove_all (store);
+    }
 }
 
 static void
-object_tree_menu_item_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+list_model_for_property_notify_cb (GObject    *object,
+                                   GParamSpec *pspec,
+                                   GListStore *store)
 {
-  GtkWidget *submenu;
+  update_list_store (store, object, pspec->name);
+}
+
+static GListModel *
+list_model_for_property (GObject    *object,
+                         const char *property)
+{
+  GListStore *store = g_list_store_new (G_TYPE_OBJECT);
 
-  submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (object));
-  if (submenu)
-    forall_func (G_OBJECT (submenu), "submenu", forall_data);
+  /* g_signal_connect_object ("notify::property") */
+  g_signal_connect_closure_by_id (object,
+                                  g_signal_lookup ("notify", G_OBJECT_TYPE (object)),
+                                  g_quark_from_static_string (property),
+                                  g_cclosure_new_object (G_CALLBACK (list_model_for_property_notify_cb), 
G_OBJECT (store)),
+                                  FALSE);
+  update_list_store (store, object, property);
+
+  return G_LIST_MODEL (store);
 }
 
-static void
-object_tree_combo_box_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+static GListModel *
+list_model_for_properties (GObject     *object,
+                           const char **props)
 {
-  GtkWidget *popup;
-  GObject *child;
+  GListStore *concat;
+  GListModel *result;
+  guint i;
 
-  popup = gtk_combo_box_get_popup (GTK_COMBO_BOX (object));
-  if (popup)
-    forall_func (G_OBJECT (popup), "popup", forall_data);
+  if (props[1] == NULL)
+    return list_model_for_property (object, props[0]);
 
-  child = G_OBJECT (gtk_combo_box_get_model (GTK_COMBO_BOX (object)));
-  if (child)
-    forall_func (child, "model", forall_data);
+  concat = g_list_store_new (G_TYPE_LIST_MODEL);
+  for (i = 0; props[i]; i++)
+    {
+      GListModel *tmp = list_model_for_property (object, props[i]);
+      g_list_store_append (concat, tmp);
+      g_object_unref (tmp);
+    }
+
+  result = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (concat)));
+  g_object_unref (concat);
+  return result;
 }
 
-static void
-object_tree_tree_view_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+static GListModel *
+object_tree_menu_item_get_children (GObject *object)
+{
+  return list_model_for_properties (object, (const char *[2]) { "submenu", NULL });
+}
+
+static GListModel *
+object_tree_combo_box_get_children (GObject *object)
 {
-  gint n_columns, i;
-  GObject *child;
+  return list_model_for_properties (object, (const char *[2]) { "model", NULL });
+}
 
-  child = G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (object)));
-  if (child)
-    forall_func (child, "model", forall_data);
+static void
+treeview_columns_changed (GtkTreeView *treeview,
+                          GListModel  *store)
+{
+  GtkTreeViewColumn *column, *item;
+  guint i, n_columns, n_items;
 
-  child = G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (object)));
-  if (child)
-    forall_func (child, "selection", forall_data);
+  n_columns = gtk_tree_view_get_n_columns (treeview);
+  n_items = g_list_model_get_n_items (store);
 
-  n_columns = gtk_tree_view_get_n_columns (GTK_TREE_VIEW (object));
-  for (i = 0; i < n_columns; i++)
+  for (i = 0; i < MAX (n_columns, n_items); i++)
     {
-      child = G_OBJECT (gtk_tree_view_get_column (GTK_TREE_VIEW (object), i));
-      forall_func (child, NULL, forall_data);
+      column = gtk_tree_view_get_column (treeview, i);
+      item = g_list_model_get_item (store, i);
+      g_object_unref (item);
+
+      if (column == item)
+        continue;
+
+      if (n_columns < n_items)
+        {
+          /* column removed */
+          g_assert (n_columns + 1 == n_items);
+          g_list_store_remove (G_LIST_STORE (store), i);
+          return;
+        }
+      else if (n_columns > n_items)
+        {
+          /* column added */
+          g_assert (n_columns - 1 == n_items);
+          g_list_store_insert (G_LIST_STORE (store), i, column);
+          return;
+        }
+      else
+        {
+          guint j;
+          /* column reordered */
+          for (j = n_columns - 1; j > i; j--)
+            {
+              column = gtk_tree_view_get_column (treeview, j);
+              item = g_list_model_get_item (store, j);
+              g_object_unref (item);
+
+              if (column != item)
+                break;
+            }
+          g_assert (j > i);
+          column = gtk_tree_view_get_column (treeview, i);
+          item = g_list_model_get_item (store, j);
+          g_object_unref (item);
+
+          if (item == column)
+            {
+              /* column was removed from position j and put into position i */
+              g_list_store_remove (G_LIST_STORE (store), j);
+              g_list_store_insert (G_LIST_STORE (store), i, column);
+            }
+          else
+            {
+              /* column was removed from position i and put into position j */
+              column = gtk_tree_view_get_column (treeview, j);
+              g_list_store_remove (G_LIST_STORE (store), i);
+              g_list_store_insert (G_LIST_STORE (store), j, column);
+            }
+        }
     }
 }
 
-static void
-object_tree_icon_view_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+static GListModel *
+object_tree_tree_view_get_children (GObject *object)
 {
-  GObject *child;
+  GtkTreeView *treeview = GTK_TREE_VIEW (object);
+  GListStore *columns, *selection, *result_list;
+  GListModel *props;
+  GtkFlattenListModel *result;
+  guint i;
 
-  child = G_OBJECT (gtk_icon_view_get_model (GTK_ICON_VIEW (object)));
-  if (child)
-    forall_func (child, "model", forall_data);
+  props = list_model_for_properties (object, (const char *[2]) { "model", NULL });
+
+  columns = g_list_store_new (GTK_TYPE_TREE_VIEW_COLUMN);
+  g_signal_connect_object (treeview, "columns-changed", G_CALLBACK (treeview_columns_changed), columns, 0);
+  for (i = 0; i < gtk_tree_view_get_n_columns (treeview); i++)
+    g_list_store_append (columns, gtk_tree_view_get_column (treeview, i));
+
+  selection = g_list_store_new (GTK_TYPE_TREE_SELECTION);
+  g_list_store_append (selection, gtk_tree_view_get_selection (treeview));
+
+  result_list = g_list_store_new (G_TYPE_LIST_MODEL);
+  g_list_store_append (result_list, props);
+  g_object_unref (props);
+  g_list_store_append (result_list, selection);
+  g_object_unref (selection);
+  g_list_store_append (result_list, columns);
+  g_object_unref (columns);
+  result = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list));
+  g_object_unref (result_list);
+
+  return G_LIST_MODEL (result);
 }
 
-typedef struct {
-  ObjectTreeForallFunc forall_func;
-  gpointer forall_data;
-  GObject *parent;
-} ParentForallData;
+static GListModel *
+object_tree_icon_view_get_children (GObject *object)
+{
+  return list_model_for_properties (object, (const char *[2]) { "model", NULL });
+}
 
 static gboolean
-cell_callback (GtkCellRenderer *renderer,
-               gpointer         data)
+object_tree_cell_area_add_child (GtkCellRenderer  *renderer,
+                                 gpointer          store)
 {
-  ParentForallData *d = data;
   gpointer cell_layout;
 
-  cell_layout = g_object_get_data (d->parent, "gtk-inspector-cell-layout");
+  cell_layout = g_object_get_data (store, "gtk-inspector-cell-layout");
   g_object_set_data (G_OBJECT (renderer), "gtk-inspector-cell-layout", cell_layout);
-  d->forall_func (G_OBJECT (renderer), NULL, d->forall_data);
+
+  g_list_store_append (store, renderer);
 
   return FALSE;
 }
 
-static void
-object_tree_cell_area_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+static GListModel *
+object_tree_cell_area_get_children (GObject *object)
 {
-  ParentForallData data = {
-    forall_func,
-    forall_data,
-    object
-  };
+  GListStore *store;
+  gpointer cell_layout;
+
+  cell_layout = g_object_get_data (object, "gtk-inspector-cell-layout");
+  store = g_list_store_new (GTK_TYPE_CELL_RENDERER);
+  g_object_set_data (G_OBJECT (store), "gtk-inspector-cell-layout", cell_layout);
+  /* XXX: no change notification for cell areas */
+  gtk_cell_area_foreach (GTK_CELL_AREA (object), object_tree_cell_area_add_child, store);
 
-  gtk_cell_area_foreach (GTK_CELL_AREA (object), cell_callback, &data);
+  return G_LIST_MODEL (store);
 }
 
-static void
-object_tree_cell_layout_forall (GObject              *object,
-                                ObjectTreeForallFunc  forall_func,
-                                gpointer              forall_data)
+static GListModel *
+object_tree_cell_layout_get_children (GObject *object)
 {
+  GListStore *store;
   GtkCellArea *area;
 
   /* cell areas handle their own stuff */
   if (GTK_IS_CELL_AREA (object))
-    return;
+    return NULL;
 
   area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (object));
   if (!area)
-    return;
+    return NULL;
 
   g_object_set_data (G_OBJECT (area), "gtk-inspector-cell-layout", object);
-  forall_func (G_OBJECT (area), "cell-area", forall_data);
+  /* XXX: are cell areas immutable? */
+  store = g_list_store_new (G_TYPE_OBJECT);
+  g_list_store_append (store, area);
+  return G_LIST_MODEL (store);
 }
 
-static void
-object_tree_text_view_forall (GObject              *object,
-                              ObjectTreeForallFunc  forall_func,
-                              gpointer              forall_data)
+static GListModel *
+object_tree_text_view_get_children (GObject *object)
 {
-  GtkTextBuffer *buffer;
+  return list_model_for_properties (object, (const char *[2]) { "buffer", NULL });
+}
 
-  buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object));
-  forall_func (G_OBJECT (buffer), "buffer", forall_data);
+static GListModel *
+object_tree_text_buffer_get_children (GObject *object)
+{
+  return list_model_for_properties (object, (const char *[2]) { "tag-table", NULL });
 }
 
 static void
-object_tree_text_buffer_forall (GObject              *object,
-                                ObjectTreeForallFunc  forall_func,
-                                gpointer              forall_data)
+text_tag_added (GtkTextTagTable *table,
+                GtkTextTag      *tag,
+                GListStore      *store)
 {
-  GtkTextTagTable *tags;
-
-  tags = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (object));
-  forall_func (G_OBJECT (tags), "tag-table", forall_data);
+  g_list_store_append (store, tag);
 }
 
 static void
-tag_callback (GtkTextTag *tag,
-              gpointer    data)
+text_tag_removed (GtkTextTagTable *table,
+                  GtkTextTag      *tag,
+                  GListStore      *store)
 {
-  ForallData *d = data;
-  gchar *name;
+  guint i;
+
+  for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++)
+    {
+      gpointer item = g_list_model_get_item (G_LIST_MODEL (store), i);
+      g_object_unref (item);
 
-  g_object_get (tag, "name", &name, NULL);
-  d->forall_func (G_OBJECT (tag), name, d->forall_data);
-  g_free (name);
+      if (tag == item)
+        {
+          g_list_store_remove (store, i);
+          return;
+        }
+    }
 }
 
 static void
-object_tree_text_tag_table_forall (GObject              *object,
-                                   ObjectTreeForallFunc  forall_func,
-                                   gpointer              forall_data)
+text_tag_foreach (GtkTextTag *tag,
+                  gpointer    store)
 {
-  ForallData data = {
-    forall_func,
-    forall_data
-  };
-
-  gtk_text_tag_table_foreach (GTK_TEXT_TAG_TABLE (object), tag_callback, &data);
+  g_list_store_append (store, tag);
 }
 
-static void
-object_tree_application_forall (GObject              *object,
-                                ObjectTreeForallFunc  forall_func,
-                                gpointer              forall_data)
+static GListModel *
+object_tree_text_tag_table_get_children (GObject *object)
 {
-  GObject *menu;
+  GListStore *store = g_list_store_new (GTK_TYPE_TEXT_TAG);
+
+  g_signal_connect_object (object, "tag-added", G_CALLBACK (text_tag_added), store, 0);
+  g_signal_connect_object (object, "tag-removed", G_CALLBACK (text_tag_removed), store, 0);
+  gtk_text_tag_table_foreach (GTK_TEXT_TAG_TABLE (object), text_tag_foreach, store);
+
+  return NULL;
+}
 
-  menu = (GObject *)gtk_application_get_app_menu (GTK_APPLICATION (object));
-  if (menu)
-    forall_func (menu, "app-menu", forall_data);
+static GListModel *
+object_tree_application_get_children (GObject *object)
+{
+  return list_model_for_properties (object, (const char *[3]) { "app-menu", "menubar", NULL });
+}
 
-  menu = (GObject *)gtk_application_get_menubar (GTK_APPLICATION (object));
-  if (menu)
-    forall_func (menu, "menubar", forall_data);
+static GObject *
+object_tree_event_controller_get_parent (GObject *object)
+{
+  return G_OBJECT (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (object)));
 }
 
 /* Note:
@@ -404,92 +494,82 @@ static const ObjectTreeClassFuncs object_tree_class_funcs[] = {
   {
     gtk_application_get_type,
     object_tree_get_parent_default,
-    object_tree_application_forall,
-    object_tree_get_sensitive_default
+    object_tree_application_get_children
   },
   {
     gtk_text_tag_table_get_type,
     object_tree_get_parent_default,
-    object_tree_text_tag_table_forall,
-    object_tree_get_sensitive_default
+    object_tree_text_tag_table_get_children
   },
   {
     gtk_text_buffer_get_type,
     object_tree_get_parent_default,
-    object_tree_text_buffer_forall,
-    object_tree_get_sensitive_default
+    object_tree_text_buffer_get_children
   },
   {
     gtk_text_view_get_type,
     object_tree_widget_get_parent,
-    object_tree_text_view_forall,
-    object_tree_widget_get_sensitive
+    object_tree_text_view_get_children
   },
   {
     gtk_icon_view_get_type,
     object_tree_widget_get_parent,
-    object_tree_icon_view_forall,
-    object_tree_widget_get_sensitive
+    object_tree_icon_view_get_children
   },
   {
     gtk_tree_view_get_type,
     object_tree_widget_get_parent,
-    object_tree_tree_view_forall,
-    object_tree_widget_get_sensitive
+    object_tree_tree_view_get_children
   },
   {
     gtk_combo_box_get_type,
     object_tree_widget_get_parent,
-    object_tree_combo_box_forall,
-    object_tree_widget_get_sensitive
+    object_tree_combo_box_get_children
   },
   {
     gtk_menu_item_get_type,
     object_tree_widget_get_parent,
-    object_tree_menu_item_forall,
-    object_tree_widget_get_sensitive
+    object_tree_menu_item_get_children
   },
   {
     gtk_menu_get_type,
     object_tree_menu_get_parent,
-    object_tree_widget_forall,
-    object_tree_widget_get_sensitive
+    object_tree_widget_get_children
   },
   {
     gtk_widget_get_type,
     object_tree_widget_get_parent,
-    object_tree_widget_forall,
-    object_tree_widget_get_sensitive
+    object_tree_widget_get_children
   },
   {
     gtk_tree_model_filter_get_type,
     object_tree_get_parent_default,
-    object_tree_tree_model_filter_forall,
-    object_tree_get_sensitive_default
+    object_tree_tree_model_filter_get_children
   },
   {
     gtk_tree_model_sort_get_type,
     object_tree_get_parent_default,
-    object_tree_tree_model_sort_forall,
-    object_tree_get_sensitive_default
+    object_tree_tree_model_sort_get_children
   },
   {
     gtk_cell_area_get_type,
     object_tree_get_parent_default,
-    object_tree_cell_area_forall,
-    object_tree_get_sensitive_default
+    object_tree_cell_area_get_children
   },
   {
     gtk_cell_layout_get_type,
     object_tree_get_parent_default,
-    object_tree_cell_layout_forall,
-    object_tree_get_sensitive_default
+    object_tree_cell_layout_get_children
+  },
+  {
+    gtk_event_controller_get_type,
+    object_tree_event_controller_get_parent,
+    object_tree_get_children_default
   },
   {
     g_object_get_type,
     object_tree_get_parent_default,
-    object_tree_forall_default,
-    object_tree_get_sensitive_default
+    object_tree_get_children_default
   },
 };
 
@@ -522,198 +602,154 @@ object_get_parent (GObject *object)
   return funcs->get_parent (object);
 }
 
-static void
-object_forall (GObject              *object,
-               ObjectTreeForallFunc  forall_func,
-               gpointer              forall_data)
+static GListModel *
+object_get_children (GObject *object)
 {
   GType object_type;
+  GListModel *result, *children;
+  GListStore *result_list;
   guint i;
 
   object_type = G_OBJECT_TYPE (object);
+  result = NULL;
+  result_list = NULL;
 
   for (i = 0; i < G_N_ELEMENTS (object_tree_class_funcs); i++)
     {
-      if (g_type_is_a (object_type, object_tree_class_funcs[i].get_type ()))
-        object_tree_class_funcs[i].forall (object, forall_func, forall_data);
-    }
-}
+      if (!g_type_is_a (object_type, object_tree_class_funcs[i].get_type ()))
+        continue;
 
-static gboolean
-object_get_sensitive (GObject *object)
-{
-  const ObjectTreeClassFuncs *funcs;
+      children = object_tree_class_funcs[i].get_children (object);
+      if (children == NULL)
+        continue;
 
-  funcs = find_class_funcs (object);
-  
-  return funcs->get_sensitive (object);
-}
-
-static void
-on_row_activated (GtkTreeView            *tree,
-                  GtkTreePath            *path,
-                  GtkTreeViewColumn      *col,
-                  GtkInspectorObjectTree *wt)
-{
-  GtkTreeIter iter;
-  GObject *object;
-  gchar *name;
-
-  gtk_tree_model_get_iter (GTK_TREE_MODEL (wt->priv->model), &iter, path);
-  gtk_tree_model_get (GTK_TREE_MODEL (wt->priv->model), &iter,
-                      OBJECT, &object,
-                      OBJECT_NAME, &name,
-                      -1);
+      if (result_list)
+        {
+          g_list_store_append (result_list, children);
+          g_object_unref (children);
+        }
+      else if (result == NULL)
+        {
+          result = children;
+        }
+      else
+        {
+          result_list = g_list_store_new (G_TYPE_LIST_MODEL);
+          g_list_store_append (result_list, result);
+          g_object_unref (result);
+          g_list_store_append (result_list, children);
+          g_object_unref (children);
+        }
+    }
 
-  g_signal_emit (wt, signals[OBJECT_ACTIVATED], 0, object, name);
+  if (result_list)
+    {
+      result = G_LIST_MODEL (gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list)));
+      g_object_unref (result_list);
+    }
 
-  g_free (name);
+  return result;
 }
 
-GObject *
-gtk_inspector_object_tree_get_selected (GtkInspectorObjectTree *wt)
+static const char *
+gtk_inspector_get_object_name (GObject *object)
 {
-  GObject *object;
-  GtkTreeIter iter;
-  GtkTreeSelection *sel;
-  GtkTreeModel *model;
+  if (GTK_IS_WIDGET (object))
+    {
+      const gchar *id;
 
-  object = NULL;
-  sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->priv->tree));
-  if (gtk_tree_selection_get_selected (sel, &model, &iter))
-    gtk_tree_model_get (model, &iter,
-                        OBJECT, &object,
-                        -1);
+      id = gtk_widget_get_name (GTK_WIDGET (object));
+      if (id != NULL && g_strcmp0 (id, G_OBJECT_TYPE_NAME (object)) != 0)
+        return id;
+    }
 
-  return object;
-}
+  if (GTK_IS_BUILDABLE (object))
+    {
+      const gchar *id;
 
-static void
-on_selection_changed (GtkTreeSelection       *selection,
-                      GtkInspectorObjectTree *wt)
-{
-  GObject *object;
-  GtkTreeIter iter;
+      id = gtk_buildable_get_name (GTK_BUILDABLE (object));
+      if (id != NULL && !g_str_has_prefix (id, "___object_"))
+        return id;
+    }
 
-  if (gtk_tree_selection_get_selected (selection, NULL, &iter))
-    gtk_tree_walk_reset (wt->priv->walk, &iter);
-  else
-    gtk_tree_walk_reset (wt->priv->walk, NULL);
-  object = gtk_inspector_object_tree_get_selected (wt);
-  g_signal_emit (wt, signals[OBJECT_SELECTED], 0, object);
+  return NULL;
 }
 
-typedef struct {
-  GObject *dead_object;
-  GtkTreeWalk *walk;
-  GtkTreePath *walk_pos;
-} RemoveData;
-
-static gboolean
-remove_cb (GtkTreeModel *model,
-           GtkTreePath  *path,
-           GtkTreeIter  *iter,
-           gpointer      data)
+char *
+gtk_inspector_get_object_title (GObject *object)
 {
-  RemoveData *remove_data = data;
-  GObject *lookup;
-
-  gtk_tree_model_get (model, iter, OBJECT, &lookup, -1);
+  const char *name = gtk_inspector_get_object_name (object);
 
-  if (lookup == remove_data->dead_object)
-    {
-      if (remove_data->walk_pos != NULL &&
-          gtk_tree_path_compare (path, remove_data->walk_pos) == 0)
-        gtk_tree_walk_reset (remove_data->walk, NULL);
-
-      gtk_tree_store_remove (GTK_TREE_STORE (model), iter);
-
-      return TRUE;
-    }
-
-  return FALSE;
+  if (name == NULL)
+    return g_strdup (G_OBJECT_TYPE_NAME (object));
+  else
+    return g_strconcat (G_OBJECT_TYPE_NAME (object), " — ", name, NULL);
 }
 
 static void
-gtk_object_tree_remove_dead_object (gpointer data, GObject *dead_object)
+on_row_activated (GtkListBox             *box,
+                  GtkListBoxRow          *row,
+                  GtkInspectorObjectTree *wt)
 {
-  GtkInspectorObjectTree *wt = data;
-  GtkTreeIter iter;
-  RemoveData remove_data;
-
-  remove_data.dead_object = dead_object;
-  remove_data.walk = wt->priv->walk;
-  if (gtk_tree_walk_get_position (wt->priv->walk, &iter))
-    remove_data.walk_pos = gtk_tree_model_get_path (GTK_TREE_MODEL (wt->priv->model), &iter);
-  else
-    remove_data.walk_pos = NULL;
+  guint pos;
+  GtkTreeListRow *item;
+  GObject *object;
+
+  pos = gtk_list_box_row_get_index (row);
+  item = g_list_model_get_item (G_LIST_MODEL (wt->priv->tree_model), pos);
+  object = gtk_tree_list_row_get_item (item);
 
-  gtk_tree_model_foreach (GTK_TREE_MODEL (wt->priv->model), remove_cb, &remove_data);
+  g_signal_emit (wt, signals[OBJECT_ACTIVATED], 0, object);
 
-  if (remove_data.walk_pos)
-    gtk_tree_path_free (remove_data.walk_pos);
+  g_object_unref (item);
+  g_object_unref (object);
 }
 
-static gboolean
-weak_unref_cb (GtkTreeModel *model,
-               GtkTreePath  *path,
-               GtkTreeIter  *iter,
-               gpointer      data)
+GObject *
+gtk_inspector_object_tree_get_selected (GtkInspectorObjectTree *wt)
 {
-  GtkInspectorObjectTree *wt = data;
+  GtkListBoxRow *selected_row;
+  guint selected_pos;
+  GtkTreeListRow *selected_row_item;
   GObject *object;
 
-  gtk_tree_model_get (model, iter, OBJECT, &object, -1);
+  selected_row = gtk_list_box_get_selected_row (wt->priv->list);
+  if (selected_row == NULL)
+    return NULL;
 
-  g_object_weak_unref (object, gtk_object_tree_remove_dead_object, wt);
+  selected_pos = gtk_list_box_row_get_index (selected_row);
+  selected_row_item = g_list_model_get_item (G_LIST_MODEL (wt->priv->tree_model), selected_pos);
 
-  return FALSE;
+  object = gtk_tree_list_row_get_item (selected_row_item);
+  g_object_unref (selected_row_item);
+
+  g_object_unref (object); /* ahem */
+  return object;
 }
 
 static void
-clear_store (GtkInspectorObjectTree *wt)
+widget_mapped (GtkWidget     *widget,
+               GtkListBoxRow *row)
 {
-  if (wt->priv->model)
-    {
-      gtk_tree_model_foreach (GTK_TREE_MODEL (wt->priv->model), weak_unref_cb, wt);
-      gtk_tree_store_clear (wt->priv->model);
-      gtk_tree_walk_reset (wt->priv->walk, NULL);
-    }
-}
+  GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (row));
 
-static gboolean
-map_or_unmap (GSignalInvocationHint *ihint,
-              guint                  n_params,
-              const GValue          *params,
-              gpointer               data)
-{
-  GtkInspectorObjectTree *wt = data;
-  GtkWidget *widget;
-  GtkTreeIter iter;
-
-  widget = g_value_get_object (params);
-  if (gtk_inspector_object_tree_find_object (wt, G_OBJECT (widget), &iter))
-    gtk_tree_store_set (wt->priv->model, &iter,
-                        SENSITIVE, gtk_widget_get_mapped (widget),
-                        -1);
-  return TRUE;
+  gtk_style_context_remove_class (context, "dim-label");
 }
 
 static void
-move_search_to_row (GtkInspectorObjectTree *wt,
-                    GtkTreeIter            *iter)
+widget_unmapped (GtkWidget     *widget,
+                 GtkListBoxRow *row)
 {
-  GtkTreeSelection *selection;
-  GtkTreePath *path;
-
-  selection = gtk_tree_view_get_selection (wt->priv->tree);
-  path = gtk_tree_model_get_path (GTK_TREE_MODEL (wt->priv->model), iter);
-  gtk_tree_view_expand_to_path (wt->priv->tree, path);
-  gtk_tree_selection_select_path (selection, path);
-  gtk_tree_view_scroll_to_cell (wt->priv->tree, path, NULL, TRUE, 0.5, 0.0);
-  gtk_tree_path_free (path);
+  GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (row));
+
+  gtk_style_context_add_class (context, "dim-label");
 }
 
+static gboolean
+search (GtkInspectorObjectTree *wt,
+        gboolean                forward,
+        gboolean                force_progress);
+
 static gboolean
 key_pressed (GtkEventController     *controller,
              guint                   keyval,
@@ -734,24 +770,8 @@ key_pressed (GtkEventController     *controller,
            keyval == GDK_KEY_ISO_Enter ||
            keyval == GDK_KEY_KP_Enter))
         {
-          GtkTreeSelection *selection;
-          GtkTreeModel *model;
-          GtkTreeIter iter;
-          GtkTreePath *path;
-
-          selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->priv->tree));
-          if (gtk_tree_selection_get_selected (selection, &model, &iter))
-            {
-              path = gtk_tree_model_get_path (model, &iter);
-              gtk_tree_view_row_activated (GTK_TREE_VIEW (wt->priv->tree),
-                                           path,
-                                           wt->priv->object_column);
-              gtk_tree_path_free (path);
-
-              return GDK_EVENT_STOP;
-            }
-          else
-            return GDK_EVENT_PROPAGATE;
+          gtk_widget_activate (GTK_WIDGET (wt->priv->list));
+          return GDK_EVENT_PROPAGATE;
         }
       else if (search_started &&
                (keyval == GDK_KEY_Escape))
@@ -763,25 +783,16 @@ key_pressed (GtkEventController     *controller,
                ((state & (default_accel | GDK_SHIFT_MASK)) == (default_accel | GDK_SHIFT_MASK)) &&
                (keyval == GDK_KEY_g || keyval == GDK_KEY_G))
         {
-          GtkTreeIter iter;
-          if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, TRUE, &iter))
-            move_search_to_row (wt, &iter);
-          else
+          if (!search (wt, TRUE, TRUE))
             gtk_widget_error_bell (GTK_WIDGET (wt));
-
           return GDK_EVENT_STOP;
         }
       else if (search_started &&
                ((state & (default_accel | GDK_SHIFT_MASK)) == default_accel) &&
                (keyval == GDK_KEY_g || keyval == GDK_KEY_G))
         {
-          GtkTreeIter iter;
-
-          if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, FALSE, &iter))
-            move_search_to_row (wt, &iter);
-          else
+          if (!search (wt, TRUE, TRUE))
             gtk_widget_error_bell (GTK_WIDGET (wt));
-
           return GDK_EVENT_STOP;
         }
     }
@@ -820,27 +831,6 @@ on_hierarchy_changed (GtkWidget *widget,
                                          toplevel);
 }
 
-static void
-on_search_changed (GtkSearchEntry         *entry,
-                   GtkInspectorObjectTree *wt)
-{
-  GtkTreeIter iter;
-  gint length;
-  gboolean backwards;
-
-  length = strlen (gtk_entry_get_text (GTK_ENTRY (entry)));
-  backwards = length < wt->priv->search_length;
-  wt->priv->search_length = length;
-
-  if (length == 0)
-    return;
-
-  if (gtk_tree_walk_next_match (wt->priv->walk, backwards, backwards, &iter))
-    move_search_to_row (wt, &iter);
-  else if (!backwards)
-    gtk_widget_error_bell (GTK_WIDGET (wt));
-}
-
 static gboolean
 match_string (const gchar *string,
               const gchar *text)
@@ -859,43 +849,120 @@ match_string (const gchar *string,
 }
 
 static gboolean
-match_row (GtkTreeModel *model,
-           GtkTreeIter  *iter,
-           gpointer      data)
+match_object (GObject    *object,
+              const char *text)
 {
-  GtkInspectorObjectTree *wt = data;
-  gchar *type, *name, *label;
-  const gchar *text;
-  gboolean match;
-
-  text = gtk_entry_get_text (GTK_ENTRY (wt->priv->search_entry));
-  gtk_tree_model_get (model, iter,
-                      OBJECT_TYPE, &type,
-                      OBJECT_NAME, &name,
-                      OBJECT_LABEL, &label,
-                      -1);
-
-  match = (match_string (type, text) ||
-           match_string (name, text) ||
-           match_string (label, text));
-
-  g_free (type);
-  g_free (name);
-  g_free (label);
+  if (match_string (G_OBJECT_TYPE_NAME (object), text) ||
+      match_string (gtk_inspector_get_object_name (object), text))
+    return TRUE;
 
-  return match;
+  if (GTK_IS_LABEL (object))
+    return match_string (gtk_label_get_label (GTK_LABEL (object)), text);
+  else if (GTK_IS_BUTTON (object))
+    return match_string (gtk_button_get_label (GTK_BUTTON (object)), text);
+  else if (GTK_IS_WINDOW (object))
+    return match_string (gtk_window_get_title (GTK_WINDOW (object)), text);
+  else if (GTK_IS_TREE_VIEW_COLUMN (object))
+    return match_string (gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (object)), text);
+  else
+    return FALSE;
 }
 
-static void
-search_mode_changed (GObject                *search_bar,
-                     GParamSpec             *pspec,
-                     GtkInspectorObjectTree *wt)
+static GObject *
+search_children (GObject    *object,
+                 const char *text,
+                 gboolean    forward)
 {
-  if (!gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (search_bar)))
+  GListModel *children;
+  GObject *child, *result;
+  guint i, n;
+
+  children = object_get_children (object);
+  if (children == NULL)
+    return NULL;
+
+  n = g_list_model_get_n_items (children);
+  for (i = 0; i < n; i++)
     {
-      gtk_tree_walk_reset (wt->priv->walk, NULL);
-      wt->priv->search_length = 0;
+      child = g_list_model_get_item (children, forward ? i : n - i - 1);
+      if (match_object (child, text))
+        return child;
+
+      result = search_children (child, text, forward);
+      g_object_unref (child);
+      if (result)
+        return result;
     }
+
+  return NULL;
+}
+
+static gboolean
+search (GtkInspectorObjectTree *wt,
+        gboolean                forward,
+        gboolean                force_progress)
+{
+  GtkInspectorObjectTreePrivate *priv = wt->priv;
+  GListModel *model = G_LIST_MODEL (priv->tree_model);
+  GtkTreeListRow *row_item;
+  GObject *child, *result;
+  guint i, selected, n, row;
+  const char *text;
+
+  text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
+  if (gtk_list_box_get_selected_row (priv->list))
+    {
+      selected = gtk_list_box_row_get_index (gtk_list_box_get_selected_row (priv->list));
+    }
+  else
+    {
+      selected = 0;
+      force_progress = FALSE;
+    }
+  n = g_list_model_get_n_items (model);
+
+  for (i = 0; i < n; i++)
+    {
+      row = (selected + (forward ? i : n - i - 1)) % n;
+      row_item = g_list_model_get_item (model, row);
+      child = gtk_tree_list_row_get_item (row_item);
+      if (i > 0 || !force_progress)
+        {
+          if (match_object (child, text))
+            {
+              gtk_list_box_select_row (priv->list, gtk_list_box_get_row_at_index (priv->list, row));
+              g_object_unref (child);
+              g_object_unref (row_item);
+              return TRUE;
+            }
+        }
+
+      if (!gtk_tree_list_row_get_expanded (row_item))
+        {
+          result = search_children (child, text, forward);
+          if (result)
+            {
+              g_print ("selecting!\n");
+              gtk_inspector_object_tree_select_object (wt, result);
+              g_object_unref (result);
+              g_object_unref (child);
+              g_object_unref (row_item);
+              return TRUE;
+            }
+        }
+      g_object_unref (child);
+      g_object_unref (row_item);
+    }
+
+  return FALSE;
+}
+
+static void
+on_search_changed (GtkSearchEntry         *entry,
+                   GtkInspectorObjectTree *wt)
+{
+  if (!search (wt, TRUE, FALSE))
+    gtk_widget_error_bell (GTK_WIDGET (wt));
 }
 
 static void
@@ -904,11 +971,7 @@ next_match (GtkButton              *button,
 {
   if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar)))
     {
-      GtkTreeIter iter;
-
-      if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, FALSE, &iter))
-        move_search_to_row (wt, &iter);
-      else
+      if (!search (wt, TRUE, TRUE))
         gtk_widget_error_bell (GTK_WIDGET (wt));
     }
 }
@@ -919,11 +982,7 @@ previous_match (GtkButton              *button,
 {
   if (gtk_search_bar_get_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar)))
     {
-      GtkTreeIter iter;
-
-      if (gtk_tree_walk_next_match (wt->priv->walk, TRUE, TRUE, &iter))
-        move_search_to_row (wt, &iter);
-      else
+      if (!search (wt, FALSE, TRUE))
         gtk_widget_error_bell (GTK_WIDGET (wt));
     }
 }
@@ -936,55 +995,182 @@ stop_search (GtkWidget              *entry,
   gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (wt->priv->search_bar), FALSE);
 }
 
-static void
-gtk_inspector_object_tree_init (GtkInspectorObjectTree *wt)
+static GtkWidget *
+gtk_inspector_object_tree_create_list_widget (gpointer row_item,
+                                              gpointer user_data)
 {
-  guint signal_id;
+  GtkInspectorObjectTree *wt = user_data;
+  gpointer item;
+  GtkWidget *row, *box, *column, *child;
+  guint depth;
 
-  wt->priv = gtk_inspector_object_tree_get_instance_private (wt);
-  gtk_widget_init_template (GTK_WIDGET (wt));
+  item = gtk_tree_list_row_get_item (row_item);
 
-  gtk_search_bar_connect_entry (GTK_SEARCH_BAR (wt->priv->search_bar),
-                                GTK_ENTRY (wt->priv->search_entry));
+  row = gtk_list_box_row_new ();
+  g_object_set_data_full (G_OBJECT (row), "make-sure-its-not-unreffed", g_object_ref (row_item), 
g_object_unref);
+  if (GTK_IS_WIDGET (item))
+    {
+      g_signal_connect_object (item, "map", G_CALLBACK (widget_mapped), row, 0);
+      g_signal_connect_object (item, "unmap", G_CALLBACK (widget_unmapped), row, 0);
+      if (!gtk_widget_get_mapped (item))
+        widget_unmapped (item, GTK_LIST_BOX_ROW (row));
+    }
+
+  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_container_add (GTK_CONTAINER (row), box);
+
+  column = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+  gtk_size_group_add_widget (wt->priv->type_size_group, column);
+  gtk_container_add (GTK_CONTAINER (box), column);
+
+  /* expander */
+  depth = gtk_tree_list_row_get_depth (row_item);
+  if (depth > 0)
+    {
+      child = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+      gtk_widget_set_size_request (child, 16 * depth, 0);
+      gtk_container_add (GTK_CONTAINER (column), child);
+    }
+  if (gtk_tree_list_row_is_expandable (row_item))
+    {
+      GtkWidget *title, *arrow;
+
+      child = g_object_new (GTK_TYPE_BOX, "css-name", "expander", NULL);
+      
+      title = g_object_new (GTK_TYPE_TOGGLE_BUTTON, "css-name", "title", NULL);
+      gtk_button_set_relief (GTK_BUTTON (title), GTK_RELIEF_NONE);
+      g_object_bind_property (row_item, "expanded", title, "active", G_BINDING_BIDIRECTIONAL | 
G_BINDING_SYNC_CREATE);
+      gtk_container_add (GTK_CONTAINER (child), title);
+
+      arrow = gtk_icon_new ("arrow");
+      gtk_container_add (GTK_CONTAINER (title), arrow);
+    }
+  else
+    {
+      child = gtk_image_new (); /* empty whatever */
+    }
+  gtk_container_add (GTK_CONTAINER (column), child);
+
+  /* 1st column: type name */
+  child = gtk_label_new (G_OBJECT_TYPE_NAME (item));
+  gtk_label_set_width_chars (GTK_LABEL (child), 30);
+  gtk_label_set_xalign (GTK_LABEL (child), 0.0);
+  gtk_container_add (GTK_CONTAINER (column), child);
+
+  /* 2nd column: name */
+  child = gtk_label_new (gtk_inspector_get_object_name (item));
+  gtk_label_set_width_chars (GTK_LABEL (child), 15);
+  gtk_label_set_xalign (GTK_LABEL (child), 0.0);
+  gtk_size_group_add_widget (wt->priv->name_size_group, child);
+  gtk_container_add (GTK_CONTAINER (box), child);
+
+  /* 3rd column: label */
+  child = gtk_label_new (NULL);
+  if (GTK_IS_LABEL (item))
+    g_object_bind_property (item, "label", child, "label", G_BINDING_SYNC_CREATE);
+  else if (GTK_IS_BUTTON (item))
+    g_object_bind_property (item, "label", child, "label", G_BINDING_SYNC_CREATE);
+  else if (GTK_IS_WINDOW (item))
+    g_object_bind_property (item, "title", child, "label", G_BINDING_SYNC_CREATE);
+  else if (GTK_IS_TREE_VIEW_COLUMN (item))
+    g_object_bind_property (item, "title", child, "label", G_BINDING_SYNC_CREATE);
+  gtk_label_set_width_chars (GTK_LABEL (child), 15);
+  gtk_label_set_xalign (GTK_LABEL (child), 0.0);
+  gtk_size_group_add_widget (wt->priv->label_size_group, child);
+  gtk_container_add (GTK_CONTAINER (box), child);
+
+  g_object_unref (item);
+
+  return row;
+}
+
+static GListModel *
+create_model_for_object (gpointer object,
+                         gpointer user_data)
+{
+  return object_get_children (object);
+}
+
+static gboolean
+toplevel_filter_func (gpointer item,
+                      gpointer data)
+{
+  GdkDisplay *display = data;
 
-  g_signal_connect (wt->priv->search_bar, "notify::search-mode-enabled",
-                    G_CALLBACK (search_mode_changed), wt);
-  wt->priv->walk = gtk_tree_walk_new (GTK_TREE_MODEL (wt->priv->model), match_row, wt, NULL);
+  if (!GTK_IS_WINDOW (item))
+    return FALSE;
+
+  if (g_str_equal (G_OBJECT_TYPE_NAME (item), "GtkInspectorWindow"))
+    return FALSE;
 
-  signal_id = g_signal_lookup ("map", GTK_TYPE_WIDGET);
-  wt->priv->map_hook = g_signal_add_emission_hook (signal_id, 0,
-                                                   map_or_unmap, wt, NULL);
-  signal_id = g_signal_lookup ("unmap", GTK_TYPE_WIDGET);
-  wt->priv->unmap_hook = g_signal_add_emission_hook (signal_id, 0,
-                                                   map_or_unmap, wt, NULL);
+  return gtk_window_get_window_type (item) == GTK_WINDOW_TOPLEVEL &&
+         gtk_widget_get_display (item) == display;
+}
 
-  gtk_inspector_object_tree_append_object (wt, G_OBJECT (gtk_settings_get_default ()), NULL, NULL);
+static GListModel *
+create_root_model (void)
+{
+  GtkFilterListModel *filter;
+  GtkFlattenListModel *flatten;
+  GListStore *list, *special;
+
+  list = g_list_store_new (G_TYPE_LIST_MODEL);
+
+  special = g_list_store_new (G_TYPE_OBJECT);
+  g_list_store_append (special, g_application_get_default ());
+  g_list_store_append (special, gtk_settings_get_default ());
+  g_list_store_append (list, special);
+  g_object_unref (special);
+
+  filter = gtk_filter_list_model_new_for_type (G_TYPE_OBJECT);
+  gtk_filter_list_model_set_filter_func (filter, 
+                                         toplevel_filter_func,
+                                         g_object_ref (gdk_display_get_default ()),
+                                         g_object_unref);
+  gtk_filter_list_model_set_model (filter, gtk_window_get_toplevels ());
+  g_list_store_append (list, filter);
+  g_object_unref (filter);
+
+  flatten = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (list));
+  g_object_unref (list);
+  return G_LIST_MODEL (flatten);
 }
 
 static void
-gtk_inspector_object_tree_dispose (GObject *object)
+gtk_inspector_object_tree_init (GtkInspectorObjectTree *wt)
 {
-  GtkInspectorObjectTree *wt = GTK_INSPECTOR_OBJECT_TREE (object);
+  GListModel *root_model;
 
-  clear_store (wt);
+  wt->priv = gtk_inspector_object_tree_get_instance_private (wt);
+  gtk_widget_init_template (GTK_WIDGET (wt));
 
-  G_OBJECT_CLASS (gtk_inspector_object_tree_parent_class)->dispose (object);
+  gtk_search_bar_connect_entry (GTK_SEARCH_BAR (wt->priv->search_bar),
+                                GTK_ENTRY (wt->priv->search_entry));
+
+  root_model = create_root_model ();
+  wt->priv->tree_model = gtk_tree_list_model_new (FALSE,
+                                                  root_model,
+                                                  FALSE,
+                                                  create_model_for_object,
+                                                  NULL,
+                                                  NULL);
+  g_object_unref (root_model);
+
+  gtk_list_box_bind_model (wt->priv->list,
+                           G_LIST_MODEL (wt->priv->tree_model),
+                           gtk_inspector_object_tree_create_list_widget,
+                           wt,
+                           NULL);
 }
 
 static void
-gtk_inspector_object_tree_finalize (GObject *object)
+gtk_inspector_object_tree_dispose (GObject *object)
 {
   GtkInspectorObjectTree *wt = GTK_INSPECTOR_OBJECT_TREE (object);
-  guint signal_id;
 
-  signal_id = g_signal_lookup ("map", GTK_TYPE_WIDGET);
-  g_signal_remove_emission_hook (signal_id, wt->priv->map_hook);
-  signal_id = g_signal_lookup ("unmap", GTK_TYPE_WIDGET);
-  g_signal_remove_emission_hook (signal_id, wt->priv->unmap_hook);
+  g_clear_object (&wt->priv->tree_model);
 
-  gtk_tree_walk_free (wt->priv->walk);
-
-  G_OBJECT_CLASS (gtk_inspector_object_tree_parent_class)->finalize (object);
+  G_OBJECT_CLASS (gtk_inspector_object_tree_parent_class)->dispose (object);
 }
 
 static void
@@ -993,7 +1179,6 @@ gtk_inspector_object_tree_class_init (GtkInspectorObjectTreeClass *klass)
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
 
-  object_class->finalize = gtk_inspector_object_tree_finalize;
   object_class->dispose = gtk_inspector_object_tree_dispose;
 
   signals[OBJECT_ACTIVATED] =
@@ -1003,7 +1188,7 @@ gtk_inspector_object_tree_class_init (GtkInspectorObjectTreeClass *klass)
                     G_STRUCT_OFFSET (GtkInspectorObjectTreeClass, object_activated),
                     NULL, NULL,
                     NULL,
-                    G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_STRING);
+                    G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
   signals[OBJECT_SELECTED] =
       g_signal_new ("object-selected",
@@ -1015,292 +1200,84 @@ gtk_inspector_object_tree_class_init (GtkInspectorObjectTreeClass *klass)
                     G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
   gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/object-tree.ui");
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, model);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, tree);
-  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, object_column);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, list);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, search_bar);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, search_entry);
-  gtk_widget_class_bind_template_callback (widget_class, on_selection_changed);
-  gtk_widget_class_bind_template_callback (widget_class, on_row_activated);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, type_size_group);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, name_size_group);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorObjectTree, label_size_group);
   gtk_widget_class_bind_template_callback (widget_class, on_hierarchy_changed);
   gtk_widget_class_bind_template_callback (widget_class, on_search_changed);
+  gtk_widget_class_bind_template_callback (widget_class, on_row_activated);
   gtk_widget_class_bind_template_callback (widget_class, next_match);
   gtk_widget_class_bind_template_callback (widget_class, previous_match);
   gtk_widget_class_bind_template_callback (widget_class, stop_search);
 }
 
-typedef struct
-{
-  GtkInspectorObjectTree *wt;
-  GtkTreeIter *iter;
-  GObject *parent;
-} FindAllData;
-
-static void
-child_callback (GObject    *object,
-                const char *name,
-                gpointer    data)
+static guint
+model_get_item_index (GListModel *model,
+                      gpointer    item)
 {
-  FindAllData *d = data;
-
-  gtk_inspector_object_tree_append_object (d->wt, object, d->iter, NULL);
-}
-
-void
-gtk_inspector_object_tree_append_object (GtkInspectorObjectTree *wt,
-                                         GObject                *object,
-                                         GtkTreeIter            *parent_iter,
-                                         const gchar            *name)
-{
-  GtkTreeIter iter;
-  const gchar *class_name;
-  gchar *classes;
-  const gchar *label;
-  FindAllData data;
-
-  class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object));
-
-  if (GTK_IS_WIDGET (object))
-    {
-      const gchar *id;
-      GtkStyleContext *context;
-      GList *list, *l;
-      GString *string;
-
-      id = gtk_widget_get_name (GTK_WIDGET (object));
-      if (name == NULL && id != NULL && g_strcmp0 (id, class_name) != 0)
-        name = id;
+  gpointer cmp;
+  guint i;
 
-      context = gtk_widget_get_style_context (GTK_WIDGET (object));
-      string = g_string_new ("");
-      list = gtk_style_context_list_classes (context);
-      for (l = list; l; l = l->next)
-        {
-          if (string->len > 0)
-            g_string_append_c (string, ' ');
-          g_string_append (string, (gchar *)l->data);
-        }
-      classes = g_string_free (string, FALSE);
-      g_list_free (list);
-    }
-  else
+  for (i = 0; (cmp = g_list_model_get_item (model, i)); i++)
     {
-      if (parent_iter)
+      if (cmp == item)
         {
-          GObject *parent;
-
-          gtk_tree_model_get (GTK_TREE_MODEL (wt->priv->model), parent_iter,
-                              OBJECT, &parent,
-                              -1);
-          g_object_set_data (object, "inspector-object-tree-parent", parent);
+          g_object_unref (cmp);
+          return i;
         }
-      classes = g_strdup ("");
+      g_object_unref (cmp);
     }
 
-  if (GTK_IS_BUILDABLE (object))
-    {
-      const gchar *id;
-      id = gtk_buildable_get_name (GTK_BUILDABLE (object));
-      if (name == NULL && id != NULL && !g_str_has_prefix (id, "___object_"))
-        name = id;
-    }
+  return G_MAXUINT;
+}
 
-  if (name == NULL)
-    name = "";
+static GtkTreeListRow *
+find_and_expand_object (GtkTreeListModel *model,
+                        GObject          *object)
+{
+  GtkTreeListRow *result;
+  GObject *parent;
+  guint pos;
 
-  if (GTK_IS_LABEL (object))
-    label = gtk_label_get_text (GTK_LABEL (object));
-  else if (GTK_IS_BUTTON (object))
-    label = gtk_button_get_label (GTK_BUTTON (object));
-  else if (GTK_IS_WINDOW (object))
-    label = gtk_window_get_title (GTK_WINDOW (object));
-  else if (GTK_IS_TREE_VIEW_COLUMN (object))
-    label = gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (object));
-  else
-    label = "";
-
-  gtk_tree_store_append (wt->priv->model, &iter, parent_iter);
-  gtk_tree_store_set (wt->priv->model, &iter,
-                      OBJECT, object,
-                      OBJECT_TYPE, class_name,
-                      OBJECT_NAME, name,
-                      OBJECT_LABEL, label,
-                      OBJECT_CLASSES, classes,
-                      SENSITIVE, object_get_sensitive (object),
-                      -1);
-
-  if (name && *name)
+  parent = object_get_parent (object);
+  if (parent)
     {
-      gchar *title;
-      title = g_strconcat (class_name, " — ", name, NULL);
-      g_object_set_data_full (object, "gtk-inspector-object-title", title, g_free);
+      GtkTreeListRow *parent_row = find_and_expand_object (model, parent);
+      if (parent_row == NULL)
+        return NULL;
+
+      gtk_tree_list_row_set_expanded (parent_row, TRUE);
+      pos = model_get_item_index (gtk_tree_list_row_get_children (parent_row), object);
+      result = gtk_tree_list_row_get_child (parent_row, pos);
+      g_object_unref (parent_row);
     }
   else
     {
-      g_object_set_data (object, "gtk-inspector-object-title", (gpointer)class_name);
+      pos = model_get_item_index (gtk_tree_list_model_get_model (model), object);
+      result = gtk_tree_list_model_get_child (model, pos);
     }
-
-  g_free (classes);
-
-  g_object_weak_ref (object, gtk_object_tree_remove_dead_object, wt);
   
-  data.wt = wt;
-  data.iter = &iter;
-  data.parent = object;
-
-  object_forall (object, child_callback, &data);
-}
-
-static void
-block_selection_changed (GtkInspectorObjectTree *wt)
-{
-  GtkTreeSelection *selection;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->priv->tree));
-  g_signal_handlers_block_by_func (selection, on_selection_changed, wt);
-}
-
-static void
-unblock_selection_changed (GtkInspectorObjectTree *wt)
-{
-  GtkTreeSelection *selection;
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->priv->tree));
-  g_signal_handlers_unblock_by_func (selection, on_selection_changed, wt);
-}
-
-static gboolean
-select_object_internal (GtkInspectorObjectTree *wt,
-                        GObject                *object,
-                        gboolean                activate)
-{
-  GtkTreeIter iter;
-
-  if (gtk_inspector_object_tree_find_object (wt, object, &iter))
-    {
-      GtkTreePath *path;
-      GtkTreeSelection *selection;
-
-      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (wt->priv->tree));
-      path = gtk_tree_model_get_path (GTK_TREE_MODEL (wt->priv->model), &iter);
-      gtk_tree_view_expand_to_path (GTK_TREE_VIEW (wt->priv->tree), path);
-      if (!activate)
-        block_selection_changed (wt);
-      gtk_tree_selection_select_iter (selection, &iter);
-      if (!activate)
-        unblock_selection_changed (wt);
-
-      gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (wt->priv->tree), path, NULL, TRUE, 0.5, 0);
-      if (activate)
-        gtk_tree_view_row_activated (GTK_TREE_VIEW (wt->priv->tree), path, NULL);
-      gtk_tree_path_free (path);
-
-      return TRUE;
-    }
-
-  return FALSE;
+  return result;
 }
 
-gboolean
+void
 gtk_inspector_object_tree_select_object (GtkInspectorObjectTree *wt,
                                          GObject                *object)
 {
-  return select_object_internal (wt, object, TRUE);
-}
-
-void
-gtk_inspector_object_tree_scan (GtkInspectorObjectTree *wt,
-                                GtkWidget              *window)
-{
-  GtkWidget *inspector_win;
-  GList *toplevels, *l;
-  GdkDisplay *display;
-  GObject *selected;
-
-  block_selection_changed (wt);
-
-  selected = gtk_inspector_object_tree_get_selected (wt);
-
-  clear_store (wt);
-  gtk_inspector_object_tree_append_object (wt, G_OBJECT (gtk_settings_get_default ()), NULL, NULL);
-  if (g_application_get_default ())
-    gtk_inspector_object_tree_append_object (wt, G_OBJECT (g_application_get_default ()), NULL, NULL);
-
-  if (window)
-    gtk_inspector_object_tree_append_object (wt, G_OBJECT (window), NULL, NULL);
-
-  display = gdk_display_get_default ();
-
-  inspector_win = gtk_widget_get_toplevel (GTK_WIDGET (wt));
-  toplevels = gtk_window_list_toplevels ();
-  for (l = toplevels; l; l = l->next)
-    {
-      if (GTK_IS_WINDOW (l->data) &&
-          gtk_window_get_window_type (l->data) == GTK_WINDOW_TOPLEVEL &&
-          gtk_widget_get_display (l->data) == display &&
-          l->data != window &&
-          l->data != inspector_win)
-        gtk_inspector_object_tree_append_object (wt, G_OBJECT (l->data), NULL, NULL);
-    }
-  g_list_free (toplevels);
-
-  gtk_tree_view_columns_autosize (GTK_TREE_VIEW (wt->priv->tree));
-
-  if (selected)
-    select_object_internal (wt, selected, FALSE);
-
-  unblock_selection_changed (wt);
-}
-
-static gboolean
-gtk_inspector_object_tree_find_object_at_parent_iter (GtkTreeModel *model,
-                                                      GObject      *object,
-                                                      GtkTreeIter  *parent,
-                                                      GtkTreeIter  *iter)
-{
-  if (!gtk_tree_model_iter_children (model, iter, parent))
-    return FALSE;
-
-  do {
-    GObject *lookup;
-
-    gtk_tree_model_get (model, iter, OBJECT, &lookup, -1);
-
-    if (lookup == object)
-      return TRUE;
-
-  } while (gtk_tree_model_iter_next (model, iter));
-
-  return FALSE;
-}
-
-gboolean
-gtk_inspector_object_tree_find_object (GtkInspectorObjectTree *wt,
-                                       GObject                *object,
-                                       GtkTreeIter            *iter)
-{
-  GtkTreeIter parent_iter;
-  GObject *parent;
+  GtkTreeListRow *row_item;
+  GtkListBoxRow *row_widget;
 
-  parent = object_get_parent (object);
-  if (parent)
-    {
-      if (!gtk_inspector_object_tree_find_object (wt, parent, &parent_iter))
-        return FALSE;
+  row_item = find_and_expand_object (wt->priv->tree_model, object);
+  if (row_item == NULL)
+    return;
 
-      return gtk_inspector_object_tree_find_object_at_parent_iter (GTK_TREE_MODEL (wt->priv->model),
-                                                                   object,
-                                                                   &parent_iter,
-                                                                   iter);
-    }
-  else
-    {
-      return gtk_inspector_object_tree_find_object_at_parent_iter (GTK_TREE_MODEL (wt->priv->model),
-                                                                   object,
-                                                                   NULL,
-                                                                   iter);
-    }
+  row_widget = gtk_list_box_get_row_at_index (wt->priv->list,
+                                              gtk_tree_list_row_get_position (row_item));
+  g_return_if_fail (row_widget != NULL);
+  gtk_list_box_select_row (wt->priv->list, row_widget);
+  g_object_unref (row_item);
 }
 
-
-// vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/object-tree.h b/gtk/inspector/object-tree.h
index e89cb82925..23c53633a3 100644
--- a/gtk/inspector/object-tree.h
+++ b/gtk/inspector/object-tree.h
@@ -58,17 +58,10 @@ G_BEGIN_DECLS
 
 GType      gtk_inspector_object_tree_get_type            (void);
 
-void       gtk_inspector_object_tree_scan                (GtkInspectorObjectTree *wt,
-                                                          GtkWidget              *window);
-gboolean   gtk_inspector_object_tree_select_object       (GtkInspectorObjectTree *wt,
+char *     gtk_inspector_get_object_title                (GObject                *object);
+
+void       gtk_inspector_object_tree_select_object       (GtkInspectorObjectTree *wt,
                                                           GObject                *object);
-void       gtk_inspector_object_tree_append_object       (GtkInspectorObjectTree *wt,
-                                                          GObject                *object,
-                                                          GtkTreeIter            *parent_iter,
-                                                          const gchar            *name);
-gboolean   gtk_inspector_object_tree_find_object         (GtkInspectorObjectTree *wt,
-                                                          GObject                *object,
-                                                          GtkTreeIter            *iter);
 
 GObject   *gtk_inspector_object_tree_get_selected        (GtkInspectorObjectTree *wt);
 
diff --git a/gtk/inspector/object-tree.ui b/gtk/inspector/object-tree.ui
index 07d85d276d..e56dc8a8d3 100644
--- a/gtk/inspector/object-tree.ui
+++ b/gtk/inspector/object-tree.ui
@@ -1,15 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface domain="gtk40">
-  <object class="GtkTreeStore" id="model">
-    <columns>
-      <column type="gpointer"/>
-      <column type="gchararray"/>
-      <column type="gchararray"/>
-      <column type="gchararray"/>
-      <column type="gchararray"/>
-      <column type="gboolean"/>
-    </columns>
-  </object>
   <template class="GtkInspectorObjectTree" parent="GtkBox">
     <property name="visible">True</property>
     <property name="orientation">vertical</property>
@@ -52,81 +42,20 @@
         <property name="hscrollbar-policy">never</property>
         <property name="expand">1</property>
         <child>
-          <object class="GtkTreeView" id="tree">
-            <property name="model">model</property>
-            <property name="enable-search">0</property>
-            <property name="enable-grid-lines">vertical</property>
+          <object class="GtkListBox" id="list">
             <signal name="row-activated" handler="on_row_activated"/>
-            <child internal-child="selection">
-              <object class="GtkTreeSelection">
-                <signal name="changed" handler="on_selection_changed"/>
-              </object>
-            </child>
-            <child>
-              <object class="GtkTreeViewColumn" id="object_column">
-                <property name="title" translatable="yes">Object</property>
-                <property name="resizable">1</property>
-                <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
-                  </object>
-                  <attributes>
-                    <attribute name="text">1</attribute>
-                    <attribute name="sensitive">5</attribute>
-                  </attributes>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Name</property>
-                <property name="resizable">1</property>
-                <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
-                  </object>
-                  <attributes>
-                    <attribute name="text">2</attribute>
-                    <attribute name="sensitive">5</attribute>
-                  </attributes>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Label</property>
-                <property name="resizable">1</property>
-                <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
-                    <property name="ellipsize">end</property>
-                    <property name="max-width-chars">30</property>
-                  </object>
-                  <attributes>
-                    <attribute name="text">3</attribute>
-                    <attribute name="sensitive">5</attribute>
-                  </attributes>
-                </child>
-              </object>
-            </child>
-            <child>
-              <object class="GtkTreeViewColumn">
-                <property name="title" translatable="yes">Style Classes</property>
-                <property name="resizable">1</property>
-                <child>
-                  <object class="GtkCellRendererText">
-                    <property name="scale">0.8</property>
-                  </object>
-                  <attributes>
-                    <attribute name="text">4</attribute>
-                    <attribute name="sensitive">5</attribute>
-                  </attributes>
-                </child>
-              </object>
-            </child>
           </object>
         </child>
       </object>
     </child>
   </template>
+  <object class="GtkSizeGroup" id="type_size_group">
+    <property name="mode">both</property>
+  </object>
+  <object class="GtkSizeGroup" id="name_size_group">
+    <property name="mode">both</property>
+  </object>
+  <object class="GtkSizeGroup" id="label_size_group">
+    <property name="mode">both</property>
+  </object>
 </interface>
diff --git a/gtk/inspector/prop-list.c b/gtk/inspector/prop-list.c
index 286c4e2ab1..46b75513e3 100644
--- a/gtk/inspector/prop-list.c
+++ b/gtk/inspector/prop-list.c
@@ -207,26 +207,13 @@ show_object (GtkInspectorPropEditor *editor,
              const gchar            *tab,
              GtkInspectorPropList   *pl)
 {
-  GtkTreeIter iter;
   GtkWidget *popover;
 
   popover = gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_POPOVER);
   gtk_widget_hide (popover);
 
   g_object_set_data (G_OBJECT (pl->priv->object_tree), "next-tab", (gpointer)tab);
-  if (gtk_inspector_object_tree_find_object (pl->priv->object_tree, object, &iter))
-    {
-      gtk_inspector_object_tree_select_object (pl->priv->object_tree, object);
-    }
-  else if (gtk_inspector_object_tree_find_object (pl->priv->object_tree, pl->priv->object, &iter))
-    {
-      gtk_inspector_object_tree_append_object (pl->priv->object_tree, object, &iter, name);
-      gtk_inspector_object_tree_select_object (pl->priv->object_tree, object);
-    }
-  else
-    {
-      g_warning ("GtkInspector: couldn't find the widget in the tree");
-    }
+  gtk_inspector_object_tree_select_object (pl->priv->object_tree, object);
 }
 
 static void
diff --git a/gtk/inspector/recorder.c b/gtk/inspector/recorder.c
index f5603c47f4..aa7f2cd1d8 100644
--- a/gtk/inspector/recorder.c
+++ b/gtk/inspector/recorder.c
@@ -402,6 +402,8 @@ recordings_list_row_selected (GtkListBox           *box,
       gtk_picture_set_paintable (GTK_PICTURE (priv->render_node_view), NULL);
     }
 
+  g_print ("%u render nodes\n", g_list_model_get_n_items (G_LIST_MODEL (priv->render_node_model)));
+
   gtk_list_box_bind_model (GTK_LIST_BOX (priv->render_node_list),
                            G_LIST_MODEL (priv->render_node_model),
                            create_widget_for_render_node,
diff --git a/gtk/inspector/window.c b/gtk/inspector/window.c
index 03273e82b9..eb7b34da31 100644
--- a/gtk/inspector/window.c
+++ b/gtk/inspector/window.c
@@ -62,13 +62,14 @@ set_selected_object (GtkInspectorWindow *iw,
                      GObject            *selected)
 {
   GList *l;
-  const char *title;
+  char *title;
 
   if (!gtk_inspector_prop_list_set_object (GTK_INSPECTOR_PROP_LIST (iw->prop_list), selected))
     return FALSE;
 
-  title = (const char *)g_object_get_data (selected, "gtk-inspector-object-title");
+  title = gtk_inspector_get_object_title (selected);
   gtk_label_set_label (GTK_LABEL (iw->object_title), title);
+  g_free (title);
 
   gtk_inspector_prop_list_set_object (GTK_INSPECTOR_PROP_LIST (iw->child_prop_list), selected);
   gtk_inspector_signals_list_set_object (GTK_INSPECTOR_SIGNALS_LIST (iw->signals_list), selected);
@@ -92,7 +93,6 @@ set_selected_object (GtkInspectorWindow *iw,
 static void
 on_object_activated (GtkInspectorObjectTree *wt,
                      GObject                *selected,
-                     const gchar            *name,
                      GtkInspectorWindow     *iw)
 {
   const gchar *tab;
@@ -232,8 +232,6 @@ gtk_inspector_window_constructed (GObject *object)
   G_OBJECT_CLASS (gtk_inspector_window_parent_class)->constructed (object);
 
   g_object_set_data (G_OBJECT (gdk_display_get_default ()), "-gtk-inspector", iw);
-
-  gtk_inspector_object_tree_scan (GTK_INSPECTOR_OBJECT_TREE (iw->object_tree), NULL);
 }
 
 static void
@@ -379,14 +377,6 @@ gtk_inspector_window_remove_overlay (GtkInspectorWindow  *iw,
   iw->overlays = g_list_delete_link (iw->overlays, item);
 }
 
-void
-gtk_inspector_window_rescan (GtkWidget *widget)
-{
-  GtkInspectorWindow *iw = GTK_INSPECTOR_WINDOW (widget);
-
-  gtk_inspector_object_tree_scan (GTK_INSPECTOR_OBJECT_TREE (iw->object_tree), NULL);
-}
-
 static GtkInspectorWindow *
 gtk_inspector_window_get_for_display (GdkDisplay *display)
 {
diff --git a/gtk/inspector/window.h b/gtk/inspector/window.h
index 92e2015867..26ba277e6b 100644
--- a/gtk/inspector/window.h
+++ b/gtk/inspector/window.h
@@ -111,8 +111,6 @@ void                    gtk_inspector_window_remove_overlay
 
 void                    gtk_inspector_window_select_widget_under_pointer        (GtkInspectorWindow     *iw);
 
-void                    gtk_inspector_window_rescan                             (GtkWidget              *iw);
-
 gboolean                gtk_inspector_is_recording                              (GtkWidget              
*widget);
 GskRenderNode *         gtk_inspector_prepare_render                            (GtkWidget              
*widget,
                                                                                  GskRenderer            
*renderer,


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