inspector: Refactor object tree construction

Instead of having lots of if statements, create a vtable. This will be
useful for the following patches.
This commit is contained in:
Benjamin Otte 2015-08-26 15:28:22 +02:00
parent 5037d134c5
commit c7ed2c2130

View File

@ -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,
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 = "";
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)
@ -650,182 +1084,11 @@ 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);
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);