[gtk+] inspector: Refactor object tree construction
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] inspector: Refactor object tree construction
- Date: Wed, 26 Aug 2015 14:35:34 +0000 (UTC)
commit c7ed2c21307efe26f2259bd28ef076bdff0a2b78
Author: Benjamin Otte <otte redhat com>
Date: Wed Aug 26 15:28:22 2015 +0200
inspector: Refactor object tree construction
Instead of having lots of if statements, create a vtable. This will be
useful for the following patches.
gtk/inspector/object-tree.c | 697 +++++++++++++++++++++++++++++--------------
1 files changed, 480 insertions(+), 217 deletions(-)
---
diff --git a/gtk/inspector/object-tree.c b/gtk/inspector/object-tree.c
index 55fc7e3..4af3868 100644
--- a/gtk/inspector/object-tree.c
+++ b/gtk/inspector/object-tree.c
@@ -83,10 +83,477 @@ struct _GtkInspectorObjectTreePrivate
gint search_length;
};
+typedef struct _ObjectTreeClassFuncs ObjectTreeClassFuncs;
+typedef void (* ObjectTreeForallFunc) (GObject *object,
+ const char *name,
+ gpointer data);
+
+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);
+};
+
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorObjectTree, gtk_inspector_object_tree, GTK_TYPE_BOX)
+static GObject *
+object_tree_get_parent_default (GObject *object)
+{
+ return NULL;
+}
+
+static void
+object_tree_forall_default (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+}
+
+static gboolean
+object_tree_get_sensitive_default (GObject *object)
+{
+ return TRUE;
+}
+
+static GObject *
+object_tree_widget_get_parent (GObject *object)
+{
+ return G_OBJECT (gtk_widget_get_parent (GTK_WIDGET (object)));
+}
+
+static void
+object_tree_widget_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ struct {
+ GtkPropagationPhase phase;
+ const gchar *name;
+ } phases[] = {
+ { GTK_PHASE_CAPTURE, "capture" },
+ { GTK_PHASE_TARGET, "target" },
+ { GTK_PHASE_BUBBLE, "bubble" },
+ { GTK_PHASE_NONE, "" }
+ };
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (phases); i++)
+ {
+ GList *list, *l;
+
+ 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);
+ }
+
+ 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);
+ }
+}
+
+static gboolean
+object_tree_widget_get_sensitive (GObject *object)
+{
+ return gtk_widget_get_mapped (GTK_WIDGET (object));
+}
+
+typedef struct {
+ ObjectTreeForallFunc forall_func;
+ gpointer forall_data;
+} ForallData;
+
+static void
+container_children_callback (GtkWidget *widget,
+ gpointer client_data)
+{
+ ForallData *forall_data = client_data;
+
+ forall_data->forall_func (G_OBJECT (widget), NULL, forall_data->forall_data);
+}
+
+static void
+object_tree_container_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ ForallData data = {
+ forall_func,
+ forall_data
+ };
+
+ gtk_container_forall (GTK_CONTAINER (object),
+ container_children_callback,
+ &data);
+}
+
+static void
+object_tree_tree_model_sort_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GObject *child = G_OBJECT (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (object)));
+
+ if (child)
+ forall_func (child, "model", forall_data);
+}
+
+static void
+object_tree_tree_model_filter_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GObject *child = G_OBJECT (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (object)));
+
+ if (child)
+ forall_func (child, "model", forall_data);
+}
+
+static void
+object_tree_menu_item_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GtkWidget *submenu;
+
+ submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (object));
+ if (submenu)
+ forall_func (G_OBJECT (submenu), "submenu", forall_data);
+}
+
+static void
+object_tree_combo_box_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GtkWidget *popup;
+ GObject *child;
+
+ popup = gtk_combo_box_get_popup (GTK_COMBO_BOX (object));
+ if (popup)
+ forall_func (G_OBJECT (popup), "popup", forall_data);
+
+ child = G_OBJECT (gtk_combo_box_get_model (GTK_COMBO_BOX (object)));
+ if (child)
+ forall_func (child, "model", forall_data);
+}
+
+static void
+object_tree_tree_view_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ gint n_columns, i;
+ GObject *child;
+
+ child = G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (object)));
+ if (child)
+ forall_func (child, "model", forall_data);
+
+ 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 (GTK_TREE_VIEW (object));
+ for (i = 0; i < n_columns; i++)
+ {
+ child = G_OBJECT (gtk_tree_view_get_column (GTK_TREE_VIEW (object), i));
+ forall_func (child, NULL, forall_data);
+ }
+}
+
+static void
+object_tree_icon_view_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GObject *child;
+
+ child = G_OBJECT (gtk_icon_view_get_model (GTK_ICON_VIEW (object)));
+ if (child)
+ forall_func (child, "mnodel", forall_data);
+}
+
+typedef struct {
+ ObjectTreeForallFunc forall_func;
+ gpointer forall_data;
+ GObject *parent;
+} ParentForallData;
+
+static gboolean
+cell_callback (GtkCellRenderer *renderer,
+ gpointer data)
+{
+ ParentForallData *d = data;
+ gpointer cell_layout;
+
+ cell_layout = g_object_get_data (d->parent, "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);
+
+ return FALSE;
+}
+
+static void
+object_tree_cell_area_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ ParentForallData data = {
+ forall_func,
+ forall_data,
+ object
+ };
+
+ gtk_cell_area_foreach (GTK_CELL_AREA (object), cell_callback, &data);
+}
+
+static void
+object_tree_cell_layout_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GtkCellArea *area;
+
+ /* cell areas handle their own stuff */
+ if (GTK_IS_CELL_AREA (object))
+ return;
+
+ area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (object));
+ g_object_set_data (G_OBJECT (area), "gtk-inspector-cell-layout", object);
+ forall_func (G_OBJECT (area), "cell-area", forall_data);
+}
+
+static void
+object_tree_text_view_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GtkTextBuffer *buffer;
+
+ buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object));
+ forall_func (G_OBJECT (buffer), "buffer", forall_data);
+}
+
+static void
+object_tree_text_buffer_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GtkTextTagTable *tags;
+
+ tags = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (object));
+ forall_func (G_OBJECT (tags), "tag-table", forall_data);
+}
+
+static void
+tag_callback (GtkTextTag *tag,
+ gpointer data)
+{
+ ForallData *d = data;
+ gchar *name;
+
+ g_object_get (tag, "name", &name, NULL);
+ d->forall_func (G_OBJECT (tag), name, d->forall_data);
+ g_free (name);
+}
+
+static void
+object_tree_text_tag_table_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ ForallData data = {
+ forall_func,
+ forall_data
+ };
+
+ gtk_text_tag_table_foreach (GTK_TEXT_TAG_TABLE (object), tag_callback, &data);
+}
+
+static void
+object_tree_application_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GObject *menu;
+
+ menu = (GObject *)gtk_application_get_app_menu (GTK_APPLICATION (object));
+ if (menu)
+ forall_func (menu, "app-menu", forall_data);
+
+ menu = (GObject *)gtk_application_get_menubar (GTK_APPLICATION (object));
+ if (menu)
+ forall_func (menu, "menubar", forall_data);
+}
+
+/* Note:
+ * This tree must be sorted with the most specific types first.
+ * We iterate over it top to bottom and return the first match
+ * using g_type_is_a ()
+ */
+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
+ },
+ {
+ gtk_text_tag_table_get_type,
+ object_tree_get_parent_default,
+ object_tree_text_tag_table_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ gtk_text_buffer_get_type,
+ object_tree_get_parent_default,
+ object_tree_text_buffer_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ gtk_text_view_get_type,
+ object_tree_widget_get_parent,
+ object_tree_text_view_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_icon_view_get_type,
+ object_tree_widget_get_parent,
+ object_tree_icon_view_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_tree_view_get_type,
+ object_tree_widget_get_parent,
+ object_tree_tree_view_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_combo_box_get_type,
+ object_tree_widget_get_parent,
+ object_tree_combo_box_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_menu_item_get_type,
+ object_tree_widget_get_parent,
+ object_tree_menu_item_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_container_get_type,
+ object_tree_widget_get_parent,
+ object_tree_container_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_widget_get_type,
+ object_tree_widget_get_parent,
+ object_tree_widget_forall,
+ object_tree_widget_get_sensitive
+ },
+ {
+ gtk_tree_model_filter_get_type,
+ object_tree_get_parent_default,
+ object_tree_tree_model_filter_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ gtk_tree_model_sort_get_type,
+ object_tree_get_parent_default,
+ object_tree_tree_model_sort_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ gtk_cell_area_get_type,
+ object_tree_get_parent_default,
+ object_tree_cell_area_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ gtk_cell_layout_get_type,
+ object_tree_get_parent_default,
+ object_tree_cell_layout_forall,
+ object_tree_get_sensitive_default
+ },
+ {
+ g_object_get_type,
+ object_tree_get_parent_default,
+ object_tree_forall_default,
+ object_tree_get_sensitive_default
+ },
+};
+
+static const ObjectTreeClassFuncs *
+find_class_funcs (GObject *object)
+{
+ GType object_type;
+ guint i;
+
+ object_type = G_OBJECT_TYPE (object);
+
+ 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 ()))
+ return &object_tree_class_funcs[i];
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+static G_GNUC_UNUSED GObject *
+object_get_parent (GObject *object)
+{
+ const ObjectTreeClassFuncs *funcs;
+
+ funcs = find_class_funcs (object);
+
+ return funcs->get_parent (object);
+}
+
+static void
+object_forall (GObject *object,
+ ObjectTreeForallFunc forall_func,
+ gpointer forall_data)
+{
+ GType object_type;
+ guint i;
+
+ object_type = G_OBJECT_TYPE (object);
+
+ 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);
+ }
+}
+
+static gboolean
+object_get_sensitive (GObject *object)
+{
+ const ObjectTreeClassFuncs *funcs;
+
+ funcs = find_class_funcs (object);
+
+ return funcs->get_sensitive (object);
+}
+
static void
on_row_activated (GtkTreeView *tree,
GtkTreePath *path,
@@ -511,38 +978,13 @@ typedef struct
} FindAllData;
static void
-child_callback (GtkWidget *widget,
- gpointer data)
+child_callback (GObject *object,
+ const char *name,
+ gpointer data)
{
FindAllData *d = data;
- gtk_inspector_object_tree_append_object (d->wt, G_OBJECT (widget), d->iter, NULL);
-}
-
-static gboolean
-cell_callback (GtkCellRenderer *renderer,
- gpointer data)
-{
- FindAllData *d = data;
- gpointer cell_layout;
-
- cell_layout = g_object_get_data (d->parent, "gtk-inspector-cell-layout");
- g_object_set_data (G_OBJECT (renderer), "gtk-inspector-cell-layout", cell_layout);
- gtk_inspector_object_tree_append_object (d->wt, G_OBJECT (renderer), d->iter, NULL);
-
- return FALSE;
-}
-
-static void
-tag_callback (GtkTextTag *tag,
- gpointer data)
-{
- FindAllData *d = data;
- gchar *name;
-
- g_object_get (tag, "name", &name, NULL);
- gtk_inspector_object_tree_append_object (d->wt, G_OBJECT (tag), d->iter, name);
- g_free (name);
+ gtk_inspector_object_tree_append_object (d->wt, object, d->iter, NULL);
}
void
@@ -555,19 +997,11 @@ gtk_inspector_object_tree_append_object (GtkInspectorObjectTree *wt,
GtkTreePath *path;
const gchar *class_name;
gchar *classes;
- gboolean mapped;
ObjectData *od;
const gchar *label;
+ FindAllData data;
- if (GTK_IS_WIDGET (object))
- mapped = gtk_widget_get_mapped (GTK_WIDGET (object));
- else
- mapped = TRUE;
-
- if (G_OBJECT (object))
- class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object));
- else
- class_name = "";
+ class_name = G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object));
if (GTK_IS_WIDGET (object))
{
@@ -624,7 +1058,7 @@ gtk_inspector_object_tree_append_object (GtkInspectorObjectTree *wt,
OBJECT_NAME, name,
OBJECT_LABEL, label,
OBJECT_CLASSES, classes,
- SENSITIVE, mapped,
+ SENSITIVE, object_get_sensitive (object),
-1);
if (name && *name)
@@ -649,183 +1083,12 @@ gtk_inspector_object_tree_append_object (GtkInspectorObjectTree *wt,
g_hash_table_insert (wt->priv->iters, object, od);
g_object_weak_ref (object, gtk_object_tree_remove_dead_object, od);
+
+ data.wt = wt;
+ data.iter = &iter;
+ data.parent = object;
- if (GTK_IS_CONTAINER (object))
- {
- FindAllData data;
-
- data.wt = wt;
- data.iter = &iter;
- data.parent = object;
-
- gtk_container_forall (GTK_CONTAINER (object), child_callback, &data);
- }
-
- /* Below are special cases for dependent objects which are not
- * children in the GtkContainer sense, but which we still want
- * to show in the tree right away.
- */
- if (GTK_IS_TREE_MODEL_SORT (object))
- {
- GObject *child = G_OBJECT (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "model");
- }
-
- if (GTK_IS_TREE_MODEL_FILTER (object))
- {
- GObject *child = G_OBJECT (gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "model");
- }
-
- if (GTK_IS_MENU_ITEM (object))
- {
- GtkWidget *submenu;
-
- submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (object));
- if (submenu)
- gtk_inspector_object_tree_append_object (wt, G_OBJECT (submenu), &iter, "submenu");
- }
-
- if (GTK_IS_COMBO_BOX (object))
- {
- GtkWidget *popup;
- GObject *child;
-
- popup = gtk_combo_box_get_popup (GTK_COMBO_BOX (object));
- if (popup)
- gtk_inspector_object_tree_append_object (wt, G_OBJECT (popup), &iter, "popup");
-
- child = G_OBJECT (gtk_combo_box_get_model (GTK_COMBO_BOX (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "model");
- }
-
- if (GTK_IS_TREE_VIEW (object))
- {
- gint n_columns, i;
- GObject *child;
-
- child = G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "model");
-
- child = G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "selection");
-
- n_columns = gtk_tree_view_get_n_columns (GTK_TREE_VIEW (object));
- for (i = 0; i < n_columns; i++)
- {
- child = G_OBJECT (gtk_tree_view_get_column (GTK_TREE_VIEW (object), i));
- gtk_inspector_object_tree_append_object (wt, child, &iter, NULL);
- }
- }
-
- if (GTK_IS_ICON_VIEW (object))
- {
- GObject *child;
-
- child = G_OBJECT (gtk_icon_view_get_model (GTK_ICON_VIEW (object)));
- if (child)
- gtk_inspector_object_tree_append_object (wt, child, &iter, "model");
- }
-
- if (GTK_IS_CELL_AREA (object))
- {
- FindAllData data;
-
- data.wt = wt;
- data.iter = &iter;
- data.parent = object;
-
- gtk_cell_area_foreach (GTK_CELL_AREA (object), cell_callback, &data);
- }
- else if (GTK_IS_CELL_LAYOUT (object))
- {
- GtkCellArea *area;
-
- area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (object));
- g_object_set_data (G_OBJECT (area), "gtk-inspector-cell-layout", object);
- gtk_inspector_object_tree_append_object (wt, G_OBJECT (area), &iter, "cell-area");
- }
-
- if (GTK_IS_TEXT_VIEW (object))
- {
- GtkTextBuffer *buffer;
-
- buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object));
- gtk_inspector_object_tree_append_object (wt, G_OBJECT (buffer), &iter, "buffer");
- }
-
- if (GTK_IS_TEXT_BUFFER (object))
- {
- GtkTextTagTable *tags;
-
- tags = gtk_text_buffer_get_tag_table (GTK_TEXT_BUFFER (object));
- gtk_inspector_object_tree_append_object (wt, G_OBJECT (tags), &iter, "tag-table");
- }
-
- if (GTK_IS_TEXT_TAG_TABLE (object))
- {
- FindAllData data;
-
- data.wt = wt;
- data.iter = &iter;
- data.parent = object;
-
- gtk_text_tag_table_foreach (GTK_TEXT_TAG_TABLE (object), tag_callback, &data);
- }
-
- if (GTK_IS_WIDGET (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;
-
- for (i = 0; i < G_N_ELEMENTS (phases); i++)
- {
- GList *list, *l;
-
- list = _gtk_widget_list_controllers (GTK_WIDGET (object), phases[i].phase);
- for (l = list; l; l = l->next)
- {
- GObject *controller = l->data;
- gtk_inspector_object_tree_append_object (wt, controller, &iter, phases[i].name);
- }
- g_list_free (list);
- }
-
- if (gtk_widget_is_toplevel (GTK_WIDGET (object)))
- {
- GObject *clock;
-
- clock = (GObject *)gtk_widget_get_frame_clock (GTK_WIDGET (object));
- if (clock)
- gtk_inspector_object_tree_append_object (wt, clock, &iter, "frame-clock");
- }
- }
-
- if (GTK_IS_APPLICATION (object))
- {
- GObject *menu;
-
- menu = (GObject *)gtk_application_get_app_menu (GTK_APPLICATION (object));
- if (menu)
- gtk_inspector_object_tree_append_object (wt, menu, &iter, "app-menu");
-
- menu = (GObject *)gtk_application_get_menubar (GTK_APPLICATION (object));
- if (menu)
- gtk_inspector_object_tree_append_object (wt, menu, &iter, "menubar");
- }
+ object_forall (object, child_callback, &data);
}
gboolean
@@ -878,8 +1141,8 @@ gtk_inspector_object_tree_scan (GtkInspectorObjectTree *wt,
selected = gtk_inspector_object_tree_get_selected (wt);
- gtk_tree_store_clear (wt->priv->model);
g_hash_table_remove_all (wt->priv->iters);
+ gtk_tree_store_clear (wt->priv->model);
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);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]